chiark / gitweb /
rtnl: add support for IFLA_MASTER
[elogind.git] / src / libsystemd-rtnl / rtnl-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27
28 #include "util.h"
29 #include "refcnt.h"
30
31 #include "sd-rtnl.h"
32 #include "rtnl-internal.h"
33
34 struct sd_rtnl_message {
35         RefCount n_ref;
36
37         struct nlmsghdr *hdr;
38
39         struct rtattr *current_container;
40
41         struct rtattr *next_rta;
42         size_t remaining_size;
43
44         bool sealed:1;
45 };
46
47 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
48         sd_rtnl_message *m;
49
50         assert_return(ret, -EINVAL);
51         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
52
53         m = new0(sd_rtnl_message, 1);
54         if (!m)
55                 return -ENOMEM;
56
57         m->hdr = malloc0(initial_size);
58         if (!m->hdr) {
59                 free(m);
60                 return -ENOMEM;
61         }
62
63         m->n_ref = REFCNT_INIT;
64
65         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
66         m->sealed = false;
67
68         *ret = m;
69
70         return 0;
71 }
72
73 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
74         struct nlmsgerr *err;
75         int r;
76
77         assert(error <= 0);
78
79         r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
80         if (r < 0)
81                 return r;
82
83         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
84         (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
85         (*ret)->hdr->nlmsg_seq = serial;
86
87         err = NLMSG_DATA((*ret)->hdr);
88
89         err->error = error;
90
91         return 0;
92 }
93
94 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
95                               unsigned char rtm_dst_len, unsigned char rtm_src_len,
96                               unsigned char rtm_tos, unsigned char rtm_table,
97                               unsigned char rtm_scope, unsigned char rtm_protocol,
98                               unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
99         struct rtmsg *rtm;
100         int r;
101
102         assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
103                       nlmsg_type == RTM_GETROUTE, -EINVAL);
104         assert_return(ret, -EINVAL);
105
106         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
107         if (r < 0)
108                 return r;
109
110         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
111         (*ret)->hdr->nlmsg_type = nlmsg_type;
112         if (nlmsg_type == RTM_NEWROUTE)
113                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
114
115         rtm = NLMSG_DATA((*ret)->hdr);
116
117         rtm->rtm_family = rtm_family;
118         rtm->rtm_dst_len = rtm_dst_len;
119         rtm->rtm_src_len = rtm_src_len;
120         rtm->rtm_tos = rtm_tos;
121         rtm->rtm_table = rtm_table;
122         rtm->rtm_protocol = rtm_protocol;
123         rtm->rtm_scope = rtm_scope;
124         rtm->rtm_type = rtm_type;
125         rtm->rtm_flags = rtm_flags;
126
127         return 0;
128 }
129
130 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned int type, unsigned int flags, sd_rtnl_message **ret) {
131         struct ifinfomsg *ifi;
132         int r;
133
134         assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK ||
135                       nlmsg_type == RTM_SETLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
136         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
137         assert_return(ret, -EINVAL);
138
139         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
140         if (r < 0)
141                 return r;
142
143         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
144         (*ret)->hdr->nlmsg_type = nlmsg_type;
145         if (nlmsg_type == RTM_NEWLINK)
146                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
147
148         ifi = NLMSG_DATA((*ret)->hdr);
149
150         ifi->ifi_family = AF_UNSPEC;
151         ifi->ifi_index = index;
152         ifi->ifi_type = type;
153         ifi->ifi_flags = flags;
154         ifi->ifi_change = 0xffffffff;
155
156         return 0;
157 }
158
159 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
160         struct ifaddrmsg *ifa;
161         int r;
162
163         assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
164         assert_return(index > 0, -EINVAL);
165         assert_return(ret, -EINVAL);
166
167         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
168         if (r < 0)
169                 return r;
170
171         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
172         (*ret)->hdr->nlmsg_type = nlmsg_type;
173
174         ifa = NLMSG_DATA((*ret)->hdr);
175
176         ifa->ifa_family = family;
177         ifa->ifa_prefixlen = prefixlen;
178         ifa->ifa_flags = flags;
179         ifa->ifa_scope = scope;
180         ifa->ifa_index = index;
181
182         return 0;
183 }
184
185 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
186         if (m)
187                 assert_se(REFCNT_INC(m->n_ref) >= 2);
188
189         return m;
190 }
191
192 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
193         if (m && REFCNT_DEC(m->n_ref) <= 0) {
194                 free(m->hdr);
195                 free(m);
196         }
197
198         return NULL;
199 }
200
201 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
202         assert_return(m, -EINVAL);
203         assert_return(type, -EINVAL);
204
205         *type = m->hdr->nlmsg_type;
206
207         return 0;
208 }
209
210 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
211         struct ifinfomsg *ifi;
212
213         assert_return(m, -EINVAL);
214         assert_return(ifindex, -EINVAL);
215         assert_return(m->hdr->nlmsg_type == RTM_NEWLINK || m->hdr->nlmsg_type == RTM_DELLINK ||
216                       m->hdr->nlmsg_type == RTM_GETLINK || m->hdr->nlmsg_type == RTM_SETLINK, -EINVAL);
217
218         ifi = NLMSG_DATA(m->hdr);
219
220         *ifindex = ifi->ifi_index;
221
222         return 0;
223 }
224
225 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
226    untouched */
227 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
228         uint32_t rta_length, message_length;
229         struct nlmsghdr *new_hdr;
230         struct rtattr *rta;
231         char *padding;
232
233         assert(m);
234         assert(m->hdr);
235         assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
236         assert(!data || data_length > 0);
237
238         /* get the size of the new rta attribute (with padding at the end) */
239         rta_length = RTA_LENGTH(data_length);
240         /* get the new message size (with padding at the end)
241          */
242         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
243
244         /* realloc to fit the new attribute */
245         new_hdr = realloc(m->hdr, message_length);
246         if (!new_hdr)
247                 return -ENOMEM;
248         m->hdr = new_hdr;
249
250         /* get pointer to the attribute we are about to add */
251         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
252         /* update message size */
253         m->hdr->nlmsg_len = message_length;
254
255         /* we are inside a container, extend it */
256         if (m->current_container)
257                 m->current_container->rta_len = (unsigned char *) m->hdr +
258                                                 m->hdr->nlmsg_len -
259                                                 (unsigned char *) m->current_container;
260
261         /* fill in the attribute */
262         rta->rta_type = type;
263         rta->rta_len = rta_length;
264         if (!data) {
265                 /* this is a container, set pointer */
266                 m->current_container = rta;
267         } else {
268                 /* we don't deal with the case where the user lies about the type
269                  * and gives us too little data (so don't do that)
270                 */
271                 padding = mempcpy(RTA_DATA(rta), data, data_length);
272                 /* make sure also the padding at the end of the message is initialized */
273                 memset(padding, '\0', (unsigned char *) m->hdr +
274                                       m->hdr->nlmsg_len -
275                                       (unsigned char *) padding);
276         }
277
278         return 0;
279 }
280
281 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
282         uint16_t rtm_type;
283         struct ifaddrmsg *ifa;
284         struct rtmsg *rtm;
285
286         assert_return(m, -EINVAL);
287         assert_return(data, -EINVAL);
288
289         sd_rtnl_message_get_type(m, &rtm_type);
290
291         if (m->current_container) {
292                 switch (rtm_type) {
293                         case RTM_NEWLINK:
294                         case RTM_SETLINK:
295                         case RTM_GETLINK:
296                         case RTM_DELLINK:
297                                 switch (m->current_container->rta_type) {
298                                         case IFLA_LINKINFO:
299                                                 switch (type) {
300                                                         case IFLA_INFO_KIND:
301                                                                 return add_rtattr(m, type, data, strlen(data) + 1);
302                                                         default:
303                                                                 return -ENOTSUP;
304                                                 }
305                                         default:
306                                                 return -ENOTSUP;
307                                 }
308                         default:
309                                 return -ENOTSUP;
310                 }
311         }
312
313         switch (rtm_type) {
314                 case RTM_NEWLINK:
315                 case RTM_SETLINK:
316                 case RTM_DELLINK:
317                 case RTM_GETLINK:
318                         switch (type) {
319                                 case IFLA_IFNAME:
320                                 case IFLA_IFALIAS:
321                                 case IFLA_QDISC:
322                                         return add_rtattr(m, type, data, strlen(data) + 1);
323                                 case IFLA_MASTER:
324                                 case IFLA_MTU:
325                                 case IFLA_LINK:
326                                         return add_rtattr(m, type, data, sizeof(uint32_t));
327                                 case IFLA_STATS:
328                                         return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
329                                 case IFLA_ADDRESS:
330                                 case IFLA_BROADCAST:
331                                         return add_rtattr(m, type, data, ETH_ALEN);
332                                 default:
333                                         return -ENOTSUP;
334                         }
335                 case RTM_NEWADDR:
336                 case RTM_DELADDR:
337                 case RTM_GETADDR:
338                         switch (type) {
339                                 case IFA_LABEL:
340                                         return add_rtattr(m, type, data, strlen(data) + 1);
341                                 case IFA_ADDRESS:
342                                 case IFA_LOCAL:
343                                 case IFA_BROADCAST:
344                                 case IFA_ANYCAST:
345                                         ifa = NLMSG_DATA(m->hdr);
346                                         switch (ifa->ifa_family) {
347                                                 case AF_INET:
348                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
349                                                 case AF_INET6:
350                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
351                                                 default:
352                                                         return -EINVAL;
353                                         }
354                                 default:
355                                         return -ENOTSUP;
356                         }
357                 case RTM_NEWROUTE:
358                 case RTM_DELROUTE:
359                 case RTM_GETROUTE:
360                         switch (type) {
361                                 case RTA_DST:
362                                 case RTA_SRC:
363                                 case RTA_GATEWAY:
364                                         rtm = NLMSG_DATA(m->hdr);
365                                         switch (rtm->rtm_family) {
366                                                 case AF_INET:
367                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
368                                                 case AF_INET6:
369                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
370                                                 default:
371                                                         return -EINVAL;
372                                         }
373                                 case RTA_TABLE:
374                                 case RTA_PRIORITY:
375                                 case RTA_IIF:
376                                 case RTA_OIF:
377                                         return add_rtattr(m, type, data, sizeof(uint32_t));
378                                 default:
379                                         return -ENOTSUP;
380                         }
381                 default:
382                         return -ENOTSUP;
383         }
384 }
385
386 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
387         uint16_t rtm_type;
388
389         assert_return(m, -EINVAL);
390         assert_return(!m->current_container, -EINVAL);
391
392         sd_rtnl_message_get_type(m, &rtm_type);
393
394         switch (rtm_type) {
395                 case RTM_NEWLINK:
396                 case RTM_SETLINK:
397                 case RTM_GETLINK:
398                 case RTM_DELLINK:
399                         if (type == IFLA_LINKINFO)
400                                 return add_rtattr(m, type, NULL, 0);
401                         else
402                                 return -ENOTSUP;
403                 default:
404                         return -ENOTSUP;
405         }
406
407         return 0;
408 }
409
410 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
411         assert_return(m, -EINVAL);
412         assert_return(m->current_container, -EINVAL);
413
414         m->current_container = NULL;
415
416         return 0;
417 }
418
419 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
420         uint16_t rtm_type;
421         int r;
422
423         assert(m);
424         assert(m->next_rta);
425         assert(type);
426         assert(data);
427
428         if (!RTA_OK(m->next_rta, m->remaining_size))
429                 return 0;
430
431         /* make sure we don't try to read a container
432          * TODO: add support for entering containers for reading */
433         r = sd_rtnl_message_get_type(m, &rtm_type);
434         if (r < 0)
435                 return r;
436
437         switch (rtm_type) {
438                 case RTM_NEWLINK:
439                 case RTM_GETLINK:
440                 case RTM_SETLINK:
441                 case RTM_DELLINK:
442                         if (m->next_rta->rta_type == IFLA_LINKINFO) {
443                                 return -EINVAL;
444                         }
445         }
446
447         *data = RTA_DATA(m->next_rta);
448         *type = m->next_rta->rta_type;
449
450         m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
451
452         return 1;
453 }
454
455 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
456         uint16_t rtm_type;
457         int r;
458
459         assert_return(m, -EINVAL);
460         assert_return(data, -EINVAL);
461
462         r = sd_rtnl_message_get_type(m, &rtm_type);
463         if (r < 0)
464                 return r;
465
466         switch (rtm_type) {
467                 case RTM_NEWLINK:
468                 case RTM_SETLINK:
469                 case RTM_DELLINK:
470                 case RTM_GETLINK:
471                         if (!m->next_rta) {
472                                 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
473
474                                 m->next_rta = IFLA_RTA(ifi);
475                                 m->remaining_size = IFLA_PAYLOAD(m->hdr);
476                         }
477                         break;
478                 case RTM_NEWADDR:
479                 case RTM_DELADDR:
480                 case RTM_GETADDR:
481                         if (!m->next_rta) {
482                                 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
483
484                                 m->next_rta = IFA_RTA(ifa);
485                                 m->remaining_size = IFA_PAYLOAD(m->hdr);
486                         }
487                         break;
488                 case RTM_NEWROUTE:
489                 case RTM_DELROUTE:
490                 case RTM_GETROUTE:
491                         if (!m->next_rta) {
492                                 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
493
494                                 m->next_rta = RTM_RTA(rtm);
495                                 m->remaining_size = RTM_PAYLOAD(m->hdr);
496                         }
497                         break;
498                 default:
499                         return -ENOTSUP;
500         }
501
502         return message_read(m, type, data);
503 }
504
505 uint32_t message_get_serial(sd_rtnl_message *m) {
506         assert(m);
507
508         return m->hdr->nlmsg_seq;
509 }
510
511 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
512         struct nlmsgerr *err;
513
514         assert_return(m, -EINVAL);
515
516         if (m->hdr->nlmsg_type != NLMSG_ERROR)
517                 return 0;
518
519         err = NLMSG_DATA(m->hdr);
520
521         return err->error;
522 }
523
524 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
525         if (m->sealed)
526                 return -EPERM;
527
528         m->hdr->nlmsg_seq = nl->serial++;
529         m->sealed = true;
530
531         return 0;
532 }
533
534 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
535         assert_return(rtnl, -EINVAL);
536         assert_return(need, -EINVAL);
537
538         /* ioctl(rtnl->fd, FIONREAD, &need)
539            Does not appear to work on netlink sockets. libnl uses
540            MSG_PEEK instead. I don't know if that is worth the
541            extra roundtrip.
542
543            For now we simply use the maximum message size the kernel
544            may use (NLMSG_GOODSIZE), and then realloc to the actual
545            size after reading the message (hence avoiding huge memory
546            usage in case many small messages are kept around) */
547         *need = page_size();
548         if (*need > 8192UL)
549                 *need = 8192UL;
550
551         return 0;
552 }
553
554 /* returns the number of bytes sent, or a negative error code */
555 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
556         union {
557                 struct sockaddr sa;
558                 struct sockaddr_nl nl;
559         } addr = {
560                 .nl.nl_family = AF_NETLINK,
561         };
562         ssize_t k;
563
564         assert_return(nl, -EINVAL);
565         assert_return(m, -EINVAL);
566
567         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
568                         0, &addr.sa, sizeof(addr));
569         if (k < 0)
570                 return (errno == EAGAIN) ? 0 : -errno;
571
572         return k;
573 }
574
575 /* On success, the number of bytes received is returned and *ret points to the received message
576  * which has a valid header and the correct size.
577  * If nothing useful was received 0 is returned.
578  * On failure, a negative error code is returned.
579  */
580 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
581         sd_rtnl_message *m;
582         union {
583                 struct sockaddr sa;
584                 struct sockaddr_nl nl;
585         } addr;
586         socklen_t addr_len;
587         int r;
588         ssize_t k;
589         size_t need;
590
591         assert_return(nl, -EINVAL);
592         assert_return(ret, -EINVAL);
593
594         r = message_receive_need(nl, &need);
595         if (r < 0)
596                 return r;
597
598         r = message_new(&m, need);
599         if (r < 0)
600                 return r;
601
602         addr_len = sizeof(addr);
603
604         k = recvfrom(nl->fd, m->hdr, need,
605                         0, &addr.sa, &addr_len);
606         if (k < 0)
607                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
608         else if (k == 0)
609                 k = -ECONNRESET; /* connection was closed by the kernel */
610         else if (addr_len != sizeof(addr.nl) ||
611                         addr.nl.nl_family != AF_NETLINK)
612                 k = -EIO; /* not a netlink message */
613         else if (addr.nl.nl_pid != 0)
614                 k = 0; /* not from the kernel */
615         else if ((size_t) k < sizeof(struct nlmsghdr) ||
616                         (size_t) k < m->hdr->nlmsg_len)
617                 k = -EIO; /* too small (we do accept too big though) */
618         else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
619                 k = 0; /* not for us */
620
621         if (k > 0)
622                 switch (m->hdr->nlmsg_type) {
623                         /* check that the size matches the message type */
624                         case NLMSG_ERROR:
625                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
626                                         k = -EIO;
627                                 break;
628                         case RTM_NEWLINK:
629                         case RTM_SETLINK:
630                         case RTM_DELLINK:
631                         case RTM_GETLINK:
632                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
633                                         k = -EIO;
634                                 break;
635                         case RTM_NEWADDR:
636                         case RTM_DELADDR:
637                         case RTM_GETADDR:
638                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
639                                         k = -EIO;
640                                 break;
641                         case NLMSG_NOOP:
642                                 k = 0;
643                                 break;
644                         default:
645                                 k = 0; /* ignoring message of unknown type */
646                 }
647
648         if (k <= 0)
649                 sd_rtnl_message_unref(m);
650         else {
651                 /* we probably allocated way too much memory, give it back */
652                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
653                 *ret = m;
654         }
655
656         return k;
657 }