]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/netlink-message.c
Merge pull request #11716 from ssahani/drop-autoconf-address
[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 netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
338 int r;
339
340 assert_return(m, -EINVAL);
341 assert_return(!m->sealed, -EPERM);
342 assert_return(data, -EINVAL);
343 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
344
345 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
346 if (r < 0)
347 return r;
348
349 r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
350 if (r < 0)
351 return r;
352
353 return 0;
354 }
355
356 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
357 return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
358 }
359
360 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
361 return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
362 }
363
364 int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
365 int r;
366
367 assert_return(m, -EINVAL);
368 assert_return(!m->sealed, -EPERM);
369 assert_return(data, -EINVAL);
370 assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
371
372 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
373 if (r < 0)
374 return r;
375
376 r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
377 if (r < 0)
378 return r;
379
380 return 0;
381 }
382
383 int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
384 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
385 }
386
387 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
388 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
389 }
390
391
392 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
393 int r;
394
395 assert_return(m, -EINVAL);
396 assert_return(!m->sealed, -EPERM);
397 assert_return(data, -EINVAL);
398
399 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
400 if (r < 0)
401 return r;
402
403 r = add_rtattr(m, type, data, ETH_ALEN);
404 if (r < 0)
405 return r;
406
407 return 0;
408 }
409
410 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
411 int r;
412
413 assert_return(m, -EINVAL);
414 assert_return(!m->sealed, -EPERM);
415 assert_return(info, -EINVAL);
416
417 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
418 if (r < 0)
419 return r;
420
421 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
422 if (r < 0)
423 return r;
424
425 return 0;
426 }
427
428 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
429 size_t size;
430 int r;
431
432 assert_return(m, -EINVAL);
433 assert_return(!m->sealed, -EPERM);
434 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
435
436 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
437 if (r < 0) {
438 const NLTypeSystemUnion *type_system_union;
439 int family;
440
441 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
442 if (r < 0)
443 return r;
444
445 r = sd_rtnl_message_get_family(m, &family);
446 if (r < 0)
447 return r;
448
449 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
450 if (r < 0)
451 return r;
452
453 r = type_system_union_protocol_get_type_system(type_system_union,
454 &m->containers[m->n_containers + 1].type_system,
455 family);
456 if (r < 0)
457 return r;
458 } else {
459 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
460 &m->containers[m->n_containers + 1].type_system,
461 type);
462 if (r < 0)
463 return r;
464 }
465
466 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
467 if (r < 0)
468 return r;
469
470 m->containers[m->n_containers++].offset = r;
471
472 return 0;
473 }
474
475 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
476 const NLTypeSystemUnion *type_system_union;
477 int r;
478
479 assert_return(m, -EINVAL);
480 assert_return(!m->sealed, -EPERM);
481
482 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
483 if (r < 0)
484 return r;
485
486 r = type_system_union_get_type_system(type_system_union,
487 &m->containers[m->n_containers + 1].type_system,
488 key);
489 if (r < 0)
490 return r;
491
492 r = sd_netlink_message_append_string(m, type_system_union->match, key);
493 if (r < 0)
494 return r;
495
496 /* do we ever need non-null size */
497 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
498 if (r < 0)
499 return r;
500
501 m->containers[m->n_containers++].offset = r;
502
503 return 0;
504 }
505
506 int sd_netlink_message_close_container(sd_netlink_message *m) {
507 assert_return(m, -EINVAL);
508 assert_return(!m->sealed, -EPERM);
509 assert_return(m->n_containers > 0, -EINVAL);
510
511 m->containers[m->n_containers].type_system = NULL;
512 m->containers[m->n_containers].offset = 0;
513 m->n_containers--;
514
515 return 0;
516 }
517
518 int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
519 int r;
520
521 assert_return(m, -EINVAL);
522 assert_return(!m->sealed, -EPERM);
523 assert_return(m->n_containers > 0, -EINVAL);
524
525 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
526 if (r < 0)
527 return r;
528
529 m->containers[m->n_containers].offset = r;
530 m->n_containers++;
531 m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
532
533 return 0;
534 }
535
536 int sd_netlink_message_cancel_array(sd_netlink_message *m) {
537 unsigned i;
538 uint32_t rta_len;
539
540 assert_return(m, -EINVAL);
541 assert_return(!m->sealed, -EPERM);
542 assert_return(m->n_containers > 1, -EINVAL);
543
544 rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
545
546 for (i = 0; i < m->n_containers; i++)
547 GET_CONTAINER(m, i)->rta_len -= rta_len;
548
549 m->hdr->nlmsg_len -= rta_len;
550
551 m->n_containers--;
552 m->containers[m->n_containers].type_system = NULL;
553
554 return 0;
555 }
556
557 static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
558 struct netlink_attribute *attribute;
559 struct rtattr *rta;
560
561 assert_return(m, -EINVAL);
562 assert_return(m->sealed, -EPERM);
563 assert_return(data, -EINVAL);
564
565 assert(m->n_containers < RTNL_CONTAINER_DEPTH);
566 assert(m->containers[m->n_containers].attributes);
567 assert(type < m->containers[m->n_containers].n_attributes);
568
569 attribute = &m->containers[m->n_containers].attributes[type];
570
571 if (attribute->offset == 0)
572 return -ENODATA;
573
574 rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
575
576 *data = RTA_DATA(rta);
577
578 if (net_byteorder)
579 *net_byteorder = attribute->net_byteorder;
580
581 return RTA_PAYLOAD(rta);
582 }
583
584 int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
585 void *attr_data;
586 int r;
587
588 assert_return(m, -EINVAL);
589
590 r = netlink_message_read_internal(m, type, &attr_data, NULL);
591 if (r < 0)
592 return r;
593
594 if ((size_t) r < size)
595 return -EIO;
596
597 if (data)
598 memcpy(data, attr_data, size);
599
600 return 0;
601 }
602
603 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **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_STRING);
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 (strnlen(attr_data, r) >= (size_t) r)
617 return -EIO;
618
619 if (data)
620 *data = (const char *) attr_data;
621
622 return 0;
623 }
624
625 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
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_U8);
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(uint8_t))
639 return -EIO;
640
641 if (data)
642 *data = *(uint8_t *) attr_data;
643
644 return 0;
645 }
646
647 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
648 void *attr_data;
649 bool net_byteorder;
650 int r;
651
652 assert_return(m, -EINVAL);
653
654 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
655 if (r < 0)
656 return r;
657
658 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
659 if (r < 0)
660 return r;
661 else if ((size_t) r < sizeof(uint16_t))
662 return -EIO;
663
664 if (data) {
665 if (net_byteorder)
666 *data = be16toh(*(uint16_t *) attr_data);
667 else
668 *data = *(uint16_t *) attr_data;
669 }
670
671 return 0;
672 }
673
674 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
675 void *attr_data;
676 bool net_byteorder;
677 int r;
678
679 assert_return(m, -EINVAL);
680
681 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
682 if (r < 0)
683 return r;
684
685 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
686 if (r < 0)
687 return r;
688 else if ((size_t)r < sizeof(uint32_t))
689 return -EIO;
690
691 if (data) {
692 if (net_byteorder)
693 *data = be32toh(*(uint32_t *) attr_data);
694 else
695 *data = *(uint32_t *) attr_data;
696 }
697
698 return 0;
699 }
700
701 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
702 int r;
703 void *attr_data;
704
705 assert_return(m, -EINVAL);
706
707 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
708 if (r < 0)
709 return r;
710
711 r = netlink_message_read_internal(m, type, &attr_data, NULL);
712 if (r < 0)
713 return r;
714 else if ((size_t)r < sizeof(struct ether_addr))
715 return -EIO;
716
717 if (data)
718 memcpy(data, attr_data, sizeof(struct ether_addr));
719
720 return 0;
721 }
722
723 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
724 int r;
725 void *attr_data;
726
727 assert_return(m, -EINVAL);
728
729 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
730 if (r < 0)
731 return r;
732
733 r = netlink_message_read_internal(m, type, &attr_data, NULL);
734 if (r < 0)
735 return r;
736 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
737 return -EIO;
738
739 if (info)
740 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
741
742 return 0;
743 }
744
745 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
746 int r;
747 void *attr_data;
748
749 assert_return(m, -EINVAL);
750
751 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
752 if (r < 0)
753 return r;
754
755 r = netlink_message_read_internal(m, type, &attr_data, NULL);
756 if (r < 0)
757 return r;
758 else if ((size_t)r < sizeof(struct in_addr))
759 return -EIO;
760
761 if (data)
762 memcpy(data, attr_data, sizeof(struct in_addr));
763
764 return 0;
765 }
766
767 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
768 int r;
769 void *attr_data;
770
771 assert_return(m, -EINVAL);
772
773 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
774 if (r < 0)
775 return r;
776
777 r = netlink_message_read_internal(m, type, &attr_data, NULL);
778 if (r < 0)
779 return r;
780 else if ((size_t)r < sizeof(struct in6_addr))
781 return -EIO;
782
783 if (data)
784 memcpy(data, attr_data, sizeof(struct in6_addr));
785
786 return 0;
787 }
788
789 static int netlink_container_parse(sd_netlink_message *m,
790 struct netlink_container *container,
791 int count,
792 struct rtattr *rta,
793 unsigned rt_len) {
794 _cleanup_free_ struct netlink_attribute *attributes = NULL;
795
796 attributes = new0(struct netlink_attribute, count);
797 if (!attributes)
798 return -ENOMEM;
799
800 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
801 unsigned short type;
802
803 type = RTA_TYPE(rta);
804
805 /* if the kernel is newer than the headers we used
806 when building, we ignore out-of-range attributes */
807 if (type >= count)
808 continue;
809
810 if (attributes[type].offset != 0)
811 log_debug("rtnl: message parse - overwriting repeated attribute");
812
813 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
814 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
815 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
816 }
817
818 container->attributes = TAKE_PTR(attributes);
819 container->n_attributes = count;
820
821 return 0;
822 }
823
824 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
825 const NLType *nl_type;
826 const NLTypeSystem *type_system;
827 void *container;
828 uint16_t type;
829 size_t size;
830 int r;
831
832 assert_return(m, -EINVAL);
833 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
834
835 r = type_system_get_type(m->containers[m->n_containers].type_system,
836 &nl_type,
837 type_id);
838 if (r < 0)
839 return r;
840
841 type = type_get_type(nl_type);
842
843 if (type == NETLINK_TYPE_NESTED) {
844 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
845 &type_system,
846 type_id);
847 if (r < 0)
848 return r;
849 } else if (type == NETLINK_TYPE_UNION) {
850 const NLTypeSystemUnion *type_system_union;
851
852 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
853 &type_system_union,
854 type_id);
855 if (r < 0)
856 return r;
857
858 switch (type_system_union->match_type) {
859 case NL_MATCH_SIBLING:
860 {
861 const char *key;
862
863 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
864 if (r < 0)
865 return r;
866
867 r = type_system_union_get_type_system(type_system_union,
868 &type_system,
869 key);
870 if (r < 0)
871 return r;
872
873 break;
874 }
875 case NL_MATCH_PROTOCOL:
876 {
877 int family;
878
879 r = sd_rtnl_message_get_family(m, &family);
880 if (r < 0)
881 return r;
882
883 r = type_system_union_protocol_get_type_system(type_system_union,
884 &type_system,
885 family);
886 if (r < 0)
887 return r;
888
889 break;
890 }
891 default:
892 assert_not_reached("sd-netlink: invalid type system union type");
893 }
894 } else
895 return -EINVAL;
896
897 r = netlink_message_read_internal(m, type_id, &container, NULL);
898 if (r < 0)
899 return r;
900 else
901 size = (size_t)r;
902
903 m->n_containers++;
904
905 r = netlink_container_parse(m,
906 &m->containers[m->n_containers],
907 type_system_get_count(type_system),
908 container,
909 size);
910 if (r < 0) {
911 m->n_containers--;
912 return r;
913 }
914
915 m->containers[m->n_containers].type_system = type_system;
916
917 return 0;
918 }
919
920 int sd_netlink_message_exit_container(sd_netlink_message *m) {
921 assert_return(m, -EINVAL);
922 assert_return(m->sealed, -EINVAL);
923 assert_return(m->n_containers > 0, -EINVAL);
924
925 m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
926 m->containers[m->n_containers].type_system = NULL;
927
928 m->n_containers--;
929
930 return 0;
931 }
932
933 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
934 assert(m);
935 assert(m->hdr);
936
937 return m->hdr->nlmsg_seq;
938 }
939
940 int sd_netlink_message_is_error(sd_netlink_message *m) {
941 assert_return(m, 0);
942 assert_return(m->hdr, 0);
943
944 return m->hdr->nlmsg_type == NLMSG_ERROR;
945 }
946
947 int sd_netlink_message_get_errno(sd_netlink_message *m) {
948 struct nlmsgerr *err;
949
950 assert_return(m, -EINVAL);
951 assert_return(m->hdr, -EINVAL);
952
953 if (!sd_netlink_message_is_error(m))
954 return 0;
955
956 err = NLMSG_DATA(m->hdr);
957
958 return err->error;
959 }
960
961 int sd_netlink_message_rewind(sd_netlink_message *m) {
962 const NLType *nl_type;
963 const NLTypeSystem *type_system_root;
964 uint16_t type;
965 size_t size;
966 unsigned i;
967 int r;
968
969 assert_return(m, -EINVAL);
970
971 /* don't allow appending to message once parsed */
972 if (!m->sealed)
973 rtnl_message_seal(m);
974
975 type_system_root = type_system_get_root(m->protocol);
976
977 for (i = 1; i <= m->n_containers; i++)
978 m->containers[i].attributes = mfree(m->containers[i].attributes);
979
980 m->n_containers = 0;
981
982 if (m->containers[0].attributes)
983 /* top-level attributes have already been parsed */
984 return 0;
985
986 assert(m->hdr);
987
988 r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
989 if (r < 0)
990 return r;
991
992 type = type_get_type(nl_type);
993 size = type_get_size(nl_type);
994
995 if (type == NETLINK_TYPE_NESTED) {
996 const NLTypeSystem *type_system;
997
998 type_get_type_system(nl_type, &type_system);
999
1000 m->containers[0].type_system = type_system;
1001
1002 r = netlink_container_parse(m,
1003 &m->containers[m->n_containers],
1004 type_system_get_count(type_system),
1005 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1006 NLMSG_PAYLOAD(m->hdr, size));
1007 if (r < 0)
1008 return r;
1009 }
1010
1011 return 0;
1012 }
1013
1014 void rtnl_message_seal(sd_netlink_message *m) {
1015 assert(m);
1016 assert(!m->sealed);
1017
1018 m->sealed = true;
1019 }
1020
1021 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1022 assert_return(m, NULL);
1023
1024 return m->next;
1025 }