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