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