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