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