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