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