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