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