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