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