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