chiark / gitweb /
1245371f7bab415693a616c0bf964c9c1a8fba4d
[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(type_get_size(nl_type));
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 (type_get_type(nl_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_get_type(type) != data_type)
227                 return -EINVAL;
228
229         return type_get_size(type);
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_id) {
674         const NLType *nl_type;
675         const NLTypeSystem *type_system;
676         void *container;
677         uint16_t type;
678         size_t size;
679         int r;
680
681         assert_return(m, -EINVAL);
682         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
683
684         r = type_system_get_type(m->container_type_system[m->n_containers],
685                                  &nl_type,
686                                  type_id);
687         if (r < 0)
688                 return r;
689
690         type = type_get_type(nl_type);
691
692         if (type == NETLINK_TYPE_NESTED) {
693                 r = type_system_get_type_system(m->container_type_system[m->n_containers],
694                                                 &type_system,
695                                                 type_id);
696                 if (r < 0)
697                         return r;
698         } else if (type == NETLINK_TYPE_UNION) {
699                 const NLTypeSystemUnion *type_system_union;
700
701                 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
702                                                       &type_system_union,
703                                                       type_id);
704                 if (r < 0)
705                         return r;
706
707                 switch (type_system_union->match_type) {
708                 case NL_MATCH_SIBLING:
709                 {
710                         const char *key;
711
712                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
713                         if (r < 0)
714                                 return r;
715
716                         r = type_system_union_get_type_system(type_system_union,
717                                                               &type_system,
718                                                               key);
719                         if (r < 0)
720                                 return r;
721
722                         break;
723                 }
724                 case NL_MATCH_PROTOCOL:
725                 {
726                         int family;
727
728                         r = sd_rtnl_message_get_family(m, &family);
729                         if (r < 0)
730                                 return r;
731
732                         r = type_system_union_protocol_get_type_system(type_system_union,
733                                                                        &type_system,
734                                                                        family);
735                         if (r < 0)
736                                 return r;
737
738                         break;
739                 }
740                 default:
741                         assert_not_reached("sd-netlink: invalid type system union type");
742                 }
743         } else
744                 return -EINVAL;
745
746         r = rtnl_message_read_internal(m, type_id, &container);
747         if (r < 0)
748                 return r;
749         else
750                 size = (size_t)r;
751
752         m->n_containers ++;
753
754         r = rtnl_message_parse(m,
755                                &m->rta_offset_tb[m->n_containers],
756                                &m->rta_tb_size[m->n_containers],
757                                type_system_get_max(type_system),
758                                container,
759                                size);
760         if (r < 0) {
761                 m->n_containers --;
762                 return r;
763         }
764
765         m->container_type_system[m->n_containers] = type_system;
766
767         return 0;
768 }
769
770 int sd_netlink_message_exit_container(sd_netlink_message *m) {
771         assert_return(m, -EINVAL);
772         assert_return(m->sealed, -EINVAL);
773         assert_return(m->n_containers > 0, -EINVAL);
774
775         free(m->rta_offset_tb[m->n_containers]);
776         m->rta_offset_tb[m->n_containers] = NULL;
777         m->container_type_system[m->n_containers] = NULL;
778
779         m->n_containers --;
780
781         return 0;
782 }
783
784 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
785         assert(m);
786         assert(m->hdr);
787
788         return m->hdr->nlmsg_seq;
789 }
790
791 int sd_netlink_message_is_error(sd_netlink_message *m) {
792         assert_return(m, 0);
793         assert_return(m->hdr, 0);
794
795         return m->hdr->nlmsg_type == NLMSG_ERROR;
796 }
797
798 int sd_netlink_message_get_errno(sd_netlink_message *m) {
799         struct nlmsgerr *err;
800
801         assert_return(m, -EINVAL);
802         assert_return(m->hdr, -EINVAL);
803
804         if (!sd_netlink_message_is_error(m))
805                 return 0;
806
807         err = NLMSG_DATA(m->hdr);
808
809         return err->error;
810 }
811
812 int rtnl_message_parse(sd_netlink_message *m,
813                        size_t **rta_offset_tb,
814                        unsigned short *rta_tb_size,
815                        int max,
816                        struct rtattr *rta,
817                        unsigned int rt_len) {
818         unsigned short type;
819         size_t *tb;
820
821         tb = new0(size_t, max + 1);
822         if(!tb)
823                 return -ENOMEM;
824
825         *rta_tb_size = max + 1;
826
827         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
828                 type = RTA_TYPE(rta);
829
830                 /* if the kernel is newer than the headers we used
831                    when building, we ignore out-of-range attributes
832                  */
833                 if (type > max)
834                         continue;
835
836                 if (tb[type])
837                         log_debug("rtnl: message parse - overwriting repeated attribute");
838
839                 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
840         }
841
842         *rta_offset_tb = tb;
843
844         return 0;
845 }
846
847 int sd_netlink_message_rewind(sd_netlink_message *m) {
848         const NLType *nl_type;
849         uint16_t type;
850         size_t size;
851         unsigned i;
852         int r;
853
854         assert_return(m, -EINVAL);
855
856         /* don't allow appending to message once parsed */
857         if (!m->sealed)
858                 rtnl_message_seal(m);
859
860         for (i = 1; i <= m->n_containers; i++) {
861                 free(m->rta_offset_tb[i]);
862                 m->rta_offset_tb[i] = NULL;
863                 m->rta_tb_size[i] = 0;
864                 m->container_type_system[i] = NULL;
865         }
866
867         m->n_containers = 0;
868
869         if (m->rta_offset_tb[0]) {
870                 /* top-level attributes have already been parsed */
871                 return 0;
872         }
873
874         assert(m->hdr);
875
876         r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
877         if (r < 0)
878                 return r;
879
880         type = type_get_type(nl_type);
881         size = type_get_size(nl_type);
882
883         if (type == NETLINK_TYPE_NESTED) {
884                 const NLTypeSystem *type_system;
885
886                 type_get_type_system(nl_type, &type_system);
887
888                 m->container_type_system[0] = type_system;
889
890                 r = rtnl_message_parse(m,
891                                        &m->rta_offset_tb[m->n_containers],
892                                        &m->rta_tb_size[m->n_containers],
893                                        type_system_get_max(type_system),
894                                        (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
895                                        NLMSG_PAYLOAD(m->hdr, size));
896                 if (r < 0)
897                         return r;
898         }
899
900         return 0;
901 }
902
903 void rtnl_message_seal(sd_netlink_message *m) {
904         assert(m);
905         assert(!m->sealed);
906
907         m->sealed = true;
908 }
909
910 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
911         assert_return(m, NULL);
912
913         return m->next;
914 }