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