chiark / gitweb /
sd-rtnl: message_open_container - don't take a 'size' argument
[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) {
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 &&
714                      GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
715                         return add_rtattr(m, type, NULL, 0);
716                 else if (type == VETH_INFO_PEER && m->n_containers == 2 &&
717                          GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
718                          GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO)
719                         return add_rtattr(m, type, NULL, sizeof(struct ifinfomsg));
720         }
721
722         return -ENOTSUP;
723 }
724
725 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
726         assert_return(m, -EINVAL);
727         assert_return(!m->sealed, -EPERM);
728         assert_return(m->n_containers > 0, -EINVAL);
729
730         m->n_containers --;
731
732         return 0;
733 }
734
735 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
736         size_t remaining_size;
737         uint16_t rtm_type;
738         int r;
739
740         assert_return(m, -EINVAL);
741         assert_return(m->sealed, -EPERM);
742         assert_return(m->next_rta_offset, -EINVAL);
743         assert_return(type, -EINVAL);
744         assert_return(data, -EINVAL);
745
746         /* only read until the end of the current container */
747         if (m->n_containers)
748                 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
749                                  (m->next_rta_offset -
750                                   m->container_offsets[m->n_containers - 1]);
751         else
752                 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
753
754         if (!RTA_OK(NEXT_RTA(m), remaining_size))
755                 return 0;
756
757         /* if we read a container, enter it and return its type */
758         r = sd_rtnl_message_get_type(m, &rtm_type);
759         if (r < 0)
760                 return r;
761
762         *type = NEXT_RTA(m)->rta_type;
763
764         if (rtnl_message_type_is_link(rtm_type) &&
765             ((m->n_containers == 0 &&
766               NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
767              (m->n_containers == 1 &&
768               GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
769               NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
770                 *data = NULL;
771                 PUSH_CONTAINER(m, NEXT_RTA(m));
772                 UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
773         } else {
774                 *data = RTA_DATA(NEXT_RTA(m));
775                 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
776         }
777
778         return 1;
779 }
780
781 int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
782         assert_return(m, -EINVAL);
783         assert_return(m->sealed, -EINVAL);
784         assert_return(m->n_containers > 0, -EINVAL);
785
786         m->n_containers --;
787
788         return 0;
789 }
790
791 uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
792         assert(m);
793         assert(m->hdr);
794
795         return m->hdr->nlmsg_seq;
796 }
797
798 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
799         struct nlmsgerr *err;
800
801         assert_return(m, -EINVAL);
802         assert_return(m->hdr, -EINVAL);
803
804         if (m->hdr->nlmsg_type != NLMSG_ERROR)
805                 return 0;
806
807         err = NLMSG_DATA(m->hdr);
808
809         return err->error;
810 }
811
812 int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
813         int r;
814
815         assert(m);
816         assert(m->hdr);
817
818         if (m->sealed)
819                 return -EPERM;
820
821         if (nl)
822                 m->hdr->nlmsg_seq = nl->serial++;
823
824         m->sealed = true;
825
826         r = sd_rtnl_message_rewind(m);
827         if (r < 0)
828                 return r;
829
830         return 0;
831 }
832
833 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
834         assert(rtnl);
835         assert(need);
836
837         /* ioctl(rtnl->fd, FIONREAD, &need)
838            Does not appear to work on netlink sockets. libnl uses
839            MSG_PEEK instead. I don't know if that is worth the
840            extra roundtrip.
841
842            For now we simply use the maximum message size the kernel
843            may use (NLMSG_GOODSIZE), and then realloc to the actual
844            size after reading the message (hence avoiding huge memory
845            usage in case many small messages are kept around) */
846         *need = page_size();
847         if (*need > 8192UL)
848                 *need = 8192UL;
849
850         return 0;
851 }
852
853 /* returns the number of bytes sent, or a negative error code */
854 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
855         union {
856                 struct sockaddr sa;
857                 struct sockaddr_nl nl;
858         } addr = {
859                 .nl.nl_family = AF_NETLINK,
860         };
861         ssize_t k;
862
863         assert(nl);
864         assert(m);
865         assert(m->hdr);
866
867         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
868                         0, &addr.sa, sizeof(addr));
869         if (k < 0)
870                 return (errno == EAGAIN) ? 0 : -errno;
871
872         return k;
873 }
874
875 /* On success, the number of bytes received is returned and *ret points to the received message
876  * which has a valid header and the correct size.
877  * If nothing useful was received 0 is returned.
878  * On failure, a negative error code is returned.
879  */
880 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
881         sd_rtnl_message *m;
882         union {
883                 struct sockaddr sa;
884                 struct sockaddr_nl nl;
885         } addr;
886         socklen_t addr_len;
887         int r;
888         ssize_t k;
889         size_t need;
890
891         assert(nl);
892         assert(ret);
893
894         r = message_receive_need(nl, &need);
895         if (r < 0)
896                 return r;
897
898         r = message_new(&m, need);
899         if (r < 0)
900                 return r;
901
902         /* don't allow sealing/appending to received messages */
903         m->sealed = true;
904
905         addr_len = sizeof(addr);
906
907         k = recvfrom(nl->fd, m->hdr, need,
908                         0, &addr.sa, &addr_len);
909         if (k < 0)
910                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
911         else if (k == 0)
912                 k = -ECONNRESET; /* connection was closed by the kernel */
913         else if (addr_len != sizeof(addr.nl) ||
914                         addr.nl.nl_family != AF_NETLINK)
915                 k = -EIO; /* not a netlink message */
916         else if (addr.nl.nl_pid != 0)
917                 k = 0; /* not from the kernel */
918         else if ((size_t) k < sizeof(struct nlmsghdr) ||
919                         (size_t) k < m->hdr->nlmsg_len)
920                 k = -EIO; /* too small (we do accept too big though) */
921         else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
922                 k = 0; /* not broadcast and not for us */
923
924         if (k > 0)
925                 switch (m->hdr->nlmsg_type) {
926                         struct ifinfomsg *ifi;
927                         struct ifaddrmsg *ifa;
928                         struct rtmsg *rtm;
929
930                         /* check that the size matches the message type */
931                         case NLMSG_ERROR:
932                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
933                                         k = -EIO;
934                                 break;
935                         case RTM_NEWLINK:
936                         case RTM_SETLINK:
937                         case RTM_DELLINK:
938                         case RTM_GETLINK:
939                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
940                                         k = -EIO;
941                                 else {
942                                         ifi = NLMSG_DATA(m->hdr);
943                                         UPDATE_RTA(m, IFLA_RTA(ifi));
944                                 }
945                                 break;
946                         case RTM_NEWADDR:
947                         case RTM_DELADDR:
948                         case RTM_GETADDR:
949                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
950                                         k = -EIO;
951                                 else {
952                                         ifa = NLMSG_DATA(m->hdr);
953                                         UPDATE_RTA(m, IFA_RTA(ifa));
954                                 }
955                                 break;
956                         case RTM_NEWROUTE:
957                         case RTM_DELROUTE:
958                         case RTM_GETROUTE:
959                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
960                                         k = -EIO;
961                                 else {
962                                         rtm = NLMSG_DATA(m->hdr);
963                                         UPDATE_RTA(m, RTM_RTA(rtm));
964                                 }
965                                 break;
966                         case NLMSG_NOOP:
967                                 k = 0;
968                                 break;
969                         default:
970                                 k = 0; /* ignoring message of unknown type */
971                 }
972
973         if (k <= 0)
974                 sd_rtnl_message_unref(m);
975         else {
976                 /* we probably allocated way too much memory, give it back */
977                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
978                 *ret = m;
979         }
980
981         return k;
982 }
983
984 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
985         struct ifinfomsg *ifi;
986         struct ifaddrmsg *ifa;
987         struct rtmsg *rtm;
988
989         assert_return(m, -EINVAL);
990         assert_return(m->sealed, -EPERM);
991         assert_return(m->hdr, -EINVAL);
992
993         switch(m->hdr->nlmsg_type) {
994                 case RTM_NEWLINK:
995                 case RTM_SETLINK:
996                 case RTM_GETLINK:
997                 case RTM_DELLINK:
998                         ifi = NLMSG_DATA(m->hdr);
999                         UPDATE_RTA(m, IFLA_RTA(ifi));
1000
1001                         break;
1002                 case RTM_NEWADDR:
1003                 case RTM_GETADDR:
1004                 case RTM_DELADDR:
1005                         ifa = NLMSG_DATA(m->hdr);
1006                         UPDATE_RTA(m, IFA_RTA(ifa));
1007
1008                         break;
1009                 case RTM_NEWROUTE:
1010                 case RTM_GETROUTE:
1011                 case RTM_DELROUTE:
1012                         rtm = NLMSG_DATA(m->hdr);
1013                         UPDATE_RTA(m, RTM_RTA(rtm));
1014
1015                         break;
1016                 default:
1017                         return -ENOTSUP;
1018         }
1019
1020         m->n_containers = 0;
1021
1022         return 0;
1023 }