chiark / gitweb /
sd-netlink: introduce api for new NL type NLA_FLAG
[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_flag(sd_netlink_message *m, unsigned short type) {
265         size_t size;
266         int r;
267
268         assert_return(m, -EINVAL);
269         assert_return(!m->sealed, -EPERM);
270
271         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
272         if (r < 0)
273                 return r;
274
275         r = add_rtattr(m, type, NULL, 0);
276         if (r < 0)
277                 return r;
278
279         return 0;
280 }
281
282 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_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_U8);
289         if (r < 0)
290                 return r;
291
292         r = add_rtattr(m, type, &data, sizeof(uint8_t));
293         if (r < 0)
294                 return r;
295
296         return 0;
297 }
298
299
300 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
301         int r;
302
303         assert_return(m, -EINVAL);
304         assert_return(!m->sealed, -EPERM);
305
306         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
307         if (r < 0)
308                 return r;
309
310         r = add_rtattr(m, type, &data, sizeof(uint16_t));
311         if (r < 0)
312                 return r;
313
314         return 0;
315 }
316
317 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
318         int r;
319
320         assert_return(m, -EINVAL);
321         assert_return(!m->sealed, -EPERM);
322
323         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
324         if (r < 0)
325                 return r;
326
327         r = add_rtattr(m, type, &data, sizeof(uint32_t));
328         if (r < 0)
329                 return r;
330
331         return 0;
332 }
333
334 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_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 in_addr));
346         if (r < 0)
347                 return r;
348
349         return 0;
350 }
351
352 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_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_IN_ADDR);
360         if (r < 0)
361                 return r;
362
363         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
364         if (r < 0)
365                 return r;
366
367         return 0;
368 }
369
370 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
371         int r;
372
373         assert_return(m, -EINVAL);
374         assert_return(!m->sealed, -EPERM);
375         assert_return(data, -EINVAL);
376
377         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
378         if (r < 0)
379                 return r;
380
381         r = add_rtattr(m, type, data, ETH_ALEN);
382         if (r < 0)
383                 return r;
384
385         return 0;
386 }
387
388 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
389         int r;
390
391         assert_return(m, -EINVAL);
392         assert_return(!m->sealed, -EPERM);
393         assert_return(info, -EINVAL);
394
395         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
396         if (r < 0)
397                 return r;
398
399         r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
400         if (r < 0)
401                 return r;
402
403         return 0;
404 }
405
406 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
407         size_t size;
408         int r;
409
410         assert_return(m, -EINVAL);
411         assert_return(!m->sealed, -EPERM);
412         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
413
414         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
415         if (r < 0) {
416                 const NLTypeSystemUnion *type_system_union;
417                 int family;
418
419                 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
420                 if (r < 0)
421                         return r;
422
423                 r = sd_rtnl_message_get_family(m, &family);
424                 if (r < 0)
425                         return r;
426
427                 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
428                 if (r < 0)
429                         return r;
430
431                 r = type_system_union_protocol_get_type_system(type_system_union,
432                                                                &m->container_type_system[m->n_containers + 1],
433                                                                family);
434                 if (r < 0)
435                         return r;
436         } else {
437                 r = type_system_get_type_system(m->container_type_system[m->n_containers],
438                                                 &m->container_type_system[m->n_containers + 1],
439                                                 type);
440                 if (r < 0)
441                         return r;
442         }
443
444         r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
445         if (r < 0)
446                 return r;
447
448         m->container_offsets[m->n_containers ++] = r;
449
450         return 0;
451 }
452
453 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
454         const NLTypeSystemUnion *type_system_union;
455         int r;
456
457         assert_return(m, -EINVAL);
458         assert_return(!m->sealed, -EPERM);
459
460         r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
461         if (r < 0)
462                 return r;
463
464         r = type_system_union_get_type_system(type_system_union,
465                                               &m->container_type_system[m->n_containers + 1],
466                                               key);
467         if (r < 0)
468                 return r;
469
470         r = sd_netlink_message_append_string(m, type_system_union->match, key);
471         if (r < 0)
472                 return r;
473
474         /* do we evere need non-null size */
475         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
476         if (r < 0)
477                 return r;
478
479         m->container_offsets[m->n_containers ++] = r;
480
481         return 0;
482 }
483
484
485 int sd_netlink_message_close_container(sd_netlink_message *m) {
486         assert_return(m, -EINVAL);
487         assert_return(!m->sealed, -EPERM);
488         assert_return(m->n_containers > 0, -EINVAL);
489
490         m->container_type_system[m->n_containers] = NULL;
491         m->n_containers --;
492
493         return 0;
494 }
495
496 static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
497         struct rtattr *rta;
498
499         assert_return(m, -EINVAL);
500         assert_return(m->sealed, -EPERM);
501         assert_return(data, -EINVAL);
502         assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
503         assert(m->rta_offset_tb[m->n_containers]);
504         assert(type < m->rta_tb_size[m->n_containers]);
505
506         if(!m->rta_offset_tb[m->n_containers][type])
507                 return -ENODATA;
508
509         rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
510
511         *data = RTA_DATA(rta);
512
513         return RTA_PAYLOAD(rta);
514 }
515
516 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
517         int r;
518         void *attr_data;
519
520         assert_return(m, -EINVAL);
521
522         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
523         if (r < 0)
524                 return r;
525
526         r = netlink_message_read_internal(m, type, &attr_data);
527         if (r < 0)
528                 return r;
529         else if (strnlen(attr_data, r) >= (size_t) r)
530                 return -EIO;
531
532         if (data)
533                 *data = (const char *) attr_data;
534
535         return 0;
536 }
537
538 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
539         int r;
540         void *attr_data;
541
542         assert_return(m, -EINVAL);
543
544         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
545         if (r < 0)
546                 return r;
547
548         r = netlink_message_read_internal(m, type, &attr_data);
549         if (r < 0)
550                 return r;
551         else if ((size_t) r < sizeof(uint8_t))
552                 return -EIO;
553
554         if (data)
555                 *data = *(uint8_t *) attr_data;
556
557         return 0;
558 }
559
560 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
561         int r;
562         void *attr_data;
563
564         assert_return(m, -EINVAL);
565
566         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
567         if (r < 0)
568                 return r;
569
570         r = netlink_message_read_internal(m, type, &attr_data);
571         if (r < 0)
572                 return r;
573         else if ((size_t) r < sizeof(uint16_t))
574                 return -EIO;
575
576         if (data)
577                 *data = *(uint16_t *) attr_data;
578
579         return 0;
580 }
581
582 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
583         int r;
584         void *attr_data;
585
586         assert_return(m, -EINVAL);
587
588         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
589         if (r < 0)
590                 return r;
591
592         r = netlink_message_read_internal(m, type, &attr_data);
593         if (r < 0)
594                 return r;
595         else if ((size_t)r < sizeof(uint32_t))
596                 return -EIO;
597
598         if (data)
599                 *data = *(uint32_t *) attr_data;
600
601         return 0;
602 }
603
604 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
605         int r;
606         void *attr_data;
607
608         assert_return(m, -EINVAL);
609
610         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
611         if (r < 0)
612                 return r;
613
614         r = netlink_message_read_internal(m, type, &attr_data);
615         if (r < 0)
616                 return r;
617         else if ((size_t)r < sizeof(struct ether_addr))
618                 return -EIO;
619
620         if (data)
621                 memcpy(data, attr_data, sizeof(struct ether_addr));
622
623         return 0;
624 }
625
626 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
627         int r;
628         void *attr_data;
629
630         assert_return(m, -EINVAL);
631
632         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
633         if (r < 0)
634                 return r;
635
636         r = netlink_message_read_internal(m, type, &attr_data);
637         if (r < 0)
638                 return r;
639         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
640                 return -EIO;
641
642         if (info)
643                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
644
645         return 0;
646 }
647
648 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
649         int r;
650         void *attr_data;
651
652         assert_return(m, -EINVAL);
653
654         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
655         if (r < 0)
656                 return r;
657
658         r = netlink_message_read_internal(m, type, &attr_data);
659         if (r < 0)
660                 return r;
661         else if ((size_t)r < sizeof(struct in_addr))
662                 return -EIO;
663
664         if (data)
665                 memcpy(data, attr_data, sizeof(struct in_addr));
666
667         return 0;
668 }
669
670 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
671         int r;
672         void *attr_data;
673
674         assert_return(m, -EINVAL);
675
676         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
677         if (r < 0)
678                 return r;
679
680         r = netlink_message_read_internal(m, type, &attr_data);
681         if (r < 0)
682                 return r;
683         else if ((size_t)r < sizeof(struct in6_addr))
684                 return -EIO;
685
686         if (data)
687                 memcpy(data, attr_data, sizeof(struct in6_addr));
688
689         return 0;
690 }
691
692 static int netlink_message_parse(sd_netlink_message *m,
693                        size_t **rta_offset_tb,
694                        unsigned short *rta_tb_size,
695                        int count,
696                        struct rtattr *rta,
697                        unsigned int rt_len) {
698         unsigned short type;
699         size_t *tb;
700
701         tb = new0(size_t, count);
702         if(!tb)
703                 return -ENOMEM;
704
705         *rta_tb_size = count;
706
707         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
708                 type = RTA_TYPE(rta);
709
710                 /* if the kernel is newer than the headers we used
711                    when building, we ignore out-of-range attributes
712                  */
713                 if (type >= count)
714                         continue;
715
716                 if (tb[type])
717                         log_debug("rtnl: message parse - overwriting repeated attribute");
718
719                 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
720         }
721
722         *rta_offset_tb = tb;
723
724         return 0;
725 }
726
727 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
728         const NLType *nl_type;
729         const NLTypeSystem *type_system;
730         void *container;
731         uint16_t type;
732         size_t size;
733         int r;
734
735         assert_return(m, -EINVAL);
736         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
737
738         r = type_system_get_type(m->container_type_system[m->n_containers],
739                                  &nl_type,
740                                  type_id);
741         if (r < 0)
742                 return r;
743
744         type = type_get_type(nl_type);
745
746         if (type == NETLINK_TYPE_NESTED) {
747                 r = type_system_get_type_system(m->container_type_system[m->n_containers],
748                                                 &type_system,
749                                                 type_id);
750                 if (r < 0)
751                         return r;
752         } else if (type == NETLINK_TYPE_UNION) {
753                 const NLTypeSystemUnion *type_system_union;
754
755                 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
756                                                       &type_system_union,
757                                                       type_id);
758                 if (r < 0)
759                         return r;
760
761                 switch (type_system_union->match_type) {
762                 case NL_MATCH_SIBLING:
763                 {
764                         const char *key;
765
766                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
767                         if (r < 0)
768                                 return r;
769
770                         r = type_system_union_get_type_system(type_system_union,
771                                                               &type_system,
772                                                               key);
773                         if (r < 0)
774                                 return r;
775
776                         break;
777                 }
778                 case NL_MATCH_PROTOCOL:
779                 {
780                         int family;
781
782                         r = sd_rtnl_message_get_family(m, &family);
783                         if (r < 0)
784                                 return r;
785
786                         r = type_system_union_protocol_get_type_system(type_system_union,
787                                                                        &type_system,
788                                                                        family);
789                         if (r < 0)
790                                 return r;
791
792                         break;
793                 }
794                 default:
795                         assert_not_reached("sd-netlink: invalid type system union type");
796                 }
797         } else
798                 return -EINVAL;
799
800         r = netlink_message_read_internal(m, type_id, &container);
801         if (r < 0)
802                 return r;
803         else
804                 size = (size_t)r;
805
806         m->n_containers ++;
807
808         r = netlink_message_parse(m,
809                                   &m->rta_offset_tb[m->n_containers],
810                                   &m->rta_tb_size[m->n_containers],
811                                   type_system_get_count(type_system),
812                                   container,
813                                   size);
814         if (r < 0) {
815                 m->n_containers --;
816                 return r;
817         }
818
819         m->container_type_system[m->n_containers] = type_system;
820
821         return 0;
822 }
823
824 int sd_netlink_message_exit_container(sd_netlink_message *m) {
825         assert_return(m, -EINVAL);
826         assert_return(m->sealed, -EINVAL);
827         assert_return(m->n_containers > 0, -EINVAL);
828
829         free(m->rta_offset_tb[m->n_containers]);
830         m->rta_offset_tb[m->n_containers] = NULL;
831         m->container_type_system[m->n_containers] = NULL;
832
833         m->n_containers --;
834
835         return 0;
836 }
837
838 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
839         assert(m);
840         assert(m->hdr);
841
842         return m->hdr->nlmsg_seq;
843 }
844
845 int sd_netlink_message_is_error(sd_netlink_message *m) {
846         assert_return(m, 0);
847         assert_return(m->hdr, 0);
848
849         return m->hdr->nlmsg_type == NLMSG_ERROR;
850 }
851
852 int sd_netlink_message_get_errno(sd_netlink_message *m) {
853         struct nlmsgerr *err;
854
855         assert_return(m, -EINVAL);
856         assert_return(m->hdr, -EINVAL);
857
858         if (!sd_netlink_message_is_error(m))
859                 return 0;
860
861         err = NLMSG_DATA(m->hdr);
862
863         return err->error;
864 }
865
866 int sd_netlink_message_rewind(sd_netlink_message *m) {
867         const NLType *nl_type;
868         uint16_t type;
869         size_t size;
870         unsigned i;
871         int r;
872
873         assert_return(m, -EINVAL);
874
875         /* don't allow appending to message once parsed */
876         if (!m->sealed)
877                 rtnl_message_seal(m);
878
879         for (i = 1; i <= m->n_containers; i++) {
880                 free(m->rta_offset_tb[i]);
881                 m->rta_offset_tb[i] = NULL;
882                 m->rta_tb_size[i] = 0;
883                 m->container_type_system[i] = NULL;
884         }
885
886         m->n_containers = 0;
887
888         if (m->rta_offset_tb[0]) {
889                 /* top-level attributes have already been parsed */
890                 return 0;
891         }
892
893         assert(m->hdr);
894
895         r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
896         if (r < 0)
897                 return r;
898
899         type = type_get_type(nl_type);
900         size = type_get_size(nl_type);
901
902         if (type == NETLINK_TYPE_NESTED) {
903                 const NLTypeSystem *type_system;
904
905                 type_get_type_system(nl_type, &type_system);
906
907                 m->container_type_system[0] = type_system;
908
909                 r = netlink_message_parse(m,
910                                           &m->rta_offset_tb[m->n_containers],
911                                           &m->rta_tb_size[m->n_containers],
912                                           type_system_get_count(type_system),
913                                           (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
914                                           NLMSG_PAYLOAD(m->hdr, size));
915                 if (r < 0)
916                         return r;
917         }
918
919         return 0;
920 }
921
922 void rtnl_message_seal(sd_netlink_message *m) {
923         assert(m);
924         assert(!m->sealed);
925
926         m->sealed = true;
927 }
928
929 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
930         assert_return(m, NULL);
931
932         return m->next;
933 }