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