chiark / gitweb /
13573dcea8ac50e2436ce69adfd80fffdbf664f9
[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)->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
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->containers[0].type_system);
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->containers[i].attributes);
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->containers[m->n_containers].type_system, &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->containers[m->n_containers].type_system, &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->containers[m->n_containers + 1].type_system,
415                                                                family);
416                 if (r < 0)
417                         return r;
418         } else {
419                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
420                                                 &m->containers[m->n_containers + 1].type_system,
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->containers[m->n_containers ++].offset = 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->containers[m->n_containers].type_system, &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->containers[m->n_containers + 1].type_system,
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->containers[m->n_containers ++].offset = 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->containers[m->n_containers].type_system = 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 netlink_attribute *attribute;
480         struct rtattr *rta;
481
482         assert_return(m, -EINVAL);
483         assert_return(m->sealed, -EPERM);
484         assert_return(data, -EINVAL);
485         assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
486         assert(m->containers[m->n_containers].attributes);
487         assert(type < m->containers[m->n_containers].n_attributes);
488
489         attribute = &m->containers[m->n_containers].attributes[type];
490
491         if(!attribute->offset)
492                 return -ENODATA;
493
494         rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
495
496         *data = RTA_DATA(rta);
497
498         return RTA_PAYLOAD(rta);
499 }
500
501 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
502         int r;
503         void *attr_data;
504
505         assert_return(m, -EINVAL);
506
507         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
508         if (r < 0)
509                 return r;
510
511         r = netlink_message_read_internal(m, type, &attr_data);
512         if (r < 0)
513                 return r;
514         else if (strnlen(attr_data, r) >= (size_t) r)
515                 return -EIO;
516
517         if (data)
518                 *data = (const char *) attr_data;
519
520         return 0;
521 }
522
523 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
524         int r;
525         void *attr_data;
526
527         assert_return(m, -EINVAL);
528
529         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
530         if (r < 0)
531                 return r;
532
533         r = netlink_message_read_internal(m, type, &attr_data);
534         if (r < 0)
535                 return r;
536         else if ((size_t) r < sizeof(uint8_t))
537                 return -EIO;
538
539         if (data)
540                 *data = *(uint8_t *) attr_data;
541
542         return 0;
543 }
544
545 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
546         int r;
547         void *attr_data;
548
549         assert_return(m, -EINVAL);
550
551         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
552         if (r < 0)
553                 return r;
554
555         r = netlink_message_read_internal(m, type, &attr_data);
556         if (r < 0)
557                 return r;
558         else if ((size_t) r < sizeof(uint16_t))
559                 return -EIO;
560
561         if (data)
562                 *data = *(uint16_t *) attr_data;
563
564         return 0;
565 }
566
567 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
568         int r;
569         void *attr_data;
570
571         assert_return(m, -EINVAL);
572
573         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
574         if (r < 0)
575                 return r;
576
577         r = netlink_message_read_internal(m, type, &attr_data);
578         if (r < 0)
579                 return r;
580         else if ((size_t)r < sizeof(uint32_t))
581                 return -EIO;
582
583         if (data)
584                 *data = *(uint32_t *) attr_data;
585
586         return 0;
587 }
588
589 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
590         int r;
591         void *attr_data;
592
593         assert_return(m, -EINVAL);
594
595         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
596         if (r < 0)
597                 return r;
598
599         r = netlink_message_read_internal(m, type, &attr_data);
600         if (r < 0)
601                 return r;
602         else if ((size_t)r < sizeof(struct ether_addr))
603                 return -EIO;
604
605         if (data)
606                 memcpy(data, attr_data, sizeof(struct ether_addr));
607
608         return 0;
609 }
610
611 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
612         int r;
613         void *attr_data;
614
615         assert_return(m, -EINVAL);
616
617         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
618         if (r < 0)
619                 return r;
620
621         r = netlink_message_read_internal(m, type, &attr_data);
622         if (r < 0)
623                 return r;
624         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
625                 return -EIO;
626
627         if (info)
628                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
629
630         return 0;
631 }
632
633 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
634         int r;
635         void *attr_data;
636
637         assert_return(m, -EINVAL);
638
639         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
640         if (r < 0)
641                 return r;
642
643         r = netlink_message_read_internal(m, type, &attr_data);
644         if (r < 0)
645                 return r;
646         else if ((size_t)r < sizeof(struct in_addr))
647                 return -EIO;
648
649         if (data)
650                 memcpy(data, attr_data, sizeof(struct in_addr));
651
652         return 0;
653 }
654
655 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
656         int r;
657         void *attr_data;
658
659         assert_return(m, -EINVAL);
660
661         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
662         if (r < 0)
663                 return r;
664
665         r = netlink_message_read_internal(m, type, &attr_data);
666         if (r < 0)
667                 return r;
668         else if ((size_t)r < sizeof(struct in6_addr))
669                 return -EIO;
670
671         if (data)
672                 memcpy(data, attr_data, sizeof(struct in6_addr));
673
674         return 0;
675 }
676
677 static int netlink_container_parse(sd_netlink_message *m,
678                                    struct netlink_container *container,
679                                    int count,
680                                    struct rtattr *rta,
681                                    unsigned int rt_len) {
682         _cleanup_free_ struct netlink_attribute *attributes = NULL;
683
684         attributes = new0(struct netlink_attribute, count);
685         if(!attributes)
686                 return -ENOMEM;
687
688         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
689                 unsigned short type;
690
691                 type = RTA_TYPE(rta);
692
693                 /* if the kernel is newer than the headers we used
694                    when building, we ignore out-of-range attributes */
695                 if (type >= count)
696                         continue;
697
698                 if (attributes[type].offset)
699                         log_debug("rtnl: message parse - overwriting repeated attribute");
700
701                 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
702         }
703
704         container->attributes = attributes;
705         attributes = NULL;
706         container->n_attributes = count;
707
708         return 0;
709 }
710
711 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
712         const NLType *nl_type;
713         const NLTypeSystem *type_system;
714         void *container;
715         uint16_t type;
716         size_t size;
717         int r;
718
719         assert_return(m, -EINVAL);
720         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
721
722         r = type_system_get_type(m->containers[m->n_containers].type_system,
723                                  &nl_type,
724                                  type_id);
725         if (r < 0)
726                 return r;
727
728         type = type_get_type(nl_type);
729
730         if (type == NETLINK_TYPE_NESTED) {
731                 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
732                                                 &type_system,
733                                                 type_id);
734                 if (r < 0)
735                         return r;
736         } else if (type == NETLINK_TYPE_UNION) {
737                 const NLTypeSystemUnion *type_system_union;
738
739                 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
740                                                       &type_system_union,
741                                                       type_id);
742                 if (r < 0)
743                         return r;
744
745                 switch (type_system_union->match_type) {
746                 case NL_MATCH_SIBLING:
747                 {
748                         const char *key;
749
750                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
751                         if (r < 0)
752                                 return r;
753
754                         r = type_system_union_get_type_system(type_system_union,
755                                                               &type_system,
756                                                               key);
757                         if (r < 0)
758                                 return r;
759
760                         break;
761                 }
762                 case NL_MATCH_PROTOCOL:
763                 {
764                         int family;
765
766                         r = sd_rtnl_message_get_family(m, &family);
767                         if (r < 0)
768                                 return r;
769
770                         r = type_system_union_protocol_get_type_system(type_system_union,
771                                                                        &type_system,
772                                                                        family);
773                         if (r < 0)
774                                 return r;
775
776                         break;
777                 }
778                 default:
779                         assert_not_reached("sd-netlink: invalid type system union type");
780                 }
781         } else
782                 return -EINVAL;
783
784         r = netlink_message_read_internal(m, type_id, &container);
785         if (r < 0)
786                 return r;
787         else
788                 size = (size_t)r;
789
790         m->n_containers ++;
791
792         r = netlink_container_parse(m,
793                                     &m->containers[m->n_containers],
794                                     type_system_get_count(type_system),
795                                     container,
796                                     size);
797         if (r < 0) {
798                 m->n_containers --;
799                 return r;
800         }
801
802         m->containers[m->n_containers].type_system = type_system;
803
804         return 0;
805 }
806
807 int sd_netlink_message_exit_container(sd_netlink_message *m) {
808         assert_return(m, -EINVAL);
809         assert_return(m->sealed, -EINVAL);
810         assert_return(m->n_containers > 0, -EINVAL);
811
812         free(m->containers[m->n_containers].attributes);
813         m->containers[m->n_containers].attributes = NULL;
814         m->containers[m->n_containers].type_system = NULL;
815
816         m->n_containers --;
817
818         return 0;
819 }
820
821 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
822         assert(m);
823         assert(m->hdr);
824
825         return m->hdr->nlmsg_seq;
826 }
827
828 int sd_netlink_message_is_error(sd_netlink_message *m) {
829         assert_return(m, 0);
830         assert_return(m->hdr, 0);
831
832         return m->hdr->nlmsg_type == NLMSG_ERROR;
833 }
834
835 int sd_netlink_message_get_errno(sd_netlink_message *m) {
836         struct nlmsgerr *err;
837
838         assert_return(m, -EINVAL);
839         assert_return(m->hdr, -EINVAL);
840
841         if (!sd_netlink_message_is_error(m))
842                 return 0;
843
844         err = NLMSG_DATA(m->hdr);
845
846         return err->error;
847 }
848
849 int sd_netlink_message_rewind(sd_netlink_message *m) {
850         const NLType *nl_type;
851         uint16_t type;
852         size_t size;
853         unsigned i;
854         int r;
855
856         assert_return(m, -EINVAL);
857
858         /* don't allow appending to message once parsed */
859         if (!m->sealed)
860                 rtnl_message_seal(m);
861
862         for (i = 1; i <= m->n_containers; i++) {
863                 free(m->containers[i].attributes);
864                 m->containers[i].attributes = NULL;
865         }
866
867         m->n_containers = 0;
868
869         if (m->containers[0].attributes) {
870                 /* top-level attributes have already been parsed */
871                 return 0;
872         }
873
874         assert(m->hdr);
875
876         r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
877         if (r < 0)
878                 return r;
879
880         type = type_get_type(nl_type);
881         size = type_get_size(nl_type);
882
883         if (type == NETLINK_TYPE_NESTED) {
884                 const NLTypeSystem *type_system;
885
886                 type_get_type_system(nl_type, &type_system);
887
888                 m->containers[0].type_system = type_system;
889
890                 r = netlink_container_parse(m,
891                                             &m->containers[m->n_containers],
892                                             type_system_get_count(type_system),
893                                             (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
894                                             NLMSG_PAYLOAD(m->hdr, size));
895                 if (r < 0)
896                         return r;
897         }
898
899         return 0;
900 }
901
902 void rtnl_message_seal(sd_netlink_message *m) {
903         assert(m);
904         assert(!m->sealed);
905
906         m->sealed = true;
907 }
908
909 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
910         assert_return(m, NULL);
911
912         return m->next;
913 }