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