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