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