]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/netlink-message.c
Merge pull request #30513 from rpigott/resolved-ede
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 "memory-util.h"
12 #include "netlink-internal.h"
13 #include "netlink-types.h"
14 #include "netlink-util.h"
15 #include "socket-util.h"
16 #include "strv.h"
17
18 #define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
19
20 int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
21 sd_netlink_message *m;
22
23 assert(nl);
24 assert(ret);
25
26 /* Note that 'nl' is currently unused, if we start using it internally we must take care to
27 * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */
28
29 m = new(sd_netlink_message, 1);
30 if (!m)
31 return -ENOMEM;
32
33 *m = (sd_netlink_message) {
34 .n_ref = 1,
35 .protocol = nl->protocol,
36 .sealed = false,
37 };
38
39 *ret = m;
40 return 0;
41 }
42
43 int message_new_full(
44 sd_netlink *nl,
45 uint16_t nlmsg_type,
46 const NLAPolicySet *policy_set,
47 size_t header_size,
48 sd_netlink_message **ret) {
49
50 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
51 size_t size;
52 int r;
53
54 assert(nl);
55 assert(policy_set);
56 assert(ret);
57
58 size = NLMSG_SPACE(header_size);
59 assert(size >= sizeof(struct nlmsghdr));
60
61 r = message_new_empty(nl, &m);
62 if (r < 0)
63 return r;
64
65 m->containers[0].policy_set = policy_set;
66
67 m->hdr = malloc0(size);
68 if (!m->hdr)
69 return -ENOMEM;
70
71 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
72 m->hdr->nlmsg_len = size;
73 m->hdr->nlmsg_type = nlmsg_type;
74
75 *ret = TAKE_PTR(m);
76 return 0;
77 }
78
79 int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) {
80 const NLAPolicySet *policy_set;
81 size_t size;
82 int r;
83
84 assert_return(nl, -EINVAL);
85 assert_return(ret, -EINVAL);
86
87 r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, &policy_set, &size);
88 if (r < 0)
89 return r;
90
91 return message_new_full(nl, nlmsg_type, policy_set, size, ret);
92 }
93
94 int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
95 struct nlmsgerr *err;
96 int r;
97
98 assert(error <= 0);
99
100 r = message_new(nl, ret, NLMSG_ERROR);
101 if (r < 0)
102 return r;
103
104 message_seal(*ret);
105 (*ret)->hdr->nlmsg_seq = serial;
106
107 err = NLMSG_DATA((*ret)->hdr);
108 err->error = error;
109
110 return 0;
111 }
112
113 int sd_netlink_message_set_request_dump(sd_netlink_message *m, int dump) {
114 assert_return(m, -EINVAL);
115 assert_return(m->hdr, -EINVAL);
116 assert_return(m->protocol != NETLINK_ROUTE ||
117 IN_SET(m->hdr->nlmsg_type,
118 RTM_GETLINK, RTM_GETLINKPROP, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH,
119 RTM_GETRULE, RTM_GETADDRLABEL, RTM_GETNEXTHOP, RTM_GETQDISC, RTM_GETTCLASS),
120 -EINVAL);
121
122 SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
123
124 return 0;
125 }
126
127 DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
128
129 sd_netlink_message* sd_netlink_message_unref(sd_netlink_message *m) {
130 while (m && --m->n_ref == 0) {
131 unsigned i;
132
133 free(m->hdr);
134
135 for (i = 0; i <= m->n_containers; i++)
136 free(m->containers[i].attributes);
137
138 sd_netlink_message *t = m;
139 m = m->next;
140 free(t);
141 }
142
143 return NULL;
144 }
145
146 int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *ret) {
147 assert_return(m, -EINVAL);
148 assert_return(ret, -EINVAL);
149
150 *ret = m->hdr->nlmsg_type;
151
152 return 0;
153 }
154
155 int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
156 assert_return(m, -EINVAL);
157 assert_return(flags != 0, -EINVAL);
158
159 m->hdr->nlmsg_flags = flags;
160
161 return 0;
162 }
163
164 int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
165 assert_return(m, -EINVAL);
166
167 return m->multicast_group != 0;
168 }
169
170 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is untouched. */
171 static int add_rtattr(sd_netlink_message *m, uint16_t attr_type, const void *data, size_t data_length) {
172 size_t message_length;
173 struct nlmsghdr *new_hdr;
174 struct rtattr *rta;
175 int offset;
176
177 assert(m);
178 assert(m->hdr);
179 assert(!m->sealed);
180 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
181 assert(!data || data_length > 0);
182
183 /* get the new message size (with padding at the end) */
184 message_length = m->hdr->nlmsg_len + RTA_SPACE(data_length);
185
186 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
187 if (message_length > MIN(page_size(), 8192UL))
188 return -ENOBUFS;
189
190 /* realloc to fit the new attribute */
191 new_hdr = realloc(m->hdr, message_length);
192 if (!new_hdr)
193 return -ENOMEM;
194 m->hdr = new_hdr;
195
196 /* get pointer to the attribute we are about to add */
197 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
198
199 rtattr_append_attribute_internal(rta, attr_type, data, data_length);
200
201 /* if we are inside containers, extend them */
202 for (unsigned i = 0; i < m->n_containers; i++)
203 GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length);
204
205 /* update message size */
206 offset = m->hdr->nlmsg_len;
207 m->hdr->nlmsg_len = message_length;
208
209 /* return old message size */
210 return offset;
211 }
212
213 static int message_attribute_has_type(sd_netlink_message *m, size_t *ret_size, uint16_t attr_type, NLAType type) {
214 const NLAPolicy *policy;
215
216 assert(m);
217
218 policy = policy_set_get_policy(m->containers[m->n_containers].policy_set, attr_type);
219 if (!policy)
220 return -EOPNOTSUPP;
221
222 if (policy_get_type(policy) != type)
223 return -EINVAL;
224
225 if (ret_size)
226 *ret_size = policy_get_size(policy);
227 return 0;
228 }
229
230 int sd_netlink_message_append_string(sd_netlink_message *m, uint16_t attr_type, const char *data) {
231 size_t length, size;
232 int r;
233
234 assert_return(m, -EINVAL);
235 assert_return(!m->sealed, -EPERM);
236 assert_return(data, -EINVAL);
237
238 r = message_attribute_has_type(m, &size, attr_type, NETLINK_TYPE_STRING);
239 if (r < 0)
240 return r;
241
242 if (size) {
243 length = strnlen(data, size+1);
244 if (length > size)
245 return -EINVAL;
246 } else
247 length = strlen(data);
248
249 r = add_rtattr(m, attr_type, data, length + 1);
250 if (r < 0)
251 return r;
252
253 return 0;
254 }
255
256 int sd_netlink_message_append_strv(sd_netlink_message *m, uint16_t attr_type, const char* const *data) {
257 size_t length, size;
258 int r;
259
260 assert_return(m, -EINVAL);
261 assert_return(!m->sealed, -EPERM);
262 assert_return(data, -EINVAL);
263
264 r = message_attribute_has_type(m, &size, attr_type, NETLINK_TYPE_STRING);
265 if (r < 0)
266 return r;
267
268 STRV_FOREACH(p, data) {
269 if (size) {
270 length = strnlen(*p, size+1);
271 if (length > size)
272 return -EINVAL;
273 } else
274 length = strlen(*p);
275
276 r = add_rtattr(m, attr_type, *p, length + 1);
277 if (r < 0)
278 return r;
279 }
280
281 return 0;
282 }
283
284 int sd_netlink_message_append_flag(sd_netlink_message *m, uint16_t attr_type) {
285 size_t size;
286 int r;
287
288 assert_return(m, -EINVAL);
289 assert_return(!m->sealed, -EPERM);
290
291 r = message_attribute_has_type(m, &size, attr_type, NETLINK_TYPE_FLAG);
292 if (r < 0)
293 return r;
294
295 r = add_rtattr(m, attr_type, NULL, 0);
296 if (r < 0)
297 return r;
298
299 return 0;
300 }
301
302 int sd_netlink_message_append_u8(sd_netlink_message *m, uint16_t attr_type, uint8_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, attr_type, NETLINK_TYPE_U8);
309 if (r < 0)
310 return r;
311
312 r = add_rtattr(m, attr_type, &data, sizeof(uint8_t));
313 if (r < 0)
314 return r;
315
316 return 0;
317 }
318
319 int sd_netlink_message_append_u16(sd_netlink_message *m, uint16_t attr_type, uint16_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, attr_type, NETLINK_TYPE_U16);
326 if (r < 0)
327 return r;
328
329 r = add_rtattr(m, attr_type, &data, sizeof(uint16_t));
330 if (r < 0)
331 return r;
332
333 return 0;
334 }
335
336 int sd_netlink_message_append_u32(sd_netlink_message *m, uint16_t attr_type, uint32_t data) {
337 int r;
338
339 assert_return(m, -EINVAL);
340 assert_return(!m->sealed, -EPERM);
341
342 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U32);
343 if (r < 0)
344 return r;
345
346 r = add_rtattr(m, attr_type, &data, sizeof(uint32_t));
347 if (r < 0)
348 return r;
349
350 return 0;
351 }
352
353 int sd_netlink_message_append_u64(sd_netlink_message *m, uint16_t attr_type, uint64_t data) {
354 int r;
355
356 assert_return(m, -EINVAL);
357 assert_return(!m->sealed, -EPERM);
358
359 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U64);
360 if (r < 0)
361 return r;
362
363 r = add_rtattr(m, attr_type, &data, sizeof(uint64_t));
364 if (r < 0)
365 return r;
366
367 return 0;
368 }
369
370 int sd_netlink_message_append_s8(sd_netlink_message *m, uint16_t attr_type, int8_t data) {
371 int r;
372
373 assert_return(m, -EINVAL);
374 assert_return(!m->sealed, -EPERM);
375
376 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_S8);
377 if (r < 0)
378 return r;
379
380 r = add_rtattr(m, attr_type, &data, sizeof(int8_t));
381 if (r < 0)
382 return r;
383
384 return 0;
385 }
386
387 int sd_netlink_message_append_s16(sd_netlink_message *m, uint16_t attr_type, int16_t data) {
388 int r;
389
390 assert_return(m, -EINVAL);
391 assert_return(!m->sealed, -EPERM);
392
393 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_S16);
394 if (r < 0)
395 return r;
396
397 r = add_rtattr(m, attr_type, &data, sizeof(int16_t));
398 if (r < 0)
399 return r;
400
401 return 0;
402 }
403
404 int sd_netlink_message_append_s32(sd_netlink_message *m, uint16_t attr_type, int32_t data) {
405 int r;
406
407 assert_return(m, -EINVAL);
408 assert_return(!m->sealed, -EPERM);
409
410 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_S32);
411 if (r < 0)
412 return r;
413
414 r = add_rtattr(m, attr_type, &data, sizeof(int32_t));
415 if (r < 0)
416 return r;
417
418 return 0;
419 }
420
421 int sd_netlink_message_append_s64(sd_netlink_message *m, uint16_t attr_type, int64_t data) {
422 int r;
423
424 assert_return(m, -EINVAL);
425 assert_return(!m->sealed, -EPERM);
426
427 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_S64);
428 if (r < 0)
429 return r;
430
431 r = add_rtattr(m, attr_type, &data, sizeof(int64_t));
432 if (r < 0)
433 return r;
434
435 return 0;
436 }
437
438 int sd_netlink_message_append_data(sd_netlink_message *m, uint16_t attr_type, const void *data, size_t len) {
439 int r;
440
441 assert_return(m, -EINVAL);
442 assert_return(!m->sealed, -EPERM);
443
444 r = add_rtattr(m, attr_type, data, len);
445 if (r < 0)
446 return r;
447
448 return 0;
449 }
450
451 int sd_netlink_message_append_container_data(
452 sd_netlink_message *m,
453 uint16_t container_type,
454 uint16_t attr_type,
455 const void *data,
456 size_t len) {
457
458 int r;
459
460 assert_return(m, -EINVAL);
461 assert_return(!m->sealed, -EPERM);
462
463 r = sd_netlink_message_open_container(m, container_type);
464 if (r < 0)
465 return r;
466
467 r = sd_netlink_message_append_data(m, attr_type, data, len);
468 if (r < 0)
469 return r;
470
471 return sd_netlink_message_close_container(m);
472 }
473
474 int netlink_message_append_in_addr_union(sd_netlink_message *m, uint16_t attr_type, int family, const union in_addr_union *data) {
475 int r;
476
477 assert_return(m, -EINVAL);
478 assert_return(!m->sealed, -EPERM);
479 assert_return(data, -EINVAL);
480 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
481
482 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_IN_ADDR);
483 if (r < 0)
484 return r;
485
486 r = add_rtattr(m, attr_type, data, FAMILY_ADDRESS_SIZE(family));
487 if (r < 0)
488 return r;
489
490 return 0;
491 }
492
493 int sd_netlink_message_append_in_addr(sd_netlink_message *m, uint16_t attr_type, const struct in_addr *data) {
494 return netlink_message_append_in_addr_union(m, attr_type, AF_INET, (const union in_addr_union *) data);
495 }
496
497 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, uint16_t attr_type, const struct in6_addr *data) {
498 return netlink_message_append_in_addr_union(m, attr_type, AF_INET6, (const union in_addr_union *) data);
499 }
500
501 int netlink_message_append_sockaddr_union(sd_netlink_message *m, uint16_t attr_type, const union sockaddr_union *data) {
502 int r;
503
504 assert_return(m, -EINVAL);
505 assert_return(!m->sealed, -EPERM);
506 assert_return(data, -EINVAL);
507 assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
508
509 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_SOCKADDR);
510 if (r < 0)
511 return r;
512
513 r = add_rtattr(m, attr_type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
514 if (r < 0)
515 return r;
516
517 return 0;
518 }
519
520 int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, uint16_t attr_type, const struct sockaddr_in *data) {
521 return netlink_message_append_sockaddr_union(m, attr_type, (const union sockaddr_union *) data);
522 }
523
524 int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, uint16_t attr_type, const struct sockaddr_in6 *data) {
525 return netlink_message_append_sockaddr_union(m, attr_type, (const union sockaddr_union *) data);
526 }
527
528 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, uint16_t attr_type, const struct ether_addr *data) {
529 int r;
530
531 assert_return(m, -EINVAL);
532 assert_return(!m->sealed, -EPERM);
533 assert_return(data, -EINVAL);
534
535 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
536 if (r < 0)
537 return r;
538
539 r = add_rtattr(m, attr_type, data, ETH_ALEN);
540 if (r < 0)
541 return r;
542
543 return 0;
544 }
545
546 int netlink_message_append_hw_addr(sd_netlink_message *m, uint16_t attr_type, const struct hw_addr_data *data) {
547 int r;
548
549 assert_return(m, -EINVAL);
550 assert_return(!m->sealed, -EPERM);
551 assert_return(data, -EINVAL);
552 assert_return(data->length > 0, -EINVAL);
553
554 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
555 if (r < 0)
556 return r;
557
558 r = add_rtattr(m, attr_type, data->bytes, data->length);
559 if (r < 0)
560 return r;
561
562 return 0;
563 }
564
565 int sd_netlink_message_append_cache_info(sd_netlink_message *m, uint16_t attr_type, const struct ifa_cacheinfo *info) {
566 int r;
567
568 assert_return(m, -EINVAL);
569 assert_return(!m->sealed, -EPERM);
570 assert_return(info, -EINVAL);
571
572 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_CACHE_INFO);
573 if (r < 0)
574 return r;
575
576 r = add_rtattr(m, attr_type, info, sizeof(struct ifa_cacheinfo));
577 if (r < 0)
578 return r;
579
580 return 0;
581 }
582
583 int sd_netlink_message_open_container(sd_netlink_message *m, uint16_t attr_type) {
584 size_t size;
585 int r;
586
587 assert_return(m, -EINVAL);
588 assert_return(!m->sealed, -EPERM);
589 /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
590 assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
591
592 r = message_attribute_has_type(m, &size, attr_type, NETLINK_TYPE_NESTED);
593 if (r < 0) {
594 const NLAPolicySetUnion *policy_set_union;
595 int family;
596
597 r = message_attribute_has_type(m, &size, attr_type, NETLINK_TYPE_NESTED_UNION_BY_FAMILY);
598 if (r < 0)
599 return r;
600
601 r = sd_rtnl_message_get_family(m, &family);
602 if (r < 0)
603 return r;
604
605 policy_set_union = policy_set_get_policy_set_union(
606 m->containers[m->n_containers].policy_set,
607 attr_type);
608 if (!policy_set_union)
609 return -EOPNOTSUPP;
610
611 m->containers[m->n_containers + 1].policy_set =
612 policy_set_union_get_policy_set_by_family(
613 policy_set_union,
614 family);
615 } else
616 m->containers[m->n_containers + 1].policy_set =
617 policy_set_get_policy_set(
618 m->containers[m->n_containers].policy_set,
619 attr_type);
620 if (!m->containers[m->n_containers + 1].policy_set)
621 return -EOPNOTSUPP;
622
623 r = add_rtattr(m, attr_type | NLA_F_NESTED, NULL, size);
624 if (r < 0)
625 return r;
626
627 m->containers[m->n_containers++].offset = r;
628
629 return 0;
630 }
631
632 int sd_netlink_message_open_container_union(sd_netlink_message *m, uint16_t attr_type, const char *key) {
633 const NLAPolicySetUnion *policy_set_union;
634 int r;
635
636 assert_return(m, -EINVAL);
637 assert_return(!m->sealed, -EPERM);
638 assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
639
640 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_NESTED_UNION_BY_STRING);
641 if (r < 0)
642 return r;
643
644 policy_set_union = policy_set_get_policy_set_union(
645 m->containers[m->n_containers].policy_set,
646 attr_type);
647 if (!policy_set_union)
648 return -EOPNOTSUPP;
649
650 m->containers[m->n_containers + 1].policy_set =
651 policy_set_union_get_policy_set_by_string(
652 policy_set_union,
653 key);
654 if (!m->containers[m->n_containers + 1].policy_set)
655 return -EOPNOTSUPP;
656
657 r = sd_netlink_message_append_string(m, policy_set_union_get_match_attribute(policy_set_union), key);
658 if (r < 0)
659 return r;
660
661 /* do we ever need non-null size */
662 r = add_rtattr(m, attr_type | NLA_F_NESTED, NULL, 0);
663 if (r < 0)
664 return r;
665
666 m->containers[m->n_containers++].offset = r;
667
668 return 0;
669 }
670
671 int sd_netlink_message_close_container(sd_netlink_message *m) {
672 assert_return(m, -EINVAL);
673 assert_return(!m->sealed, -EPERM);
674 assert_return(m->n_containers > 0, -EINVAL);
675
676 m->containers[m->n_containers].policy_set = NULL;
677 m->containers[m->n_containers].offset = 0;
678 m->n_containers--;
679
680 return 0;
681 }
682
683 int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t attr_type) {
684 int r;
685
686 assert_return(m, -EINVAL);
687 assert_return(!m->sealed, -EPERM);
688 assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE);
689
690 r = add_rtattr(m, attr_type | NLA_F_NESTED, NULL, 0);
691 if (r < 0)
692 return r;
693
694 m->containers[m->n_containers].offset = r;
695 m->n_containers++;
696 m->containers[m->n_containers].policy_set = m->containers[m->n_containers - 1].policy_set;
697
698 return 0;
699 }
700
701 int sd_netlink_message_cancel_array(sd_netlink_message *m) {
702 uint32_t rta_len;
703
704 assert_return(m, -EINVAL);
705 assert_return(!m->sealed, -EPERM);
706 assert_return(m->n_containers > 1, -EINVAL);
707
708 rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
709
710 for (unsigned i = 0; i < m->n_containers; i++)
711 GET_CONTAINER(m, i)->rta_len -= rta_len;
712
713 m->hdr->nlmsg_len -= rta_len;
714
715 m->n_containers--;
716 m->containers[m->n_containers].policy_set = NULL;
717
718 return 0;
719 }
720
721 static int netlink_message_read_internal(
722 sd_netlink_message *m,
723 uint16_t attr_type,
724 void **ret_data,
725 bool *ret_net_byteorder) {
726
727 struct netlink_attribute *attribute;
728 struct rtattr *rta;
729
730 assert_return(m, -EINVAL);
731 assert_return(m->sealed, -EPERM);
732
733 assert(m->n_containers < NETLINK_CONTAINER_DEPTH);
734
735 if (!m->containers[m->n_containers].attributes)
736 return -ENODATA;
737
738 if (attr_type > m->containers[m->n_containers].max_attribute)
739 return -ENODATA;
740
741 attribute = &m->containers[m->n_containers].attributes[attr_type];
742
743 if (attribute->offset == 0)
744 return -ENODATA;
745
746 rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
747
748 if (ret_data)
749 *ret_data = RTA_DATA(rta);
750
751 if (ret_net_byteorder)
752 *ret_net_byteorder = attribute->net_byteorder;
753
754 return RTA_PAYLOAD(rta);
755 }
756
757 int sd_netlink_message_read(sd_netlink_message *m, uint16_t attr_type, size_t size, void *data) {
758 void *attr_data;
759 int r;
760
761 assert_return(m, -EINVAL);
762
763 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
764 if (r < 0)
765 return r;
766
767 if ((size_t) r > size)
768 return -ENOBUFS;
769
770 if (data)
771 memcpy(data, attr_data, r);
772
773 return r;
774 }
775
776 int sd_netlink_message_read_data(sd_netlink_message *m, uint16_t attr_type, size_t *ret_size, void **ret_data) {
777 void *attr_data;
778 int r;
779
780 assert_return(m, -EINVAL);
781
782 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
783 if (r < 0)
784 return r;
785
786 if (ret_data) {
787 void *data;
788
789 data = memdup(attr_data, r);
790 if (!data)
791 return -ENOMEM;
792
793 *ret_data = data;
794 }
795
796 if (ret_size)
797 *ret_size = r;
798
799 return r;
800 }
801
802 int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, uint16_t attr_type, size_t *ret_size, void **ret_data) {
803 void *attr_data;
804 int r;
805
806 assert_return(m, -EINVAL);
807
808 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
809 if (r < 0)
810 return r;
811
812 if (ret_data) {
813 void *data;
814
815 data = memdup_suffix0(attr_data, r);
816 if (!data)
817 return -ENOMEM;
818
819 *ret_data = data;
820 }
821
822 if (ret_size)
823 *ret_size = r;
824
825 return r;
826 }
827
828 int sd_netlink_message_read_string_strdup(sd_netlink_message *m, uint16_t attr_type, char **data) {
829 void *attr_data;
830 int r;
831
832 assert_return(m, -EINVAL);
833
834 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_STRING);
835 if (r < 0)
836 return r;
837
838 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
839 if (r < 0)
840 return r;
841
842 if (data) {
843 char *str;
844
845 str = strndup(attr_data, r);
846 if (!str)
847 return -ENOMEM;
848
849 *data = str;
850 }
851
852 return 0;
853 }
854
855 int sd_netlink_message_read_string(sd_netlink_message *m, uint16_t attr_type, const char **data) {
856 void *attr_data;
857 int r;
858
859 assert_return(m, -EINVAL);
860
861 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_STRING);
862 if (r < 0)
863 return r;
864
865 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
866 if (r < 0)
867 return r;
868
869 if (strnlen(attr_data, r) >= (size_t) r)
870 return -EIO;
871
872 if (data)
873 *data = (const char *) attr_data;
874
875 return 0;
876 }
877
878 int sd_netlink_message_read_u8(sd_netlink_message *m, uint16_t attr_type, uint8_t *data) {
879 void *attr_data;
880 int r;
881
882 assert_return(m, -EINVAL);
883
884 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U8);
885 if (r < 0)
886 return r;
887
888 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
889 if (r < 0)
890 return r;
891
892 if ((size_t) r < sizeof(uint8_t))
893 return -EIO;
894
895 if (data)
896 *data = *(uint8_t *) attr_data;
897
898 return 0;
899 }
900
901 int sd_netlink_message_read_u16(sd_netlink_message *m, uint16_t attr_type, uint16_t *data) {
902 void *attr_data;
903 bool net_byteorder;
904 int r;
905
906 assert_return(m, -EINVAL);
907
908 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U16);
909 if (r < 0)
910 return r;
911
912 r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
913 if (r < 0)
914 return r;
915
916 if ((size_t) r < sizeof(uint16_t))
917 return -EIO;
918
919 if (data) {
920 if (net_byteorder)
921 *data = be16toh(*(uint16_t *) attr_data);
922 else
923 *data = *(uint16_t *) attr_data;
924 }
925
926 return 0;
927 }
928
929 int sd_netlink_message_read_u32(sd_netlink_message *m, uint16_t attr_type, uint32_t *data) {
930 void *attr_data;
931 bool net_byteorder;
932 int r;
933
934 assert_return(m, -EINVAL);
935
936 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_U32);
937 if (r < 0)
938 return r;
939
940 r = netlink_message_read_internal(m, attr_type, &attr_data, &net_byteorder);
941 if (r < 0)
942 return r;
943
944 if ((size_t) r < sizeof(uint32_t))
945 return -EIO;
946
947 if (data) {
948 if (net_byteorder)
949 *data = be32toh(*(uint32_t *) attr_data);
950 else
951 *data = *(uint32_t *) attr_data;
952 }
953
954 return 0;
955 }
956
957 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, uint16_t attr_type, struct ether_addr *data) {
958 void *attr_data;
959 int r;
960
961 assert_return(m, -EINVAL);
962
963 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
964 if (r < 0)
965 return r;
966
967 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
968 if (r < 0)
969 return r;
970
971 if ((size_t) r < sizeof(struct ether_addr))
972 return -EIO;
973
974 if (data)
975 memcpy(data, attr_data, sizeof(struct ether_addr));
976
977 return 0;
978 }
979
980 int netlink_message_read_hw_addr(sd_netlink_message *m, uint16_t attr_type, struct hw_addr_data *data) {
981 void *attr_data;
982 int r;
983
984 assert_return(m, -EINVAL);
985
986 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_ETHER_ADDR);
987 if (r < 0)
988 return r;
989
990 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
991 if (r < 0)
992 return r;
993
994 if (r > HW_ADDR_MAX_SIZE)
995 return -EIO;
996
997 if (data) {
998 memcpy(data->bytes, attr_data, r);
999 data->length = r;
1000 }
1001
1002 return 0;
1003 }
1004
1005 int sd_netlink_message_read_cache_info(sd_netlink_message *m, uint16_t attr_type, struct ifa_cacheinfo *info) {
1006 void *attr_data;
1007 int r;
1008
1009 assert_return(m, -EINVAL);
1010
1011 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_CACHE_INFO);
1012 if (r < 0)
1013 return r;
1014
1015 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
1016 if (r < 0)
1017 return r;
1018
1019 if ((size_t) r < sizeof(struct ifa_cacheinfo))
1020 return -EIO;
1021
1022 if (info)
1023 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
1024
1025 return 0;
1026 }
1027
1028 int netlink_message_read_in_addr_union(sd_netlink_message *m, uint16_t attr_type, int family, union in_addr_union *data) {
1029 void *attr_data;
1030 int r;
1031
1032 assert_return(m, -EINVAL);
1033 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
1034
1035 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_IN_ADDR);
1036 if (r < 0)
1037 return r;
1038
1039 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
1040 if (r < 0)
1041 return r;
1042
1043 if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
1044 return -EIO;
1045
1046 if (data)
1047 memcpy(data, attr_data, FAMILY_ADDRESS_SIZE(family));
1048
1049 return 0;
1050 }
1051
1052 int sd_netlink_message_read_in_addr(sd_netlink_message *m, uint16_t attr_type, struct in_addr *data) {
1053 union in_addr_union u;
1054 int r;
1055
1056 r = netlink_message_read_in_addr_union(m, attr_type, AF_INET, &u);
1057 if (r >= 0 && data)
1058 *data = u.in;
1059
1060 return r;
1061 }
1062
1063 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, uint16_t attr_type, struct in6_addr *data) {
1064 union in_addr_union u;
1065 int r;
1066
1067 r = netlink_message_read_in_addr_union(m, attr_type, AF_INET6, &u);
1068 if (r >= 0 && data)
1069 *data = u.in6;
1070
1071 return r;
1072 }
1073
1074 int sd_netlink_message_has_flag(sd_netlink_message *m, uint16_t attr_type) {
1075 void *attr_data;
1076 int r;
1077
1078 assert_return(m, -EINVAL);
1079
1080 /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
1081
1082 r = message_attribute_has_type(m, NULL, attr_type, NETLINK_TYPE_FLAG);
1083 if (r < 0)
1084 return r;
1085
1086 r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
1087 if (r == -ENODATA)
1088 return 0;
1089 if (r < 0)
1090 return r;
1091
1092 return 1;
1093 }
1094
1095 int sd_netlink_message_read_strv(sd_netlink_message *m, uint16_t container_type, uint16_t attr_type, char ***ret) {
1096 _cleanup_strv_free_ char **s = NULL;
1097 const NLAPolicySet *policy_set;
1098 const NLAPolicy *policy;
1099 struct rtattr *rta;
1100 void *container;
1101 size_t rt_len;
1102 int r;
1103
1104 assert_return(m, -EINVAL);
1105 assert_return(m->n_containers < NETLINK_CONTAINER_DEPTH, -EINVAL);
1106
1107 policy = policy_set_get_policy(
1108 m->containers[m->n_containers].policy_set,
1109 container_type);
1110 if (!policy)
1111 return -EOPNOTSUPP;
1112
1113 if (policy_get_type(policy) != NETLINK_TYPE_NESTED)
1114 return -EINVAL;
1115
1116 policy_set = policy_set_get_policy_set(
1117 m->containers[m->n_containers].policy_set,
1118 container_type);
1119 if (!policy_set)
1120 return -EOPNOTSUPP;
1121
1122 policy = policy_set_get_policy(policy_set, attr_type);
1123 if (!policy)
1124 return -EOPNOTSUPP;
1125
1126 if (policy_get_type(policy) != NETLINK_TYPE_STRING)
1127 return -EINVAL;
1128
1129 r = netlink_message_read_internal(m, container_type, &container, NULL);
1130 if (r < 0)
1131 return r;
1132
1133 rt_len = (size_t) r;
1134 rta = container;
1135
1136 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1137 * LGTM.com analysis does not like the type difference. Hence, here we
1138 * introduce an unsigned short variable as a workaround. */
1139 unsigned short len = rt_len;
1140 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
1141 uint16_t type;
1142
1143 type = RTA_TYPE(rta);
1144 if (type != attr_type)
1145 continue;
1146
1147 r = strv_extend(&s, RTA_DATA(rta));
1148 if (r < 0)
1149 return r;
1150 }
1151
1152 *ret = TAKE_PTR(s);
1153 return 0;
1154 }
1155
1156 static int netlink_container_parse(
1157 sd_netlink_message *m,
1158 struct netlink_container *container,
1159 struct rtattr *rta,
1160 size_t rt_len) {
1161
1162 _cleanup_free_ struct netlink_attribute *attributes = NULL;
1163 uint16_t max_attr = 0;
1164
1165 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1166 * LGTM.com analysis does not like the type difference. Hence, here we
1167 * introduce an unsigned short variable as a workaround. */
1168 unsigned short len = rt_len;
1169 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
1170 uint16_t attr;
1171
1172 attr = RTA_TYPE(rta);
1173 max_attr = MAX(max_attr, attr);
1174
1175 if (!GREEDY_REALLOC0(attributes, (size_t) max_attr + 1))
1176 return -ENOMEM;
1177
1178 if (attributes[attr].offset != 0)
1179 log_debug("sd-netlink: message parse - overwriting repeated attribute");
1180
1181 attributes[attr].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
1182 attributes[attr].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
1183 attributes[attr].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
1184 }
1185
1186 container->attributes = TAKE_PTR(attributes);
1187 container->max_attribute = max_attr;
1188
1189 return 0;
1190 }
1191
1192 int sd_netlink_message_enter_container(sd_netlink_message *m, uint16_t attr_type) {
1193 const NLAPolicy *policy;
1194 const NLAPolicySet *policy_set;
1195 void *container;
1196 size_t size;
1197 int r;
1198
1199 assert_return(m, -EINVAL);
1200 assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
1201
1202 policy = policy_set_get_policy(
1203 m->containers[m->n_containers].policy_set,
1204 attr_type);
1205 if (!policy)
1206 return -EOPNOTSUPP;
1207
1208 switch (policy_get_type(policy)) {
1209 case NETLINK_TYPE_NESTED:
1210 policy_set = policy_set_get_policy_set(
1211 m->containers[m->n_containers].policy_set,
1212 attr_type);
1213 break;
1214
1215 case NETLINK_TYPE_NESTED_UNION_BY_STRING: {
1216 const NLAPolicySetUnion *policy_set_union;
1217 const char *key;
1218
1219 policy_set_union = policy_get_policy_set_union(policy);
1220 if (!policy_set_union)
1221 return -EOPNOTSUPP;
1222
1223 r = sd_netlink_message_read_string(
1224 m,
1225 policy_set_union_get_match_attribute(policy_set_union),
1226 &key);
1227 if (r < 0)
1228 return r;
1229
1230 policy_set = policy_set_union_get_policy_set_by_string(
1231 policy_set_union,
1232 key);
1233 break;
1234 }
1235 case NETLINK_TYPE_NESTED_UNION_BY_FAMILY: {
1236 const NLAPolicySetUnion *policy_set_union;
1237 int family;
1238
1239 policy_set_union = policy_get_policy_set_union(policy);
1240 if (!policy_set_union)
1241 return -EOPNOTSUPP;
1242
1243 r = sd_rtnl_message_get_family(m, &family);
1244 if (r < 0)
1245 return r;
1246
1247 policy_set = policy_set_union_get_policy_set_by_family(
1248 policy_set_union,
1249 family);
1250 break;
1251 }
1252 default:
1253 assert_not_reached();
1254 }
1255 if (!policy_set)
1256 return -EOPNOTSUPP;
1257
1258 r = netlink_message_read_internal(m, attr_type, &container, NULL);
1259 if (r < 0)
1260 return r;
1261
1262 size = (size_t) r;
1263 m->n_containers++;
1264
1265 r = netlink_container_parse(m,
1266 &m->containers[m->n_containers],
1267 container,
1268 size);
1269 if (r < 0) {
1270 m->n_containers--;
1271 return r;
1272 }
1273
1274 m->containers[m->n_containers].policy_set = policy_set;
1275
1276 return 0;
1277 }
1278
1279 int sd_netlink_message_enter_array(sd_netlink_message *m, uint16_t attr_type) {
1280 void *container;
1281 size_t size;
1282 int r;
1283
1284 assert_return(m, -EINVAL);
1285 assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL);
1286
1287 r = netlink_message_read_internal(m, attr_type, &container, NULL);
1288 if (r < 0)
1289 return r;
1290
1291 size = (size_t) r;
1292 m->n_containers++;
1293
1294 r = netlink_container_parse(m,
1295 &m->containers[m->n_containers],
1296 container,
1297 size);
1298 if (r < 0) {
1299 m->n_containers--;
1300 return r;
1301 }
1302
1303 m->containers[m->n_containers].policy_set = m->containers[m->n_containers - 1].policy_set;
1304
1305 return 0;
1306 }
1307
1308 int sd_netlink_message_exit_container(sd_netlink_message *m) {
1309 assert_return(m, -EINVAL);
1310 assert_return(m->sealed, -EINVAL);
1311 assert_return(m->n_containers > 0, -EINVAL);
1312
1313 m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
1314 m->containers[m->n_containers].max_attribute = 0;
1315 m->containers[m->n_containers].policy_set = NULL;
1316
1317 m->n_containers--;
1318
1319 return 0;
1320 }
1321
1322 int sd_netlink_message_get_max_attribute(sd_netlink_message *m, uint16_t *ret) {
1323 assert_return(m, -EINVAL);
1324 assert_return(m->sealed, -EINVAL);
1325 assert_return(ret, -EINVAL);
1326
1327 *ret = m->containers[m->n_containers].max_attribute;
1328 return 0;
1329 }
1330
1331 int sd_netlink_message_is_error(sd_netlink_message *m) {
1332 assert_return(m, 0);
1333 assert_return(m->hdr, 0);
1334
1335 return m->hdr->nlmsg_type == NLMSG_ERROR;
1336 }
1337
1338 int sd_netlink_message_get_errno(sd_netlink_message *m) {
1339 struct nlmsgerr *err;
1340
1341 assert_return(m, -EINVAL);
1342 assert_return(m->hdr, -EINVAL);
1343
1344 if (!sd_netlink_message_is_error(m))
1345 return 0;
1346
1347 err = NLMSG_DATA(m->hdr);
1348
1349 return err->error;
1350 }
1351
1352 static int netlink_message_parse_error(sd_netlink_message *m) {
1353 struct nlmsgerr *err = NLMSG_DATA(m->hdr);
1354 size_t hlen = sizeof(struct nlmsgerr);
1355
1356 /* no TLVs, nothing to do here */
1357 if (!(m->hdr->nlmsg_flags & NLM_F_ACK_TLVS))
1358 return 0;
1359
1360 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1361 if (!(m->hdr->nlmsg_flags & NLM_F_CAPPED))
1362 hlen += err->msg.nlmsg_len - sizeof(struct nlmsghdr);
1363
1364 if (m->hdr->nlmsg_len <= NLMSG_SPACE(hlen))
1365 return 0;
1366
1367 return netlink_container_parse(m,
1368 &m->containers[m->n_containers],
1369 (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + hlen),
1370 NLMSG_PAYLOAD(m->hdr, hlen));
1371 }
1372
1373 int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
1374 size_t size;
1375 int r;
1376
1377 assert_return(m, -EINVAL);
1378 assert_return(nl, -EINVAL);
1379
1380 /* don't allow appending to message once parsed */
1381 message_seal(m);
1382
1383 for (unsigned i = 1; i <= m->n_containers; i++)
1384 m->containers[i].attributes = mfree(m->containers[i].attributes);
1385
1386 m->n_containers = 0;
1387
1388 if (m->containers[0].attributes)
1389 /* top-level attributes have already been parsed */
1390 return 0;
1391
1392 assert(m->hdr);
1393
1394 r = netlink_get_policy_set_and_header_size(nl, m->hdr->nlmsg_type,
1395 &m->containers[0].policy_set, &size);
1396 if (r < 0)
1397 return r;
1398
1399 if (sd_netlink_message_is_error(m))
1400 return netlink_message_parse_error(m);
1401
1402 return netlink_container_parse(m,
1403 &m->containers[0],
1404 (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1405 NLMSG_PAYLOAD(m->hdr, size));
1406 }
1407
1408 void message_seal(sd_netlink_message *m) {
1409 assert(m);
1410
1411 m->sealed = true;
1412 }
1413
1414 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1415 assert_return(m, NULL);
1416
1417 return m->next;
1418 }