]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/netlink-message.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/in.h>
4 #include <stdbool.h>
5 #include <unistd.h>
6
7 #include "sd-netlink.h"
8
9 #include "alloc-util.h"
10 #include "format-util.h"
11 #include "missing.h"
12 #include "netlink-internal.h"
13 #include "netlink-types.h"
14 #include "netlink-util.h"
15 #include "refcnt.h"
16 #include "socket-util.h"
17 #include "util.h"
18
19 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
20 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
21
22 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
23 #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
24
25 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
26 sd_netlink_message *m;
27
28 assert_return(ret, -EINVAL);
29
30 /* Note that 'rtnl' is currently unused, if we start using it internally
31 we must take care to avoid problems due to mutual references between
32 buses and their queued messages. See sd-bus.
33 */
34
35 m = new0(sd_netlink_message, 1);
36 if (!m)
37 return -ENOMEM;
38
39 m->n_ref = REFCNT_INIT;
40 m->protocol = rtnl->protocol;
41 m->sealed = false;
42
43 *ret = m;
44
45 return 0;
46 }
47
48 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
49 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
50 const NLType *nl_type;
51 const NLTypeSystem *type_system_root;
52 size_t size;
53 int r;
54
55 assert_return(rtnl, -EINVAL);
56
57 type_system_root = type_system_get_root(rtnl->protocol);
58
59 r = type_system_get_type(type_system_root, &nl_type, type);
60 if (r < 0)
61 return r;
62
63 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
64 return -EINVAL;
65
66 r = message_new_empty(rtnl, &m);
67 if (r < 0)
68 return r;
69
70 size = NLMSG_SPACE(type_get_size(nl_type));
71
72 assert(size >= sizeof(struct nlmsghdr));
73 m->hdr = malloc0(size);
74 if (!m->hdr)
75 return -ENOMEM;
76
77 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
78
79 type_get_type_system(nl_type, &m->containers[0].type_system);
80 m->hdr->nlmsg_len = size;
81 m->hdr->nlmsg_type = type;
82
83 *ret = TAKE_PTR(m);
84
85 return 0;
86 }
87
88 int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
89 assert_return(m, -EINVAL);
90 assert_return(m->hdr, -EINVAL);
91
92 assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
93
94 SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
95
96 return 0;
97 }
98
99 DEFINE_ATOMIC_REF_FUNC(sd_netlink_message, sd_netlink_message);
100
101 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
102 sd_netlink_message *t;
103
104 while (m && REFCNT_DEC(m->n_ref) == 0) {
105 unsigned i;
106
107 free(m->hdr);
108
109 for (i = 0; i <= m->n_containers; i++)
110 free(m->containers[i].attributes);
111
112 t = m;
113 m = m->next;
114 free(t);
115 }
116
117 return NULL;
118 }
119
120 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
121 assert_return(m, -EINVAL);
122 assert_return(type, -EINVAL);
123
124 *type = m->hdr->nlmsg_type;
125
126 return 0;
127 }
128
129 int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
130 assert_return(m, -EINVAL);
131 assert_return(flags, -EINVAL);
132
133 m->hdr->nlmsg_flags = flags;
134
135 return 0;
136 }
137
138 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
139 assert_return(m, -EINVAL);
140
141 return m->broadcast;
142 }
143
144 /* If successful the updated message will be correctly aligned, if
145 unsuccessful the old message is untouched. */
146 static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
147 uint32_t rta_length;
148 size_t message_length, padding_length;
149 struct nlmsghdr *new_hdr;
150 struct rtattr *rta;
151 char *padding;
152 unsigned i;
153 int offset;
154
155 assert(m);
156 assert(m->hdr);
157 assert(!m->sealed);
158 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
159 assert(!data || data_length);
160
161 /* get offset of the new attribute */
162 offset = m->hdr->nlmsg_len;
163
164 /* get the size of the new rta attribute (with padding at the end) */
165 rta_length = RTA_LENGTH(data_length);
166
167 /* get the new message size (with padding at the end) */
168 message_length = offset + RTA_ALIGN(rta_length);
169
170 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
171 if (message_length > MIN(page_size(), 8192UL))
172 return -ENOBUFS;
173
174 /* realloc to fit the new attribute */
175 new_hdr = realloc(m->hdr, message_length);
176 if (!new_hdr)
177 return -ENOMEM;
178 m->hdr = new_hdr;
179
180 /* get pointer to the attribute we are about to add */
181 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
182
183 /* if we are inside containers, extend them */
184 for (i = 0; i < m->n_containers; i++)
185 GET_CONTAINER(m, i)->rta_len += message_length - offset;
186
187 /* fill in the attribute */
188 rta->rta_type = type;
189 rta->rta_len = rta_length;
190 if (data)
191 /* we don't deal with the case where the user lies about the type
192 * and gives us too little data (so don't do that)
193 */
194 padding = mempcpy(RTA_DATA(rta), data, data_length);
195
196 else
197 /* if no data was passed, make sure we still initialize the padding
198 note that we can have data_length > 0 (used by some containers) */
199 padding = RTA_DATA(rta);
200
201 /* make sure also the padding at the end of the message is initialized */
202 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
203 memzero(padding, padding_length);
204
205 /* update message size */
206 m->hdr->nlmsg_len = message_length;
207
208 return offset;
209 }
210
211 static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
212 const NLType *type;
213 int r;
214
215 assert(m);
216
217 r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
218 if (r < 0)
219 return r;
220
221 if (type_get_type(type) != data_type)
222 return -EINVAL;
223
224 if (out_size)
225 *out_size = type_get_size(type);
226 return 0;
227 }
228
229 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
230 size_t length, size;
231 int r;
232
233 assert_return(m, -EINVAL);
234 assert_return(!m->sealed, -EPERM);
235 assert_return(data, -EINVAL);
236
237 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
238 if (r < 0)
239 return r;
240
241 if (size) {
242 length = strnlen(data, size+1);
243 if (length > size)
244 return -EINVAL;
245 } else
246 length = strlen(data);
247
248 r = add_rtattr(m, type, data, length + 1);
249 if (r < 0)
250 return r;
251
252 return 0;
253 }
254
255 int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
256 size_t size;
257 int r;
258
259 assert_return(m, -EINVAL);
260 assert_return(!m->sealed, -EPERM);
261
262 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
263 if (r < 0)
264 return r;
265
266 r = add_rtattr(m, type, NULL, 0);
267 if (r < 0)
268 return r;
269
270 return 0;
271 }
272
273 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
274 int r;
275
276 assert_return(m, -EINVAL);
277 assert_return(!m->sealed, -EPERM);
278
279 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
280 if (r < 0)
281 return r;
282
283 r = add_rtattr(m, type, &data, sizeof(uint8_t));
284 if (r < 0)
285 return r;
286
287 return 0;
288 }
289
290 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_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_U16);
297 if (r < 0)
298 return r;
299
300 r = add_rtattr(m, type, &data, sizeof(uint16_t));
301 if (r < 0)
302 return r;
303
304 return 0;
305 }
306
307 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
308 int r;
309
310 assert_return(m, -EINVAL);
311 assert_return(!m->sealed, -EPERM);
312
313 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
314 if (r < 0)
315 return r;
316
317 r = add_rtattr(m, type, &data, sizeof(uint32_t));
318 if (r < 0)
319 return r;
320
321 return 0;
322 }
323
324 int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
325 int r;
326
327 assert_return(m, -EINVAL);
328 assert_return(!m->sealed, -EPERM);
329
330 r = add_rtattr(m, type, data, len);
331 if (r < 0)
332 return r;
333
334 return 0;
335 }
336
337 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
338 int r;
339
340 assert_return(m, -EINVAL);
341 assert_return(!m->sealed, -EPERM);
342 assert_return(data, -EINVAL);
343
344 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
345 if (r < 0)
346 return r;
347
348 r = add_rtattr(m, type, data, sizeof(struct in_addr));
349 if (r < 0)
350 return r;
351
352 return 0;
353 }
354
355 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_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 in6_addr));
367 if (r < 0)
368 return r;
369
370 return 0;
371 }
372
373 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_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_ETHER_ADDR);
381 if (r < 0)
382 return r;
383
384 r = add_rtattr(m, type, data, ETH_ALEN);
385 if (r < 0)
386 return r;
387
388 return 0;
389 }
390
391 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
392 int r;
393
394 assert_return(m, -EINVAL);
395 assert_return(!m->sealed, -EPERM);
396 assert_return(info, -EINVAL);
397
398 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
399 if (r < 0)
400 return r;
401
402 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
403 if (r < 0)
404 return r;
405
406 return 0;
407 }
408
409 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
410 size_t size;
411 int r;
412
413 assert_return(m, -EINVAL);
414 assert_return(!m->sealed, -EPERM);
415 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
416
417 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
418 if (r < 0) {
419 const NLTypeSystemUnion *type_system_union;
420 int family;
421
422 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
423 if (r < 0)
424 return r;
425
426 r = sd_rtnl_message_get_family(m, &family);
427 if (r < 0)
428 return r;
429
430 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
431 if (r < 0)
432 return r;
433
434 r = type_system_union_protocol_get_type_system(type_system_union,
435 &m->containers[m->n_containers + 1].type_system,
436 family);
437 if (r < 0)
438 return r;
439 } else {
440 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
441 &m->containers[m->n_containers + 1].type_system,
442 type);
443 if (r < 0)
444 return r;
445 }
446
447 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
448 if (r < 0)
449 return r;
450
451 m->containers[m->n_containers++].offset = r;
452
453 return 0;
454 }
455
456 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
457 const NLTypeSystemUnion *type_system_union;
458 int r;
459
460 assert_return(m, -EINVAL);
461 assert_return(!m->sealed, -EPERM);
462
463 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
464 if (r < 0)
465 return r;
466
467 r = type_system_union_get_type_system(type_system_union,
468 &m->containers[m->n_containers + 1].type_system,
469 key);
470 if (r < 0)
471 return r;
472
473 r = sd_netlink_message_append_string(m, type_system_union->match, key);
474 if (r < 0)
475 return r;
476
477 /* do we ever need non-null size */
478 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
479 if (r < 0)
480 return r;
481
482 m->containers[m->n_containers++].offset = r;
483
484 return 0;
485 }
486
487 int sd_netlink_message_close_container(sd_netlink_message *m) {
488 assert_return(m, -EINVAL);
489 assert_return(!m->sealed, -EPERM);
490 assert_return(m->n_containers > 0, -EINVAL);
491
492 m->containers[m->n_containers].type_system = NULL;
493 m->containers[m->n_containers].offset = 0;
494 m->n_containers--;
495
496 return 0;
497 }
498
499 int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
500 int r;
501
502 assert_return(m, -EINVAL);
503 assert_return(!m->sealed, -EPERM);
504 assert_return(m->n_containers > 0, -EINVAL);
505
506 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
507 if (r < 0)
508 return r;
509
510 m->containers[m->n_containers].offset = r;
511 m->n_containers++;
512 m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
513
514 return 0;
515 }
516
517 int sd_netlink_message_cancel_array(sd_netlink_message *m) {
518 unsigned i;
519 uint32_t rta_len;
520
521 assert_return(m, -EINVAL);
522 assert_return(!m->sealed, -EPERM);
523 assert_return(m->n_containers > 1, -EINVAL);
524
525 rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
526
527 for (i = 0; i < m->n_containers; i++)
528 GET_CONTAINER(m, i)->rta_len -= rta_len;
529
530 m->hdr->nlmsg_len -= rta_len;
531
532 m->n_containers--;
533 m->containers[m->n_containers].type_system = NULL;
534
535 return 0;
536 }
537
538 static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
539 struct netlink_attribute *attribute;
540 struct rtattr *rta;
541
542 assert_return(m, -EINVAL);
543 assert_return(m->sealed, -EPERM);
544 assert_return(data, -EINVAL);
545
546 assert(m->n_containers < RTNL_CONTAINER_DEPTH);
547 assert(m->containers[m->n_containers].attributes);
548 assert(type < m->containers[m->n_containers].n_attributes);
549
550 attribute = &m->containers[m->n_containers].attributes[type];
551
552 if (attribute->offset == 0)
553 return -ENODATA;
554
555 rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
556
557 *data = RTA_DATA(rta);
558
559 if (net_byteorder)
560 *net_byteorder = attribute->net_byteorder;
561
562 return RTA_PAYLOAD(rta);
563 }
564
565 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **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_STRING);
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 (strnlen(attr_data, r) >= (size_t) r)
579 return -EIO;
580
581 if (data)
582 *data = (const char *) attr_data;
583
584 return 0;
585 }
586
587 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
588 int r;
589 void *attr_data;
590
591 assert_return(m, -EINVAL);
592
593 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
594 if (r < 0)
595 return r;
596
597 r = netlink_message_read_internal(m, type, &attr_data, NULL);
598 if (r < 0)
599 return r;
600 else if ((size_t) r < sizeof(uint8_t))
601 return -EIO;
602
603 if (data)
604 *data = *(uint8_t *) attr_data;
605
606 return 0;
607 }
608
609 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
610 void *attr_data;
611 bool net_byteorder;
612 int r;
613
614 assert_return(m, -EINVAL);
615
616 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
617 if (r < 0)
618 return r;
619
620 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
621 if (r < 0)
622 return r;
623 else if ((size_t) r < sizeof(uint16_t))
624 return -EIO;
625
626 if (data) {
627 if (net_byteorder)
628 *data = be16toh(*(uint16_t *) attr_data);
629 else
630 *data = *(uint16_t *) attr_data;
631 }
632
633 return 0;
634 }
635
636 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
637 void *attr_data;
638 bool net_byteorder;
639 int r;
640
641 assert_return(m, -EINVAL);
642
643 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
644 if (r < 0)
645 return r;
646
647 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
648 if (r < 0)
649 return r;
650 else if ((size_t)r < sizeof(uint32_t))
651 return -EIO;
652
653 if (data) {
654 if (net_byteorder)
655 *data = be32toh(*(uint32_t *) attr_data);
656 else
657 *data = *(uint32_t *) attr_data;
658 }
659
660 return 0;
661 }
662
663 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
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_ETHER_ADDR);
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 ether_addr))
677 return -EIO;
678
679 if (data)
680 memcpy(data, attr_data, sizeof(struct ether_addr));
681
682 return 0;
683 }
684
685 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
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_CACHE_INFO);
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 ifa_cacheinfo))
699 return -EIO;
700
701 if (info)
702 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
703
704 return 0;
705 }
706
707 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_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 in_addr))
721 return -EIO;
722
723 if (data)
724 memcpy(data, attr_data, sizeof(struct in_addr));
725
726 return 0;
727 }
728
729 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
730 int r;
731 void *attr_data;
732
733 assert_return(m, -EINVAL);
734
735 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
736 if (r < 0)
737 return r;
738
739 r = netlink_message_read_internal(m, type, &attr_data, NULL);
740 if (r < 0)
741 return r;
742 else if ((size_t)r < sizeof(struct in6_addr))
743 return -EIO;
744
745 if (data)
746 memcpy(data, attr_data, sizeof(struct in6_addr));
747
748 return 0;
749 }
750
751 static int netlink_container_parse(sd_netlink_message *m,
752 struct netlink_container *container,
753 int count,
754 struct rtattr *rta,
755 unsigned rt_len) {
756 _cleanup_free_ struct netlink_attribute *attributes = NULL;
757
758 attributes = new0(struct netlink_attribute, count);
759 if (!attributes)
760 return -ENOMEM;
761
762 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
763 unsigned short type;
764
765 type = RTA_TYPE(rta);
766
767 /* if the kernel is newer than the headers we used
768 when building, we ignore out-of-range attributes */
769 if (type >= count)
770 continue;
771
772 if (attributes[type].offset != 0)
773 log_debug("rtnl: message parse - overwriting repeated attribute");
774
775 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
776 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
777 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
778 }
779
780 container->attributes = TAKE_PTR(attributes);
781 container->n_attributes = count;
782
783 return 0;
784 }
785
786 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
787 const NLType *nl_type;
788 const NLTypeSystem *type_system;
789 void *container;
790 uint16_t type;
791 size_t size;
792 int r;
793
794 assert_return(m, -EINVAL);
795 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
796
797 r = type_system_get_type(m->containers[m->n_containers].type_system,
798 &nl_type,
799 type_id);
800 if (r < 0)
801 return r;
802
803 type = type_get_type(nl_type);
804
805 if (type == NETLINK_TYPE_NESTED) {
806 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
807 &type_system,
808 type_id);
809 if (r < 0)
810 return r;
811 } else if (type == NETLINK_TYPE_UNION) {
812 const NLTypeSystemUnion *type_system_union;
813
814 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
815 &type_system_union,
816 type_id);
817 if (r < 0)
818 return r;
819
820 switch (type_system_union->match_type) {
821 case NL_MATCH_SIBLING:
822 {
823 const char *key;
824
825 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
826 if (r < 0)
827 return r;
828
829 r = type_system_union_get_type_system(type_system_union,
830 &type_system,
831 key);
832 if (r < 0)
833 return r;
834
835 break;
836 }
837 case NL_MATCH_PROTOCOL:
838 {
839 int family;
840
841 r = sd_rtnl_message_get_family(m, &family);
842 if (r < 0)
843 return r;
844
845 r = type_system_union_protocol_get_type_system(type_system_union,
846 &type_system,
847 family);
848 if (r < 0)
849 return r;
850
851 break;
852 }
853 default:
854 assert_not_reached("sd-netlink: invalid type system union type");
855 }
856 } else
857 return -EINVAL;
858
859 r = netlink_message_read_internal(m, type_id, &container, NULL);
860 if (r < 0)
861 return r;
862 else
863 size = (size_t)r;
864
865 m->n_containers++;
866
867 r = netlink_container_parse(m,
868 &m->containers[m->n_containers],
869 type_system_get_count(type_system),
870 container,
871 size);
872 if (r < 0) {
873 m->n_containers--;
874 return r;
875 }
876
877 m->containers[m->n_containers].type_system = type_system;
878
879 return 0;
880 }
881
882 int sd_netlink_message_exit_container(sd_netlink_message *m) {
883 assert_return(m, -EINVAL);
884 assert_return(m->sealed, -EINVAL);
885 assert_return(m->n_containers > 0, -EINVAL);
886
887 m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
888 m->containers[m->n_containers].type_system = NULL;
889
890 m->n_containers--;
891
892 return 0;
893 }
894
895 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
896 assert(m);
897 assert(m->hdr);
898
899 return m->hdr->nlmsg_seq;
900 }
901
902 int sd_netlink_message_is_error(sd_netlink_message *m) {
903 assert_return(m, 0);
904 assert_return(m->hdr, 0);
905
906 return m->hdr->nlmsg_type == NLMSG_ERROR;
907 }
908
909 int sd_netlink_message_get_errno(sd_netlink_message *m) {
910 struct nlmsgerr *err;
911
912 assert_return(m, -EINVAL);
913 assert_return(m->hdr, -EINVAL);
914
915 if (!sd_netlink_message_is_error(m))
916 return 0;
917
918 err = NLMSG_DATA(m->hdr);
919
920 return err->error;
921 }
922
923 int sd_netlink_message_rewind(sd_netlink_message *m) {
924 const NLType *nl_type;
925 const NLTypeSystem *type_system_root;
926 uint16_t type;
927 size_t size;
928 unsigned i;
929 int r;
930
931 assert_return(m, -EINVAL);
932
933 /* don't allow appending to message once parsed */
934 if (!m->sealed)
935 rtnl_message_seal(m);
936
937 type_system_root = type_system_get_root(m->protocol);
938
939 for (i = 1; i <= m->n_containers; i++)
940 m->containers[i].attributes = mfree(m->containers[i].attributes);
941
942 m->n_containers = 0;
943
944 if (m->containers[0].attributes)
945 /* top-level attributes have already been parsed */
946 return 0;
947
948 assert(m->hdr);
949
950 r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
951 if (r < 0)
952 return r;
953
954 type = type_get_type(nl_type);
955 size = type_get_size(nl_type);
956
957 if (type == NETLINK_TYPE_NESTED) {
958 const NLTypeSystem *type_system;
959
960 type_get_type_system(nl_type, &type_system);
961
962 m->containers[0].type_system = type_system;
963
964 r = netlink_container_parse(m,
965 &m->containers[m->n_containers],
966 type_system_get_count(type_system),
967 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
968 NLMSG_PAYLOAD(m->hdr, size));
969 if (r < 0)
970 return r;
971 }
972
973 return 0;
974 }
975
976 void rtnl_message_seal(sd_netlink_message *m) {
977 assert(m);
978 assert(!m->sealed);
979
980 m->sealed = true;
981 }
982
983 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
984 assert_return(m, NULL);
985
986 return m->next;
987 }