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