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