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