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