]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/netlink-message.c
Merge pull request #355 from dvdhrm/netlink
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/in.h>
23 #include <stdbool.h>
24 #include <unistd.h>
25
26 #include "util.h"
27 #include "socket-util.h"
28 #include "formats-util.h"
29 #include "refcnt.h"
30 #include "missing.h"
31
32 #include "sd-netlink.h"
33 #include "netlink-util.h"
34 #include "netlink-internal.h"
35 #include "netlink-types.h"
36
37 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
38 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
39
40 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
41
42 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
43 sd_netlink_message *m;
44
45 assert_return(ret, -EINVAL);
46
47 /* Note that 'rtnl' is currently unused, if we start using it internally
48 we must take care to avoid problems due to mutual references between
49 buses and their queued messages. See sd-bus.
50 */
51
52 m = new0(sd_netlink_message, 1);
53 if (!m)
54 return -ENOMEM;
55
56 m->n_ref = REFCNT_INIT;
57
58 m->sealed = false;
59
60 *ret = m;
61
62 return 0;
63 }
64
65 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
66 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
67 const NLType *nl_type;
68 size_t size;
69 int r;
70
71 r = type_system_get_type(&type_system_root, &nl_type, type);
72 if (r < 0)
73 return r;
74
75 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
76 return -EINVAL;
77
78 r = message_new_empty(rtnl, &m);
79 if (r < 0)
80 return r;
81
82 size = NLMSG_SPACE(type_get_size(nl_type));
83
84 assert(size >= sizeof(struct nlmsghdr));
85 m->hdr = malloc0(size);
86 if (!m->hdr)
87 return -ENOMEM;
88
89 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
90
91 type_get_type_system(nl_type, &m->container_type_system[0]);
92 m->hdr->nlmsg_len = size;
93 m->hdr->nlmsg_type = type;
94
95 *ret = m;
96 m = NULL;
97
98 return 0;
99 }
100
101 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
102 assert_return(m, -EINVAL);
103 assert_return(m->hdr, -EINVAL);
104 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
105 m->hdr->nlmsg_type == RTM_GETADDR ||
106 m->hdr->nlmsg_type == RTM_GETROUTE ||
107 m->hdr->nlmsg_type == RTM_GETNEIGH,
108 -EINVAL);
109
110 if (dump)
111 m->hdr->nlmsg_flags |= NLM_F_DUMP;
112 else
113 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
114
115 return 0;
116 }
117
118 sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
119 if (m)
120 assert_se(REFCNT_INC(m->n_ref) >= 2);
121
122 return m;
123 }
124
125 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
126 if (m && REFCNT_DEC(m->n_ref) == 0) {
127 unsigned i;
128
129 free(m->hdr);
130
131 for (i = 0; i <= m->n_containers; i++)
132 free(m->rta_offset_tb[i]);
133
134 sd_netlink_message_unref(m->next);
135
136 free(m);
137 }
138
139 return NULL;
140 }
141
142 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
143 assert_return(m, -EINVAL);
144 assert_return(type, -EINVAL);
145
146 *type = m->hdr->nlmsg_type;
147
148 return 0;
149 }
150
151 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
152 assert_return(m, -EINVAL);
153
154 return m->broadcast;
155 }
156
157 /* If successful the updated message will be correctly aligned, if
158 unsuccessful the old message is untouched. */
159 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
160 uint32_t rta_length;
161 size_t message_length, padding_length;
162 struct nlmsghdr *new_hdr;
163 struct rtattr *rta;
164 char *padding;
165 unsigned i;
166 int offset;
167
168 assert(m);
169 assert(m->hdr);
170 assert(!m->sealed);
171 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
172 assert(!data || data_length);
173
174 /* get offset of the new attribute */
175 offset = m->hdr->nlmsg_len;
176
177 /* get the size of the new rta attribute (with padding at the end) */
178 rta_length = RTA_LENGTH(data_length);
179
180 /* get the new message size (with padding at the end) */
181 message_length = offset + RTA_ALIGN(rta_length);
182
183 /* realloc to fit the new attribute */
184 new_hdr = realloc(m->hdr, message_length);
185 if (!new_hdr)
186 return -ENOMEM;
187 m->hdr = new_hdr;
188
189 /* get pointer to the attribute we are about to add */
190 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
191
192 /* if we are inside containers, extend them */
193 for (i = 0; i < m->n_containers; i++)
194 GET_CONTAINER(m, i)->rta_len += message_length - offset;
195
196 /* fill in the attribute */
197 rta->rta_type = type;
198 rta->rta_len = rta_length;
199 if (data)
200 /* we don't deal with the case where the user lies about the type
201 * and gives us too little data (so don't do that)
202 */
203 padding = mempcpy(RTA_DATA(rta), data, data_length);
204 else {
205 /* if no data was passed, make sure we still initialize the padding
206 note that we can have data_length > 0 (used by some containers) */
207 padding = RTA_DATA(rta);
208 }
209
210 /* make sure also the padding at the end of the message is initialized */
211 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
212 memzero(padding, padding_length);
213
214 /* update message size */
215 m->hdr->nlmsg_len = message_length;
216
217 return offset;
218 }
219
220 static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
221 const NLType *type;
222 int r;
223
224 assert(m);
225
226 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
227 if (r < 0)
228 return r;
229
230 if (type_get_type(type) != data_type)
231 return -EINVAL;
232
233 if (out_size)
234 *out_size = type_get_size(type);
235 return 0;
236 }
237
238 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
239 size_t length, size;
240 int r;
241
242 assert_return(m, -EINVAL);
243 assert_return(!m->sealed, -EPERM);
244 assert_return(data, -EINVAL);
245
246 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
247 if (r < 0)
248 return r;
249
250 if (size) {
251 length = strnlen(data, size+1);
252 if (length > size)
253 return -EINVAL;
254 } else
255 length = strlen(data);
256
257 r = add_rtattr(m, type, data, length + 1);
258 if (r < 0)
259 return r;
260
261 return 0;
262 }
263
264 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
265 int r;
266
267 assert_return(m, -EINVAL);
268 assert_return(!m->sealed, -EPERM);
269
270 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
271 if (r < 0)
272 return r;
273
274 r = add_rtattr(m, type, &data, sizeof(uint8_t));
275 if (r < 0)
276 return r;
277
278 return 0;
279 }
280
281
282 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
283 int r;
284
285 assert_return(m, -EINVAL);
286 assert_return(!m->sealed, -EPERM);
287
288 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
289 if (r < 0)
290 return r;
291
292 r = add_rtattr(m, type, &data, sizeof(uint16_t));
293 if (r < 0)
294 return r;
295
296 return 0;
297 }
298
299 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
300 int r;
301
302 assert_return(m, -EINVAL);
303 assert_return(!m->sealed, -EPERM);
304
305 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
306 if (r < 0)
307 return r;
308
309 r = add_rtattr(m, type, &data, sizeof(uint32_t));
310 if (r < 0)
311 return r;
312
313 return 0;
314 }
315
316 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
317 int r;
318
319 assert_return(m, -EINVAL);
320 assert_return(!m->sealed, -EPERM);
321 assert_return(data, -EINVAL);
322
323 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
324 if (r < 0)
325 return r;
326
327 r = add_rtattr(m, type, data, sizeof(struct in_addr));
328 if (r < 0)
329 return r;
330
331 return 0;
332 }
333
334 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
335 int r;
336
337 assert_return(m, -EINVAL);
338 assert_return(!m->sealed, -EPERM);
339 assert_return(data, -EINVAL);
340
341 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
342 if (r < 0)
343 return r;
344
345 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
346 if (r < 0)
347 return r;
348
349 return 0;
350 }
351
352 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
353 int r;
354
355 assert_return(m, -EINVAL);
356 assert_return(!m->sealed, -EPERM);
357 assert_return(data, -EINVAL);
358
359 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
360 if (r < 0)
361 return r;
362
363 r = add_rtattr(m, type, data, ETH_ALEN);
364 if (r < 0)
365 return r;
366
367 return 0;
368 }
369
370 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
371 int r;
372
373 assert_return(m, -EINVAL);
374 assert_return(!m->sealed, -EPERM);
375 assert_return(info, -EINVAL);
376
377 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
378 if (r < 0)
379 return r;
380
381 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
382 if (r < 0)
383 return r;
384
385 return 0;
386 }
387
388 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
389 size_t size;
390 int r;
391
392 assert_return(m, -EINVAL);
393 assert_return(!m->sealed, -EPERM);
394 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
395
396 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
397 if (r < 0) {
398 const NLTypeSystemUnion *type_system_union;
399 int family;
400
401 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
402 if (r < 0)
403 return r;
404
405 r = sd_rtnl_message_get_family(m, &family);
406 if (r < 0)
407 return r;
408
409 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
410 if (r < 0)
411 return r;
412
413 r = type_system_union_protocol_get_type_system(type_system_union,
414 &m->container_type_system[m->n_containers + 1],
415 family);
416 if (r < 0)
417 return r;
418 } else {
419 r = type_system_get_type_system(m->container_type_system[m->n_containers],
420 &m->container_type_system[m->n_containers + 1],
421 type);
422 if (r < 0)
423 return r;
424 }
425
426 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
427 if (r < 0)
428 return r;
429
430 m->container_offsets[m->n_containers ++] = r;
431
432 return 0;
433 }
434
435 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
436 const NLTypeSystemUnion *type_system_union;
437 int r;
438
439 assert_return(m, -EINVAL);
440 assert_return(!m->sealed, -EPERM);
441
442 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
443 if (r < 0)
444 return r;
445
446 r = type_system_union_get_type_system(type_system_union,
447 &m->container_type_system[m->n_containers + 1],
448 key);
449 if (r < 0)
450 return r;
451
452 r = sd_netlink_message_append_string(m, type_system_union->match, key);
453 if (r < 0)
454 return r;
455
456 /* do we evere need non-null size */
457 r = add_rtattr(m, type, NULL, 0);
458 if (r < 0)
459 return r;
460
461 m->container_offsets[m->n_containers ++] = r;
462
463 return 0;
464 }
465
466
467 int sd_netlink_message_close_container(sd_netlink_message *m) {
468 assert_return(m, -EINVAL);
469 assert_return(!m->sealed, -EPERM);
470 assert_return(m->n_containers > 0, -EINVAL);
471
472 m->container_type_system[m->n_containers] = NULL;
473 m->n_containers --;
474
475 return 0;
476 }
477
478 int rtnl_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
479 struct rtattr *rta;
480
481 assert_return(m, -EINVAL);
482 assert_return(m->sealed, -EPERM);
483 assert_return(data, -EINVAL);
484 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
485 assert(m->rta_offset_tb[m->n_containers]);
486 assert(type < m->rta_tb_size[m->n_containers]);
487
488 if(!m->rta_offset_tb[m->n_containers][type])
489 return -ENODATA;
490
491 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
492
493 *data = RTA_DATA(rta);
494
495 return RTA_PAYLOAD(rta);
496 }
497
498 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
499 int r;
500 void *attr_data;
501
502 assert_return(m, -EINVAL);
503
504 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
505 if (r < 0)
506 return r;
507
508 r = rtnl_message_read_internal(m, type, &attr_data);
509 if (r < 0)
510 return r;
511 else if (strnlen(attr_data, r) >= (size_t) r)
512 return -EIO;
513
514 if (data)
515 *data = (const char *) attr_data;
516
517 return 0;
518 }
519
520 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
521 int r;
522 void *attr_data;
523
524 assert_return(m, -EINVAL);
525
526 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
527 if (r < 0)
528 return r;
529
530 r = rtnl_message_read_internal(m, type, &attr_data);
531 if (r < 0)
532 return r;
533 else if ((size_t) r < sizeof(uint8_t))
534 return -EIO;
535
536 if (data)
537 *data = *(uint8_t *) attr_data;
538
539 return 0;
540 }
541
542 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
543 int r;
544 void *attr_data;
545
546 assert_return(m, -EINVAL);
547
548 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
549 if (r < 0)
550 return r;
551
552 r = rtnl_message_read_internal(m, type, &attr_data);
553 if (r < 0)
554 return r;
555 else if ((size_t) r < sizeof(uint16_t))
556 return -EIO;
557
558 if (data)
559 *data = *(uint16_t *) attr_data;
560
561 return 0;
562 }
563
564 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
565 int r;
566 void *attr_data;
567
568 assert_return(m, -EINVAL);
569
570 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
571 if (r < 0)
572 return r;
573
574 r = rtnl_message_read_internal(m, type, &attr_data);
575 if (r < 0)
576 return r;
577 else if ((size_t)r < sizeof(uint32_t))
578 return -EIO;
579
580 if (data)
581 *data = *(uint32_t *) attr_data;
582
583 return 0;
584 }
585
586 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
587 int r;
588 void *attr_data;
589
590 assert_return(m, -EINVAL);
591
592 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
593 if (r < 0)
594 return r;
595
596 r = rtnl_message_read_internal(m, type, &attr_data);
597 if (r < 0)
598 return r;
599 else if ((size_t)r < sizeof(struct ether_addr))
600 return -EIO;
601
602 if (data)
603 memcpy(data, attr_data, sizeof(struct ether_addr));
604
605 return 0;
606 }
607
608 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
609 int r;
610 void *attr_data;
611
612 assert_return(m, -EINVAL);
613
614 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
615 if (r < 0)
616 return r;
617
618 r = rtnl_message_read_internal(m, type, &attr_data);
619 if (r < 0)
620 return r;
621 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
622 return -EIO;
623
624 if (info)
625 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
626
627 return 0;
628 }
629
630 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
631 int r;
632 void *attr_data;
633
634 assert_return(m, -EINVAL);
635
636 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
637 if (r < 0)
638 return r;
639
640 r = rtnl_message_read_internal(m, type, &attr_data);
641 if (r < 0)
642 return r;
643 else if ((size_t)r < sizeof(struct in_addr))
644 return -EIO;
645
646 if (data)
647 memcpy(data, attr_data, sizeof(struct in_addr));
648
649 return 0;
650 }
651
652 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
653 int r;
654 void *attr_data;
655
656 assert_return(m, -EINVAL);
657
658 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
659 if (r < 0)
660 return r;
661
662 r = rtnl_message_read_internal(m, type, &attr_data);
663 if (r < 0)
664 return r;
665 else if ((size_t)r < sizeof(struct in6_addr))
666 return -EIO;
667
668 if (data)
669 memcpy(data, attr_data, sizeof(struct in6_addr));
670
671 return 0;
672 }
673
674 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
675 const NLType *nl_type;
676 const NLTypeSystem *type_system;
677 void *container;
678 uint16_t type;
679 size_t size;
680 int r;
681
682 assert_return(m, -EINVAL);
683 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
684
685 r = type_system_get_type(m->container_type_system[m->n_containers],
686 &nl_type,
687 type_id);
688 if (r < 0)
689 return r;
690
691 type = type_get_type(nl_type);
692
693 if (type == NETLINK_TYPE_NESTED) {
694 r = type_system_get_type_system(m->container_type_system[m->n_containers],
695 &type_system,
696 type_id);
697 if (r < 0)
698 return r;
699 } else if (type == NETLINK_TYPE_UNION) {
700 const NLTypeSystemUnion *type_system_union;
701
702 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
703 &type_system_union,
704 type_id);
705 if (r < 0)
706 return r;
707
708 switch (type_system_union->match_type) {
709 case NL_MATCH_SIBLING:
710 {
711 const char *key;
712
713 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
714 if (r < 0)
715 return r;
716
717 r = type_system_union_get_type_system(type_system_union,
718 &type_system,
719 key);
720 if (r < 0)
721 return r;
722
723 break;
724 }
725 case NL_MATCH_PROTOCOL:
726 {
727 int family;
728
729 r = sd_rtnl_message_get_family(m, &family);
730 if (r < 0)
731 return r;
732
733 r = type_system_union_protocol_get_type_system(type_system_union,
734 &type_system,
735 family);
736 if (r < 0)
737 return r;
738
739 break;
740 }
741 default:
742 assert_not_reached("sd-netlink: invalid type system union type");
743 }
744 } else
745 return -EINVAL;
746
747 r = rtnl_message_read_internal(m, type_id, &container);
748 if (r < 0)
749 return r;
750 else
751 size = (size_t)r;
752
753 m->n_containers ++;
754
755 r = rtnl_message_parse(m,
756 &m->rta_offset_tb[m->n_containers],
757 &m->rta_tb_size[m->n_containers],
758 type_system_get_count(type_system),
759 container,
760 size);
761 if (r < 0) {
762 m->n_containers --;
763 return r;
764 }
765
766 m->container_type_system[m->n_containers] = type_system;
767
768 return 0;
769 }
770
771 int sd_netlink_message_exit_container(sd_netlink_message *m) {
772 assert_return(m, -EINVAL);
773 assert_return(m->sealed, -EINVAL);
774 assert_return(m->n_containers > 0, -EINVAL);
775
776 free(m->rta_offset_tb[m->n_containers]);
777 m->rta_offset_tb[m->n_containers] = NULL;
778 m->container_type_system[m->n_containers] = NULL;
779
780 m->n_containers --;
781
782 return 0;
783 }
784
785 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
786 assert(m);
787 assert(m->hdr);
788
789 return m->hdr->nlmsg_seq;
790 }
791
792 int sd_netlink_message_is_error(sd_netlink_message *m) {
793 assert_return(m, 0);
794 assert_return(m->hdr, 0);
795
796 return m->hdr->nlmsg_type == NLMSG_ERROR;
797 }
798
799 int sd_netlink_message_get_errno(sd_netlink_message *m) {
800 struct nlmsgerr *err;
801
802 assert_return(m, -EINVAL);
803 assert_return(m->hdr, -EINVAL);
804
805 if (!sd_netlink_message_is_error(m))
806 return 0;
807
808 err = NLMSG_DATA(m->hdr);
809
810 return err->error;
811 }
812
813 int rtnl_message_parse(sd_netlink_message *m,
814 size_t **rta_offset_tb,
815 unsigned short *rta_tb_size,
816 int count,
817 struct rtattr *rta,
818 unsigned int rt_len) {
819 unsigned short type;
820 size_t *tb;
821
822 tb = new0(size_t, count);
823 if(!tb)
824 return -ENOMEM;
825
826 *rta_tb_size = count;
827
828 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
829 type = RTA_TYPE(rta);
830
831 /* if the kernel is newer than the headers we used
832 when building, we ignore out-of-range attributes
833 */
834 if (type >= count)
835 continue;
836
837 if (tb[type])
838 log_debug("rtnl: message parse - overwriting repeated attribute");
839
840 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
841 }
842
843 *rta_offset_tb = tb;
844
845 return 0;
846 }
847
848 int sd_netlink_message_rewind(sd_netlink_message *m) {
849 const NLType *nl_type;
850 uint16_t type;
851 size_t size;
852 unsigned i;
853 int r;
854
855 assert_return(m, -EINVAL);
856
857 /* don't allow appending to message once parsed */
858 if (!m->sealed)
859 rtnl_message_seal(m);
860
861 for (i = 1; i <= m->n_containers; i++) {
862 free(m->rta_offset_tb[i]);
863 m->rta_offset_tb[i] = NULL;
864 m->rta_tb_size[i] = 0;
865 m->container_type_system[i] = NULL;
866 }
867
868 m->n_containers = 0;
869
870 if (m->rta_offset_tb[0]) {
871 /* top-level attributes have already been parsed */
872 return 0;
873 }
874
875 assert(m->hdr);
876
877 r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
878 if (r < 0)
879 return r;
880
881 type = type_get_type(nl_type);
882 size = type_get_size(nl_type);
883
884 if (type == NETLINK_TYPE_NESTED) {
885 const NLTypeSystem *type_system;
886
887 type_get_type_system(nl_type, &type_system);
888
889 m->container_type_system[0] = type_system;
890
891 r = rtnl_message_parse(m,
892 &m->rta_offset_tb[m->n_containers],
893 &m->rta_tb_size[m->n_containers],
894 type_system_get_count(type_system),
895 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
896 NLMSG_PAYLOAD(m->hdr, size));
897 if (r < 0)
898 return r;
899 }
900
901 return 0;
902 }
903
904 void rtnl_message_seal(sd_netlink_message *m) {
905 assert(m);
906 assert(!m->sealed);
907
908 m->sealed = true;
909 }
910
911 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
912 assert_return(m, NULL);
913
914 return m->next;
915 }