chiark / gitweb /
3f8bf018268d29c9c58538a855544fd9afc7ab27
[elogind.git] / src / libsystemd / sd-netlink / netlink-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/in.h>
23 #include <stdbool.h>
24 #include <unistd.h>
25
26 #include "util.h"
27 #include "socket-util.h"
28 #include "formats-util.h"
29 #include "refcnt.h"
30 #include "missing.h"
31
32 #include "sd-netlink.h"
33 #include "netlink-util.h"
34 #include "netlink-internal.h"
35 #include "netlink-types.h"
36
37 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
38 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
39
40 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
41
42 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
43         sd_netlink_message *m;
44
45         assert_return(ret, -EINVAL);
46
47         /* Note that 'rtnl' is currently unused, if we start using it internally
48            we must take care to avoid problems due to mutual references between
49            buses and their queued messages. See sd-bus.
50          */
51
52         m = new0(sd_netlink_message, 1);
53         if (!m)
54                 return -ENOMEM;
55
56         m->n_ref = REFCNT_INIT;
57
58         m->sealed = false;
59
60         *ret = m;
61
62         return 0;
63 }
64
65 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
66         _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
67         const NLType *nl_type;
68         size_t size;
69         int r;
70
71         r = type_system_get_type(&type_system_root, &nl_type, type);
72         if (r < 0)
73                 return r;
74
75         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, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
219         const NLType *type;
220         int r;
221
222         assert(m);
223
224         r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
225         if (r < 0)
226                 return r;
227
228         if (type_get_type(type) != data_type)
229                 return -EINVAL;
230
231         if (out_size)
232                 *out_size = type_get_size(type);
233         return 0;
234 }
235
236 int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
237         size_t length, size;
238         int r;
239
240         assert_return(m, -EINVAL);
241         assert_return(!m->sealed, -EPERM);
242         assert_return(data, -EINVAL);
243
244         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
245         if (r < 0)
246                 return r;
247
248         if (size) {
249                 length = strnlen(data, size+1);
250                 if (length > size)
251                         return -EINVAL;
252         } else
253                 length = strlen(data);
254
255         r = add_rtattr(m, type, data, length + 1);
256         if (r < 0)
257                 return r;
258
259         return 0;
260 }
261
262 int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
263         int r;
264
265         assert_return(m, -EINVAL);
266         assert_return(!m->sealed, -EPERM);
267
268         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
269         if (r < 0)
270                 return r;
271
272         r = add_rtattr(m, type, &data, sizeof(uint8_t));
273         if (r < 0)
274                 return r;
275
276         return 0;
277 }
278
279
280 int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
281         int r;
282
283         assert_return(m, -EINVAL);
284         assert_return(!m->sealed, -EPERM);
285
286         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
287         if (r < 0)
288                 return r;
289
290         r = add_rtattr(m, type, &data, sizeof(uint16_t));
291         if (r < 0)
292                 return r;
293
294         return 0;
295 }
296
297 int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
298         int r;
299
300         assert_return(m, -EINVAL);
301         assert_return(!m->sealed, -EPERM);
302
303         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
304         if (r < 0)
305                 return r;
306
307         r = add_rtattr(m, type, &data, sizeof(uint32_t));
308         if (r < 0)
309                 return r;
310
311         return 0;
312 }
313
314 int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
315         int r;
316
317         assert_return(m, -EINVAL);
318         assert_return(!m->sealed, -EPERM);
319         assert_return(data, -EINVAL);
320
321         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
322         if (r < 0)
323                 return r;
324
325         r = add_rtattr(m, type, data, sizeof(struct in_addr));
326         if (r < 0)
327                 return r;
328
329         return 0;
330 }
331
332 int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
333         int r;
334
335         assert_return(m, -EINVAL);
336         assert_return(!m->sealed, -EPERM);
337         assert_return(data, -EINVAL);
338
339         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
340         if (r < 0)
341                 return r;
342
343         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
344         if (r < 0)
345                 return r;
346
347         return 0;
348 }
349
350 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
351         int r;
352
353         assert_return(m, -EINVAL);
354         assert_return(!m->sealed, -EPERM);
355         assert_return(data, -EINVAL);
356
357         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
358         if (r < 0)
359                 return r;
360
361         r = add_rtattr(m, type, data, ETH_ALEN);
362         if (r < 0)
363                 return r;
364
365         return 0;
366 }
367
368 int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
369         int r;
370
371         assert_return(m, -EINVAL);
372         assert_return(!m->sealed, -EPERM);
373         assert_return(info, -EINVAL);
374
375         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
376         if (r < 0)
377                 return r;
378
379         r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
380         if (r < 0)
381                 return r;
382
383         return 0;
384 }
385
386 int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
387         size_t size;
388         int r;
389
390         assert_return(m, -EINVAL);
391         assert_return(!m->sealed, -EPERM);
392         assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
393
394         r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
395         if (r < 0) {
396                 const NLTypeSystemUnion *type_system_union;
397                 int family;
398
399                 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
400                 if (r < 0)
401                         return r;
402
403                 r = sd_rtnl_message_get_family(m, &family);
404                 if (r < 0)
405                         return r;
406
407                 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
408                 if (r < 0)
409                         return r;
410
411                 r = type_system_union_protocol_get_type_system(type_system_union,
412                                                                &m->container_type_system[m->n_containers + 1],
413                                                                family);
414                 if (r < 0)
415                         return r;
416         } else {
417                 r = type_system_get_type_system(m->container_type_system[m->n_containers],
418                                                 &m->container_type_system[m->n_containers + 1],
419                                                 type);
420                 if (r < 0)
421                         return r;
422         }
423
424         r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
425         if (r < 0)
426                 return r;
427
428         m->container_offsets[m->n_containers ++] = r;
429
430         return 0;
431 }
432
433 int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
434         const NLTypeSystemUnion *type_system_union;
435         int r;
436
437         assert_return(m, -EINVAL);
438         assert_return(!m->sealed, -EPERM);
439
440         r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
441         if (r < 0)
442                 return r;
443
444         r = type_system_union_get_type_system(type_system_union,
445                                               &m->container_type_system[m->n_containers + 1],
446                                               key);
447         if (r < 0)
448                 return r;
449
450         r = sd_netlink_message_append_string(m, type_system_union->match, key);
451         if (r < 0)
452                 return r;
453
454         /* do we evere need non-null size */
455         r = add_rtattr(m, type, NULL, 0);
456         if (r < 0)
457                 return r;
458
459         m->container_offsets[m->n_containers ++] = r;
460
461         return 0;
462 }
463
464
465 int sd_netlink_message_close_container(sd_netlink_message *m) {
466         assert_return(m, -EINVAL);
467         assert_return(!m->sealed, -EPERM);
468         assert_return(m->n_containers > 0, -EINVAL);
469
470         m->container_type_system[m->n_containers] = NULL;
471         m->n_containers --;
472
473         return 0;
474 }
475
476 int rtnl_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
477         struct rtattr *rta;
478
479         assert_return(m, -EINVAL);
480         assert_return(m->sealed, -EPERM);
481         assert_return(data, -EINVAL);
482         assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
483         assert(m->rta_offset_tb[m->n_containers]);
484         assert(type < m->rta_tb_size[m->n_containers]);
485
486         if(!m->rta_offset_tb[m->n_containers][type])
487                 return -ENODATA;
488
489         rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
490
491         *data = RTA_DATA(rta);
492
493         return RTA_PAYLOAD(rta);
494 }
495
496 int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
497         int r;
498         void *attr_data;
499
500         assert_return(m, -EINVAL);
501
502         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
503         if (r < 0)
504                 return r;
505
506         r = rtnl_message_read_internal(m, type, &attr_data);
507         if (r < 0)
508                 return r;
509         else if (strnlen(attr_data, r) >= (size_t) r)
510                 return -EIO;
511
512         if (data)
513                 *data = (const char *) attr_data;
514
515         return 0;
516 }
517
518 int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
519         int r;
520         void *attr_data;
521
522         assert_return(m, -EINVAL);
523
524         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
525         if (r < 0)
526                 return r;
527
528         r = rtnl_message_read_internal(m, type, &attr_data);
529         if (r < 0)
530                 return r;
531         else if ((size_t) r < sizeof(uint8_t))
532                 return -EIO;
533
534         if (data)
535                 *data = *(uint8_t *) attr_data;
536
537         return 0;
538 }
539
540 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
541         int r;
542         void *attr_data;
543
544         assert_return(m, -EINVAL);
545
546         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
547         if (r < 0)
548                 return r;
549
550         r = rtnl_message_read_internal(m, type, &attr_data);
551         if (r < 0)
552                 return r;
553         else if ((size_t) r < sizeof(uint16_t))
554                 return -EIO;
555
556         if (data)
557                 *data = *(uint16_t *) attr_data;
558
559         return 0;
560 }
561
562 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
563         int r;
564         void *attr_data;
565
566         assert_return(m, -EINVAL);
567
568         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
569         if (r < 0)
570                 return r;
571
572         r = rtnl_message_read_internal(m, type, &attr_data);
573         if (r < 0)
574                 return r;
575         else if ((size_t)r < sizeof(uint32_t))
576                 return -EIO;
577
578         if (data)
579                 *data = *(uint32_t *) attr_data;
580
581         return 0;
582 }
583
584 int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
585         int r;
586         void *attr_data;
587
588         assert_return(m, -EINVAL);
589
590         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
591         if (r < 0)
592                 return r;
593
594         r = rtnl_message_read_internal(m, type, &attr_data);
595         if (r < 0)
596                 return r;
597         else if ((size_t)r < sizeof(struct ether_addr))
598                 return -EIO;
599
600         if (data)
601                 memcpy(data, attr_data, sizeof(struct ether_addr));
602
603         return 0;
604 }
605
606 int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
607         int r;
608         void *attr_data;
609
610         assert_return(m, -EINVAL);
611
612         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
613         if (r < 0)
614                 return r;
615
616         r = rtnl_message_read_internal(m, type, &attr_data);
617         if (r < 0)
618                 return r;
619         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
620                 return -EIO;
621
622         if (info)
623                 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
624
625         return 0;
626 }
627
628 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
629         int r;
630         void *attr_data;
631
632         assert_return(m, -EINVAL);
633
634         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
635         if (r < 0)
636                 return r;
637
638         r = rtnl_message_read_internal(m, type, &attr_data);
639         if (r < 0)
640                 return r;
641         else if ((size_t)r < sizeof(struct in_addr))
642                 return -EIO;
643
644         if (data)
645                 memcpy(data, attr_data, sizeof(struct in_addr));
646
647         return 0;
648 }
649
650 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
651         int r;
652         void *attr_data;
653
654         assert_return(m, -EINVAL);
655
656         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
657         if (r < 0)
658                 return r;
659
660         r = rtnl_message_read_internal(m, type, &attr_data);
661         if (r < 0)
662                 return r;
663         else if ((size_t)r < sizeof(struct in6_addr))
664                 return -EIO;
665
666         if (data)
667                 memcpy(data, attr_data, sizeof(struct in6_addr));
668
669         return 0;
670 }
671
672 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
673         const NLType *nl_type;
674         const NLTypeSystem *type_system;
675         void *container;
676         uint16_t type;
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_id);
686         if (r < 0)
687                 return r;
688
689         type = type_get_type(nl_type);
690
691         if (type == NETLINK_TYPE_NESTED) {
692                 r = type_system_get_type_system(m->container_type_system[m->n_containers],
693                                                 &type_system,
694                                                 type_id);
695                 if (r < 0)
696                         return r;
697         } else if (type == NETLINK_TYPE_UNION) {
698                 const NLTypeSystemUnion *type_system_union;
699
700                 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
701                                                       &type_system_union,
702                                                       type_id);
703                 if (r < 0)
704                         return r;
705
706                 switch (type_system_union->match_type) {
707                 case NL_MATCH_SIBLING:
708                 {
709                         const char *key;
710
711                         r = sd_netlink_message_read_string(m, type_system_union->match, &key);
712                         if (r < 0)
713                                 return r;
714
715                         r = type_system_union_get_type_system(type_system_union,
716                                                               &type_system,
717                                                               key);
718                         if (r < 0)
719                                 return r;
720
721                         break;
722                 }
723                 case NL_MATCH_PROTOCOL:
724                 {
725                         int family;
726
727                         r = sd_rtnl_message_get_family(m, &family);
728                         if (r < 0)
729                                 return r;
730
731                         r = type_system_union_protocol_get_type_system(type_system_union,
732                                                                        &type_system,
733                                                                        family);
734                         if (r < 0)
735                                 return r;
736
737                         break;
738                 }
739                 default:
740                         assert_not_reached("sd-netlink: invalid type system union type");
741                 }
742         } else
743                 return -EINVAL;
744
745         r = rtnl_message_read_internal(m, type_id, &container);
746         if (r < 0)
747                 return r;
748         else
749                 size = (size_t)r;
750
751         m->n_containers ++;
752
753         r = rtnl_message_parse(m,
754                                &m->rta_offset_tb[m->n_containers],
755                                &m->rta_tb_size[m->n_containers],
756                                type_system_get_count(type_system),
757                                container,
758                                size);
759         if (r < 0) {
760                 m->n_containers --;
761                 return r;
762         }
763
764         m->container_type_system[m->n_containers] = type_system;
765
766         return 0;
767 }
768
769 int sd_netlink_message_exit_container(sd_netlink_message *m) {
770         assert_return(m, -EINVAL);
771         assert_return(m->sealed, -EINVAL);
772         assert_return(m->n_containers > 0, -EINVAL);
773
774         free(m->rta_offset_tb[m->n_containers]);
775         m->rta_offset_tb[m->n_containers] = NULL;
776         m->container_type_system[m->n_containers] = NULL;
777
778         m->n_containers --;
779
780         return 0;
781 }
782
783 uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
784         assert(m);
785         assert(m->hdr);
786
787         return m->hdr->nlmsg_seq;
788 }
789
790 int sd_netlink_message_is_error(sd_netlink_message *m) {
791         assert_return(m, 0);
792         assert_return(m->hdr, 0);
793
794         return m->hdr->nlmsg_type == NLMSG_ERROR;
795 }
796
797 int sd_netlink_message_get_errno(sd_netlink_message *m) {
798         struct nlmsgerr *err;
799
800         assert_return(m, -EINVAL);
801         assert_return(m->hdr, -EINVAL);
802
803         if (!sd_netlink_message_is_error(m))
804                 return 0;
805
806         err = NLMSG_DATA(m->hdr);
807
808         return err->error;
809 }
810
811 int rtnl_message_parse(sd_netlink_message *m,
812                        size_t **rta_offset_tb,
813                        unsigned short *rta_tb_size,
814                        int count,
815                        struct rtattr *rta,
816                        unsigned int rt_len) {
817         unsigned short type;
818         size_t *tb;
819
820         tb = new0(size_t, count);
821         if(!tb)
822                 return -ENOMEM;
823
824         *rta_tb_size = count;
825
826         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
827                 type = RTA_TYPE(rta);
828
829                 /* if the kernel is newer than the headers we used
830                    when building, we ignore out-of-range attributes
831                  */
832                 if (type >= count)
833                         continue;
834
835                 if (tb[type])
836                         log_debug("rtnl: message parse - overwriting repeated attribute");
837
838                 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
839         }
840
841         *rta_offset_tb = tb;
842
843         return 0;
844 }
845
846 int sd_netlink_message_rewind(sd_netlink_message *m) {
847         const NLType *nl_type;
848         uint16_t type;
849         size_t size;
850         unsigned i;
851         int r;
852
853         assert_return(m, -EINVAL);
854
855         /* don't allow appending to message once parsed */
856         if (!m->sealed)
857                 rtnl_message_seal(m);
858
859         for (i = 1; i <= m->n_containers; i++) {
860                 free(m->rta_offset_tb[i]);
861                 m->rta_offset_tb[i] = NULL;
862                 m->rta_tb_size[i] = 0;
863                 m->container_type_system[i] = NULL;
864         }
865
866         m->n_containers = 0;
867
868         if (m->rta_offset_tb[0]) {
869                 /* top-level attributes have already been parsed */
870                 return 0;
871         }
872
873         assert(m->hdr);
874
875         r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
876         if (r < 0)
877                 return r;
878
879         type = type_get_type(nl_type);
880         size = type_get_size(nl_type);
881
882         if (type == NETLINK_TYPE_NESTED) {
883                 const NLTypeSystem *type_system;
884
885                 type_get_type_system(nl_type, &type_system);
886
887                 m->container_type_system[0] = type_system;
888
889                 r = rtnl_message_parse(m,
890                                        &m->rta_offset_tb[m->n_containers],
891                                        &m->rta_tb_size[m->n_containers],
892                                        type_system_get_count(type_system),
893                                        (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
894                                        NLMSG_PAYLOAD(m->hdr, size));
895                 if (r < 0)
896                         return r;
897         }
898
899         return 0;
900 }
901
902 void rtnl_message_seal(sd_netlink_message *m) {
903         assert(m);
904         assert(!m->sealed);
905
906         m->sealed = true;
907 }
908
909 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
910         assert_return(m, NULL);
911
912         return m->next;
913 }