chiark / gitweb /
226329f314d82dab3017b02b8986e056adc6ed6f
[elogind.git] / src / libsystemd / sd-rtnl / rtnl-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 <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27 #include <linux/veth.h>
28
29 #include "util.h"
30 #include "refcnt.h"
31
32 #include "sd-rtnl.h"
33 #include "rtnl-util.h"
34 #include "rtnl-internal.h"
35
36 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
37 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
38 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
39 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
40
41 int message_new(sd_rtnl_message **ret, size_t initial_size) {
42         sd_rtnl_message *m;
43
44         assert_return(ret, -EINVAL);
45         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
46
47         m = new0(sd_rtnl_message, 1);
48         if (!m)
49                 return -ENOMEM;
50
51         m->hdr = malloc0(initial_size);
52         if (!m->hdr) {
53                 free(m);
54                 return -ENOMEM;
55         }
56
57         m->n_ref = REFCNT_INIT;
58
59         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
60         m->sealed = false;
61
62         *ret = m;
63
64         return 0;
65 }
66
67 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
68         struct rtmsg *rtm;
69
70         assert_return(m, -EINVAL);
71         assert_return(m->hdr, -EINVAL);
72         assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
73
74         rtm = NLMSG_DATA(m->hdr);
75
76         if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
77             (rtm->rtm_family == AF_INET6 && prefixlen > 128))
78                 return -ERANGE;
79
80         rtm->rtm_dst_len = prefixlen;
81
82         return 0;
83 }
84
85 int sd_rtnl_message_new_route(uint16_t nlmsg_type, unsigned char rtm_family,
86                               sd_rtnl_message **ret) {
87         struct rtmsg *rtm;
88         int r;
89
90         assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
91         assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
92         assert_return(ret, -EINVAL);
93
94         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
95         if (r < 0)
96                 return r;
97
98         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
99         (*ret)->hdr->nlmsg_type = nlmsg_type;
100         if (nlmsg_type == RTM_NEWROUTE)
101                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
102
103         rtm = NLMSG_DATA((*ret)->hdr);
104
105         UPDATE_RTA(*ret, RTM_RTA(rtm));
106
107         rtm->rtm_family = rtm_family;
108         rtm->rtm_scope = RT_SCOPE_UNIVERSE;
109         rtm->rtm_type = RTN_UNICAST;
110         rtm->rtm_table = RT_TABLE_MAIN;
111         rtm->rtm_protocol = RTPROT_BOOT;
112
113         return 0;
114 }
115
116 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
117         struct ifinfomsg *ifi;
118
119         assert_return(m, -EINVAL);
120         assert_return(m->hdr, -EINVAL);
121         assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
122         assert_return(change, -EINVAL);
123
124         ifi = NLMSG_DATA(m->hdr);
125
126         ifi->ifi_flags = flags;
127         ifi->ifi_change = change;
128
129         return 0;
130 }
131
132 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
133         struct ifinfomsg *ifi;
134
135         assert_return(m, -EINVAL);
136         assert_return(m->hdr, -EINVAL);
137         assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
138
139         ifi = NLMSG_DATA(m->hdr);
140
141         ifi->ifi_type = type;
142
143         return 0;
144 }
145
146 int sd_rtnl_message_new_link(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
147         struct ifinfomsg *ifi;
148         int r;
149
150         assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
151         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
152         assert_return(ret, -EINVAL);
153
154         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
155         if (r < 0)
156                 return r;
157
158         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
159         (*ret)->hdr->nlmsg_type = nlmsg_type;
160         if (nlmsg_type == RTM_NEWLINK)
161                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
162
163         ifi = NLMSG_DATA((*ret)->hdr);
164
165         ifi->ifi_family = AF_UNSPEC;
166         ifi->ifi_index = index;
167
168         UPDATE_RTA(*ret, IFLA_RTA(ifi));
169
170         return 0;
171 }
172
173 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
174         struct ifaddrmsg *ifa;
175
176         assert_return(m, -EINVAL);
177         assert_return(m->hdr, -EINVAL);
178         assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
179
180         ifa = NLMSG_DATA(m->hdr);
181
182         if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
183             (ifa->ifa_family == AF_INET6 && prefixlen > 128))
184                 return -ERANGE;
185
186         ifa->ifa_prefixlen = prefixlen;
187
188         return 0;
189 }
190
191 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
192         struct ifaddrmsg *ifa;
193
194         assert_return(m, -EINVAL);
195         assert_return(m->hdr, -EINVAL);
196         assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
197
198         ifa = NLMSG_DATA(m->hdr);
199
200         ifa->ifa_flags = flags;
201
202         return 0;
203 }
204
205 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
206         struct ifaddrmsg *ifa;
207
208         assert_return(m, -EINVAL);
209         assert_return(m->hdr, -EINVAL);
210         assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
211
212         ifa = NLMSG_DATA(m->hdr);
213
214         ifa->ifa_scope = scope;
215
216         return 0;
217 }
218
219 int sd_rtnl_message_new_addr(uint16_t nlmsg_type, int index, unsigned char family,
220                              sd_rtnl_message **ret) {
221         struct ifaddrmsg *ifa;
222         int r;
223
224         assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
225         assert_return(index > 0, -EINVAL);
226         assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
227         assert_return(ret, -EINVAL);
228
229         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
230         if (r < 0)
231                 return r;
232
233         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
234         (*ret)->hdr->nlmsg_type = nlmsg_type;
235
236         ifa = NLMSG_DATA((*ret)->hdr);
237
238         ifa->ifa_index = index;
239         ifa->ifa_family = family;
240         if (family == AF_INET)
241                 ifa->ifa_prefixlen = 32;
242         else if (family == AF_INET6)
243                 ifa->ifa_prefixlen = 128;
244
245         UPDATE_RTA(*ret, IFA_RTA(ifa));
246
247         return 0;
248 }
249
250 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
251         if (m)
252                 assert_se(REFCNT_INC(m->n_ref) >= 2);
253
254         return m;
255 }
256
257 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
258         if (m && REFCNT_DEC(m->n_ref) <= 0) {
259                 free(m->hdr);
260                 free(m);
261         }
262
263         return NULL;
264 }
265
266 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
267         assert_return(m, -EINVAL);
268         assert_return(type, -EINVAL);
269
270         *type = m->hdr->nlmsg_type;
271
272         return 0;
273 }
274
275 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
276         struct ifinfomsg *ifi;
277
278         assert_return(m, -EINVAL);
279         assert_return(m->hdr, -EINVAL);
280         assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
281         assert_return(ifindex, -EINVAL);
282
283         ifi = NLMSG_DATA(m->hdr);
284
285         *ifindex = ifi->ifi_index;
286
287         return 0;
288 }
289
290 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
291         struct ifinfomsg *ifi;
292
293         assert_return(m, -EINVAL);
294         assert_return(m->hdr, -EINVAL);
295         assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
296         assert_return(flags, -EINVAL);
297
298         ifi = NLMSG_DATA(m->hdr);
299
300         *flags = ifi->ifi_flags;
301
302         return 0;
303 }
304
305 /* If successful the updated message will be correctly aligned, if
306    unsuccessful the old message is untouched. */
307 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
308         uint32_t rta_length, message_length;
309         struct nlmsghdr *new_hdr;
310         struct rtattr *rta;
311         char *padding;
312         unsigned i;
313
314         assert(m);
315         assert(m->hdr);
316         assert(!m->sealed);
317         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
318         assert(!data || data_length > 0);
319         assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
320
321         /* get the size of the new rta attribute (with padding at the end) */
322         rta_length = RTA_LENGTH(data_length);
323
324         /* get the new message size (with padding at the end) */
325         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
326
327         /* realloc to fit the new attribute */
328         new_hdr = realloc(m->hdr, message_length);
329         if (!new_hdr)
330                 return -ENOMEM;
331         m->hdr = new_hdr;
332
333         /* get pointer to the attribute we are about to add */
334         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
335
336         /* if we are inside containers, extend them */
337         for (i = 0; i < m->n_containers; i++)
338                 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
339
340         /* fill in the attribute */
341         rta->rta_type = type;
342         rta->rta_len = rta_length;
343         if (!data) {
344                 /* this is the start of a new container */
345                 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
346         } else {
347                 /* we don't deal with the case where the user lies about the type
348                  * and gives us too little data (so don't do that)
349                 */
350                 padding = mempcpy(RTA_DATA(rta), data, data_length);
351                 /* make sure also the padding at the end of the message is initialized */
352                 memzero(padding,
353                         (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
354         }
355
356         /* update message size */
357         m->hdr->nlmsg_len = message_length;
358
359         return 0;
360 }
361
362 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
363         uint16_t rtm_type;
364         int r;
365
366         assert_return(m, -EINVAL);
367         assert_return(!m->sealed, -EPERM);
368         assert_return(data, -EINVAL);
369
370         r = sd_rtnl_message_get_type(m, &rtm_type);
371         if (r < 0)
372                 return r;
373
374         /* check that the type is correct */
375         switch (rtm_type) {
376                 case RTM_NEWLINK:
377                 case RTM_SETLINK:
378                 case RTM_GETLINK:
379                 case RTM_DELLINK:
380                         if (m->n_containers == 1) {
381                                 if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO ||
382                                     type != IFLA_INFO_KIND)
383                                         return -ENOTSUP;
384                         } else {
385                                 switch (type) {
386                                         case IFLA_IFNAME:
387                                         case IFLA_IFALIAS:
388                                         case IFLA_QDISC:
389                                                 break;
390                                         default:
391                                                 return -ENOTSUP;
392                                 }
393                         }
394                         break;
395                 case RTM_NEWADDR:
396                 case RTM_GETADDR:
397                 case RTM_DELADDR:
398                         if (type != IFA_LABEL)
399                                 return -ENOTSUP;
400                         break;
401                 default:
402                         return -ENOTSUP;
403         }
404
405         r = add_rtattr(m, type, data, strlen(data) + 1);
406         if (r < 0)
407                 return r;
408
409         return 0;
410 }
411
412 int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
413         uint16_t rtm_type;
414         int r;
415
416         assert_return(m, -EINVAL);
417         assert_return(!m->sealed, -EPERM);
418
419         r = sd_rtnl_message_get_type(m, &rtm_type);
420         if (r < 0)
421                 return r;
422
423         switch (rtm_type) {
424                 case RTM_NEWLINK:
425                 case RTM_SETLINK:
426                 case RTM_GETLINK:
427                 case RTM_DELLINK:
428                         switch (type) {
429                                 case IFLA_CARRIER:
430                                 case IFLA_OPERSTATE:
431                                 case IFLA_LINKMODE:
432                                 break;
433                         default:
434                                 return -ENOTSUP;
435                         }
436
437                         break;
438                 default:
439                         return -ENOTSUP;
440         }
441
442         r = add_rtattr(m, type, &data, sizeof(uint8_t));
443         if (r < 0)
444                 return r;
445
446         return 0;
447 }
448
449
450 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
451         uint16_t rtm_type;
452         int r;
453
454         assert_return(m, -EINVAL);
455         assert_return(!m->sealed, -EPERM);
456
457         r = sd_rtnl_message_get_type(m, &rtm_type);
458         if (r < 0)
459                 return r;
460
461         /* check that the type is correct */
462         switch (rtm_type) {
463                 case RTM_NEWLINK:
464                 case RTM_SETLINK:
465                 case RTM_GETLINK:
466                 case RTM_DELLINK:
467                         if (m->n_containers == 2 &&
468                             GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
469                             GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
470                             type == IFLA_VLAN_ID)
471                                 break;
472                         else
473                                 return -ENOTSUP;
474                         break;
475                 default:
476                         return -ENOTSUP;
477         }
478
479         r = add_rtattr(m, type, &data, sizeof(uint16_t));
480         if (r < 0)
481                 return r;
482
483         return 0;
484 }
485
486 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
487         uint16_t rtm_type;
488         int r;
489
490         assert_return(m, -EINVAL);
491         assert_return(!m->sealed, -EPERM);
492
493         r = sd_rtnl_message_get_type(m, &rtm_type);
494         if (r < 0)
495                 return r;
496
497         /* check that the type is correct */
498         switch (rtm_type) {
499                 case RTM_NEWLINK:
500                 case RTM_SETLINK:
501                 case RTM_GETLINK:
502                 case RTM_DELLINK:
503                         switch (type) {
504                                 case IFLA_MASTER:
505                                 case IFLA_MTU:
506                                 case IFLA_LINK:
507                                 case IFLA_GROUP:
508                                 case IFLA_TXQLEN:
509                                 case IFLA_WEIGHT:
510                                 case IFLA_NET_NS_FD:
511                                 case IFLA_NET_NS_PID:
512                                 case IFLA_PROMISCUITY:
513                                 case IFLA_NUM_TX_QUEUES:
514                                 case IFLA_NUM_RX_QUEUES:
515                                         break;
516                                 default:
517                                         return -ENOTSUP;
518                         }
519                         break;
520                 case RTM_NEWROUTE:
521                 case RTM_GETROUTE:
522                 case RTM_DELROUTE:
523                         switch (type) {
524                                 case RTA_TABLE:
525                                 case RTA_PRIORITY:
526                                 case RTA_IIF:
527                                 case RTA_OIF:
528                                 case RTA_MARK:
529                                         break;
530                                 default:
531                                         return -ENOTSUP;
532                         }
533                         break;
534                 default:
535                         return -ENOTSUP;
536         }
537
538         r = add_rtattr(m, type, &data, sizeof(uint32_t));
539         if (r < 0)
540                 return r;
541
542         return 0;
543 }
544
545 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
546         struct ifaddrmsg *ifa;
547         struct rtmsg *rtm;
548         uint16_t rtm_type;
549         int r;
550
551         assert_return(m, -EINVAL);
552         assert_return(!m->sealed, -EPERM);
553         assert_return(data, -EINVAL);
554
555         r = sd_rtnl_message_get_type(m, &rtm_type);
556         if (r < 0)
557                 return r;
558
559         /* check that the type is correct */
560         switch (rtm_type) {
561                 case RTM_NEWADDR:
562                 case RTM_GETADDR:
563                 case RTM_DELADDR:
564                         switch (type) {
565                                 case IFA_ADDRESS:
566                                 case IFA_LOCAL:
567                                 case IFA_BROADCAST:
568                                 case IFA_ANYCAST:
569                                         ifa = NLMSG_DATA(m->hdr);
570
571                                         if (ifa->ifa_family != AF_INET)
572                                                 return -EINVAL;
573
574                                         break;
575                                 default:
576                                         return -ENOTSUP;
577                         }
578                         break;
579                 case RTM_NEWROUTE:
580                 case RTM_GETROUTE:
581                 case RTM_DELROUTE:
582                         switch (type) {
583                                 case RTA_DST:
584                                 case RTA_SRC:
585                                 case RTA_GATEWAY:
586                                         rtm = NLMSG_DATA(m->hdr);
587
588                                         if (rtm->rtm_family != AF_INET)
589                                                 return -EINVAL;
590
591                                         break;
592                                 default:
593                                         return -ENOTSUP;
594                         }
595                         break;
596                 default:
597                         return -ENOTSUP;
598         }
599
600         r = add_rtattr(m, type, data, sizeof(struct in_addr));
601         if (r < 0)
602                 return r;
603
604         return 0;
605 }
606
607 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
608         struct ifaddrmsg *ifa;
609         struct rtmsg *rtm;
610         uint16_t rtm_type;
611         int r;
612
613         assert_return(m, -EINVAL);
614         assert_return(!m->sealed, -EPERM);
615         assert_return(data, -EINVAL);
616
617         r = sd_rtnl_message_get_type(m, &rtm_type);
618         if (r < 0)
619                 return r;
620
621         /* check that the type is correct */
622         switch (rtm_type) {
623                 case RTM_NEWADDR:
624                 case RTM_GETADDR:
625                 case RTM_DELADDR:
626                         switch (type) {
627                                 case IFA_ADDRESS:
628                                 case IFA_LOCAL:
629                                 case IFA_BROADCAST:
630                                 case IFA_ANYCAST:
631                                         ifa = NLMSG_DATA(m->hdr);
632
633                                         if (ifa->ifa_family != AF_INET6)
634                                                 return -EINVAL;
635
636                                         break;
637                                 default:
638                                         return -ENOTSUP;
639                         }
640                         break;
641                 case RTM_NEWROUTE:
642                 case RTM_GETROUTE:
643                 case RTM_DELROUTE:
644                         switch (type) {
645                                 case RTA_DST:
646                                 case RTA_SRC:
647                                 case RTA_GATEWAY:
648                                         rtm = NLMSG_DATA(m->hdr);
649
650                                         if (rtm->rtm_family != AF_INET6)
651                                                 return -EINVAL;
652
653                                         break;
654                                 default:
655                                         return -ENOTSUP;
656                         }
657                 default:
658                         return -ENOTSUP;
659         }
660
661         r = add_rtattr(m, type, data, sizeof(struct in6_addr));
662         if (r < 0)
663                 return r;
664
665         return 0;
666 }
667
668 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
669         uint16_t rtm_type;
670         int r;
671
672         assert_return(m, -EINVAL);
673         assert_return(!m->sealed, -EPERM);
674         assert_return(data, -EINVAL);
675
676         sd_rtnl_message_get_type(m, &rtm_type);
677
678         switch (rtm_type) {
679                 case RTM_NEWLINK:
680                 case RTM_SETLINK:
681                 case RTM_DELLINK:
682                 case RTM_GETLINK:
683                         switch (type) {
684                                 case IFLA_ADDRESS:
685                                 case IFLA_BROADCAST:
686                                         break;
687                                 default:
688                                         return -ENOTSUP;
689                         }
690                         break;
691                 default:
692                         return -ENOTSUP;
693         }
694
695         r = add_rtattr(m, type, data, ETH_ALEN);
696         if (r < 0)
697                 return r;
698
699         return 0;
700 }
701
702 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type, size_t extra) {
703         uint16_t rtm_type;
704
705         assert_return(m, -EINVAL);
706         assert_return(!m->sealed, -EPERM);
707
708         sd_rtnl_message_get_type(m, &rtm_type);
709
710         if (rtnl_message_type_is_link(rtm_type)) {
711
712                 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
713                     (type == IFLA_INFO_DATA && m->n_containers == 1 && GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO) ||
714                     (type == VETH_INFO_PEER && m->n_containers == 2 && GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA))
715                         return add_rtattr(m, type, NULL, extra);
716         }
717
718         return -ENOTSUP;
719 }
720
721 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
722         assert_return(m, -EINVAL);
723         assert_return(!m->sealed, -EPERM);
724         assert_return(m->n_containers > 0, -EINVAL);
725
726         m->n_containers --;
727
728         return 0;
729 }
730
731 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
732         size_t remaining_size;
733         uint16_t rtm_type;
734         int r;
735
736         assert_return(m, -EINVAL);
737         assert_return(m->sealed, -EPERM);
738         assert_return(m->next_rta_offset, -EINVAL);
739         assert_return(type, -EINVAL);
740         assert_return(data, -EINVAL);
741
742         /* only read until the end of the current container */
743         if (m->n_containers)
744                 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
745                                  (m->next_rta_offset -
746                                   m->container_offsets[m->n_containers - 1]);
747         else
748                 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
749
750         if (!RTA_OK(NEXT_RTA(m), remaining_size))
751                 return 0;
752
753         /* if we read a container, enter it and return its type */
754         r = sd_rtnl_message_get_type(m, &rtm_type);
755         if (r < 0)
756                 return r;
757
758         *type = NEXT_RTA(m)->rta_type;
759
760         if (rtnl_message_type_is_link(rtm_type) &&
761             ((m->n_containers == 0 &&
762               NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
763              (m->n_containers == 1 &&
764               GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
765               NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
766                 *data = NULL;
767                 PUSH_CONTAINER(m, NEXT_RTA(m));
768                 UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
769         } else {
770                 *data = RTA_DATA(NEXT_RTA(m));
771                 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
772         }
773
774         return 1;
775 }
776
777 int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
778         assert_return(m, -EINVAL);
779         assert_return(m->sealed, -EINVAL);
780         assert_return(m->n_containers > 0, -EINVAL);
781
782         m->n_containers --;
783
784         return 0;
785 }
786
787 uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
788         assert(m);
789         assert(m->hdr);
790
791         return m->hdr->nlmsg_seq;
792 }
793
794 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
795         struct nlmsgerr *err;
796
797         assert_return(m, -EINVAL);
798         assert_return(m->hdr, -EINVAL);
799
800         if (m->hdr->nlmsg_type != NLMSG_ERROR)
801                 return 0;
802
803         err = NLMSG_DATA(m->hdr);
804
805         return err->error;
806 }
807
808 int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
809         int r;
810
811         assert(m);
812         assert(m->hdr);
813
814         if (m->sealed)
815                 return -EPERM;
816
817         if (nl)
818                 m->hdr->nlmsg_seq = nl->serial++;
819
820         m->sealed = true;
821
822         r = sd_rtnl_message_rewind(m);
823         if (r < 0)
824                 return r;
825
826         return 0;
827 }
828
829 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
830         assert(rtnl);
831         assert(need);
832
833         /* ioctl(rtnl->fd, FIONREAD, &need)
834            Does not appear to work on netlink sockets. libnl uses
835            MSG_PEEK instead. I don't know if that is worth the
836            extra roundtrip.
837
838            For now we simply use the maximum message size the kernel
839            may use (NLMSG_GOODSIZE), and then realloc to the actual
840            size after reading the message (hence avoiding huge memory
841            usage in case many small messages are kept around) */
842         *need = page_size();
843         if (*need > 8192UL)
844                 *need = 8192UL;
845
846         return 0;
847 }
848
849 /* returns the number of bytes sent, or a negative error code */
850 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
851         union {
852                 struct sockaddr sa;
853                 struct sockaddr_nl nl;
854         } addr = {
855                 .nl.nl_family = AF_NETLINK,
856         };
857         ssize_t k;
858
859         assert(nl);
860         assert(m);
861         assert(m->hdr);
862
863         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
864                         0, &addr.sa, sizeof(addr));
865         if (k < 0)
866                 return (errno == EAGAIN) ? 0 : -errno;
867
868         return k;
869 }
870
871 /* On success, the number of bytes received is returned and *ret points to the received message
872  * which has a valid header and the correct size.
873  * If nothing useful was received 0 is returned.
874  * On failure, a negative error code is returned.
875  */
876 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
877         sd_rtnl_message *m;
878         union {
879                 struct sockaddr sa;
880                 struct sockaddr_nl nl;
881         } addr;
882         socklen_t addr_len;
883         int r;
884         ssize_t k;
885         size_t need;
886
887         assert(nl);
888         assert(ret);
889
890         r = message_receive_need(nl, &need);
891         if (r < 0)
892                 return r;
893
894         r = message_new(&m, need);
895         if (r < 0)
896                 return r;
897
898         /* don't allow sealing/appending to received messages */
899         m->sealed = true;
900
901         addr_len = sizeof(addr);
902
903         k = recvfrom(nl->fd, m->hdr, need,
904                         0, &addr.sa, &addr_len);
905         if (k < 0)
906                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
907         else if (k == 0)
908                 k = -ECONNRESET; /* connection was closed by the kernel */
909         else if (addr_len != sizeof(addr.nl) ||
910                         addr.nl.nl_family != AF_NETLINK)
911                 k = -EIO; /* not a netlink message */
912         else if (addr.nl.nl_pid != 0)
913                 k = 0; /* not from the kernel */
914         else if ((size_t) k < sizeof(struct nlmsghdr) ||
915                         (size_t) k < m->hdr->nlmsg_len)
916                 k = -EIO; /* too small (we do accept too big though) */
917         else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
918                 k = 0; /* not broadcast and not for us */
919
920         if (k > 0)
921                 switch (m->hdr->nlmsg_type) {
922                         struct ifinfomsg *ifi;
923                         struct ifaddrmsg *ifa;
924                         struct rtmsg *rtm;
925
926                         /* check that the size matches the message type */
927                         case NLMSG_ERROR:
928                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
929                                         k = -EIO;
930                                 break;
931                         case RTM_NEWLINK:
932                         case RTM_SETLINK:
933                         case RTM_DELLINK:
934                         case RTM_GETLINK:
935                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
936                                         k = -EIO;
937                                 else {
938                                         ifi = NLMSG_DATA(m->hdr);
939                                         UPDATE_RTA(m, IFLA_RTA(ifi));
940                                 }
941                                 break;
942                         case RTM_NEWADDR:
943                         case RTM_DELADDR:
944                         case RTM_GETADDR:
945                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
946                                         k = -EIO;
947                                 else {
948                                         ifa = NLMSG_DATA(m->hdr);
949                                         UPDATE_RTA(m, IFA_RTA(ifa));
950                                 }
951                                 break;
952                         case RTM_NEWROUTE:
953                         case RTM_DELROUTE:
954                         case RTM_GETROUTE:
955                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
956                                         k = -EIO;
957                                 else {
958                                         rtm = NLMSG_DATA(m->hdr);
959                                         UPDATE_RTA(m, RTM_RTA(rtm));
960                                 }
961                                 break;
962                         case NLMSG_NOOP:
963                                 k = 0;
964                                 break;
965                         default:
966                                 k = 0; /* ignoring message of unknown type */
967                 }
968
969         if (k <= 0)
970                 sd_rtnl_message_unref(m);
971         else {
972                 /* we probably allocated way too much memory, give it back */
973                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
974                 *ret = m;
975         }
976
977         return k;
978 }
979
980 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
981         struct ifinfomsg *ifi;
982         struct ifaddrmsg *ifa;
983         struct rtmsg *rtm;
984
985         assert_return(m, -EINVAL);
986         assert_return(m->sealed, -EPERM);
987         assert_return(m->hdr, -EINVAL);
988
989         switch(m->hdr->nlmsg_type) {
990                 case RTM_NEWLINK:
991                 case RTM_SETLINK:
992                 case RTM_GETLINK:
993                 case RTM_DELLINK:
994                         ifi = NLMSG_DATA(m->hdr);
995                         UPDATE_RTA(m, IFLA_RTA(ifi));
996
997                         break;
998                 case RTM_NEWADDR:
999                 case RTM_GETADDR:
1000                 case RTM_DELADDR:
1001                         ifa = NLMSG_DATA(m->hdr);
1002                         UPDATE_RTA(m, IFA_RTA(ifa));
1003
1004                         break;
1005                 case RTM_NEWROUTE:
1006                 case RTM_GETROUTE:
1007                 case RTM_DELROUTE:
1008                         rtm = NLMSG_DATA(m->hdr);
1009                         UPDATE_RTA(m, RTM_RTA(rtm));
1010
1011                         break;
1012                 default:
1013                         return -ENOTSUP;
1014         }
1015
1016         m->n_containers = 0;
1017
1018         return 0;
1019 }