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