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