chiark / gitweb /
85cf55a3cdcc2df8cad09e0d5445512078f82b89
[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 *next_rta;
40         size_t remaining_size;
41
42         bool sealed:1;
43 };
44
45 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
46         sd_rtnl_message *m;
47
48         assert_return(ret, -EINVAL);
49         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
50
51         m = new0(sd_rtnl_message, 1);
52         if (!m)
53                 return -ENOMEM;
54
55         m->hdr = malloc0(initial_size);
56         if (!m->hdr) {
57                 free(m);
58                 return -ENOMEM;
59         }
60
61         m->n_ref = REFCNT_INIT;
62
63         m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
64         m->sealed = false;
65
66         *ret = m;
67
68         return 0;
69 }
70
71 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
72                               unsigned char rtm_dst_len, unsigned char rtm_src_len,
73                               unsigned char rtm_tos, unsigned char rtm_table,
74                               unsigned char rtm_scope, unsigned char rtm_protocol,
75                               unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
76         struct rtmsg *rtm;
77         int r;
78
79         assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
80                       nlmsg_type == RTM_GETROUTE, -EINVAL);
81         assert_return(ret, -EINVAL);
82
83         r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
84         if (r < 0)
85                 return r;
86
87         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
88         (*ret)->hdr->nlmsg_type = nlmsg_type;
89         if (nlmsg_type == RTM_NEWROUTE)
90                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
91
92         rtm = NLMSG_DATA((*ret)->hdr);
93
94         rtm->rtm_family = rtm_family;
95         rtm->rtm_dst_len = rtm_dst_len;
96         rtm->rtm_src_len = rtm_src_len;
97         rtm->rtm_tos = rtm_tos;
98         rtm->rtm_table = rtm_table;
99         rtm->rtm_protocol = rtm_protocol;
100         rtm->rtm_scope = rtm_scope;
101         rtm->rtm_type = rtm_type;
102         rtm->rtm_flags = rtm_flags;
103
104         return 0;
105 }
106
107 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned int type, unsigned int flags, sd_rtnl_message **ret) {
108         struct ifinfomsg *ifi;
109         int r;
110
111         assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
112         assert_return(index > 0, -EINVAL);
113         assert_return(ret, -EINVAL);
114
115         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
116         if (r < 0)
117                 return r;
118
119         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
120         (*ret)->hdr->nlmsg_type = nlmsg_type;
121
122         ifi = NLMSG_DATA((*ret)->hdr);
123
124         ifi->ifi_family = AF_UNSPEC;
125         ifi->ifi_index = index;
126         ifi->ifi_type = type;
127         ifi->ifi_flags = flags;
128         ifi->ifi_change = 0xffffffff;
129
130         return 0;
131 }
132
133 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) {
134         struct ifaddrmsg *ifa;
135         int r;
136
137         assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
138         assert_return(index > 0, -EINVAL);
139         assert_return(ret, -EINVAL);
140
141         r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
142         if (r < 0)
143                 return r;
144
145         (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
146         (*ret)->hdr->nlmsg_type = nlmsg_type;
147
148         ifa = NLMSG_DATA((*ret)->hdr);
149
150         ifa->ifa_family = family;
151         ifa->ifa_prefixlen = prefixlen;
152         ifa->ifa_flags = flags;
153         ifa->ifa_scope = scope;
154         ifa->ifa_index = index;
155
156         return 0;
157 }
158
159 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
160         if (m)
161                 assert_se(REFCNT_INC(m->n_ref) >= 2);
162
163         return m;
164 }
165
166 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
167         if (m && REFCNT_DEC(m->n_ref) <= 0) {
168                 free(m->hdr);
169                 free(m);
170         }
171
172         return NULL;
173 }
174
175 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
176         assert_return(m, -EINVAL);
177         assert_return(type, -EINVAL);
178
179         *type = m->hdr->nlmsg_type;
180
181         return 0;
182 }
183
184 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
185    untouched */
186 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
187         uint32_t rta_length, message_length;
188         struct nlmsghdr *new_hdr;
189         struct rtattr *rta;
190
191         assert_return(m, -EINVAL);
192         assert_return(m->hdr, -EINVAL);
193         assert_return(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len, -EINVAL);
194         assert_return(data, -EINVAL);
195         assert_return(data_length > 0, -EINVAL);
196
197         /* get the size of the new rta attribute (without padding at the end) */
198         rta_length = RTA_LENGTH(data_length);
199         /* get the new message size (with padding between the old message and the new attrib,
200          * but no padding after)
201          */
202         message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
203
204         /* realloc to fit the new attribute */
205         new_hdr = realloc(m->hdr, message_length);
206         if (!new_hdr)
207                 return -ENOMEM;
208         m->hdr = new_hdr;
209
210         /* get pointer to the attribute we are about to add */
211         rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
212         /* update message size */
213         m->hdr->nlmsg_len = message_length;
214
215         /* fill in the attribute */
216         rta->rta_type = type;
217         rta->rta_len = rta_length;
218         /* we don't deal with the case where the user lies about the type and gives us
219          * too little data (so don't do that)
220          */
221         memcpy(RTA_DATA(rta), data, data_length);
222
223         return 0;
224 }
225
226 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
227         uint16_t rtm_type;
228         struct ifaddrmsg *ifa;
229         struct rtmsg *rtm;
230
231         assert_return(m, -EINVAL);
232         assert_return(data, -EINVAL);
233
234         sd_rtnl_message_get_type(m, &rtm_type);
235
236         switch (rtm_type) {
237                 case RTM_NEWLINK:
238                 case RTM_DELLINK:
239                 case RTM_GETLINK:
240                         switch (type) {
241                                 case IFLA_IFNAME:
242                                 case IFLA_QDISC:
243                                         return add_rtattr(m, type, data, strlen(data) + 1);
244                                 case IFLA_MTU:
245                                         return add_rtattr(m, type, data, sizeof(uint32_t));
246                                 case IFLA_LINK:
247                                         return add_rtattr(m, type, data, sizeof(uint32_t));
248                                 case IFLA_STATS:
249                                         return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
250                                 case IFLA_ADDRESS:
251                                 case IFLA_BROADCAST:
252                                         return add_rtattr(m, type, data, ETH_ALEN);
253                                 default:
254                                         return -ENOTSUP;
255                         }
256                 case RTM_NEWADDR:
257                 case RTM_DELADDR:
258                 case RTM_GETADDR:
259                         switch (type) {
260                                 case IFA_LABEL:
261                                         return add_rtattr(m, type, data, strlen(data) + 1);
262                                 case IFA_ADDRESS:
263                                 case IFA_LOCAL:
264                                 case IFA_BROADCAST:
265                                 case IFA_ANYCAST:
266                                         ifa = NLMSG_DATA(m->hdr);
267                                         switch (ifa->ifa_family) {
268                                                 case AF_INET:
269                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
270                                                 case AF_INET6:
271                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
272                                                 default:
273                                                         return -EINVAL;
274                                         }
275                                 default:
276                                         return -ENOTSUP;
277                         }
278                 case RTM_NEWROUTE:
279                 case RTM_DELROUTE:
280                 case RTM_GETROUTE:
281                         switch (type) {
282                                 case RTA_DST:
283                                 case RTA_SRC:
284                                 case RTA_GATEWAY:
285                                         rtm = NLMSG_DATA(m->hdr);
286                                         switch (rtm->rtm_family) {
287                                                 case AF_INET:
288                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
289                                                 case AF_INET6:
290                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
291                                                 default:
292                                                         return -EINVAL;
293                                         }
294                                 case RTA_TABLE:
295                                 case RTA_PRIORITY:
296                                 case RTA_IIF:
297                                 case RTA_OIF:
298                                         return add_rtattr(m, type, data, sizeof(uint32_t));
299                                 default:
300                                         return -ENOTSUP;
301                         }
302                 default:
303                         return -ENOTSUP;
304         }
305 }
306
307 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
308         assert_return(m, -EINVAL);
309         assert_return(data, -EINVAL);
310
311         if (!RTA_OK(m->next_rta, m->remaining_size))
312                 return 0;
313
314         *data = RTA_DATA(m->next_rta);
315         *type = m->next_rta->rta_type;
316
317         m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
318
319         return 1;
320 }
321
322 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
323         uint16_t rtm_type;
324
325         assert_return(m, -EINVAL);
326         assert_return(data, -EINVAL);
327
328         sd_rtnl_message_get_type(m, &rtm_type);
329
330         switch (rtm_type) {
331                 case RTM_NEWLINK:
332                 case RTM_DELLINK:
333                 case RTM_GETLINK:
334                         if (!m->next_rta) {
335                                 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
336
337                                 m->next_rta = IFLA_RTA(ifi);
338                                 m->remaining_size = IFLA_PAYLOAD(m->hdr);
339                         }
340                         break;
341                 case RTM_NEWADDR:
342                 case RTM_DELADDR:
343                 case RTM_GETADDR:
344                         if (!m->next_rta) {
345                                 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
346
347                                 m->next_rta = IFA_RTA(ifa);
348                                 m->remaining_size = IFA_PAYLOAD(m->hdr);
349                         }
350                         break;
351                 case RTM_NEWROUTE:
352                 case RTM_DELROUTE:
353                 case RTM_GETROUTE:
354                         if (!m->next_rta) {
355                                 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
356
357                                 m->next_rta = RTM_RTA(rtm);
358                                 m->remaining_size = RTM_PAYLOAD(m->hdr);
359                         }
360                         break;
361                 default:
362                         return -ENOTSUP;
363         }
364
365         return message_read(m, type, data);
366 }
367
368 int message_get_serial(sd_rtnl_message *m) {
369         assert(m);
370
371         return m->hdr->nlmsg_seq;
372 }
373
374 int message_get_errno(sd_rtnl_message *m) {
375         struct nlmsgerr *err;
376
377         assert(m);
378
379         if (m->hdr->nlmsg_type != NLMSG_ERROR)
380                 return 0;
381
382         err = NLMSG_DATA(m->hdr);
383
384         return err->error;
385 }
386
387 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
388         if (m->sealed)
389                 return -EPERM;
390
391         m->hdr->nlmsg_seq = nl->serial++;
392         m->sealed = true;
393
394         return 0;
395 }
396
397 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
398         assert_return(rtnl, -EINVAL);
399         assert_return(need, -EINVAL);
400
401         /* ioctl(rtnl->fd, FIONREAD, &need)
402            Does not appear to work on netlink sockets. libnl uses
403            MSG_PEEK instead. I don't know if that is worth the
404            extra roundtrip.
405
406            For now we simply use the maximum message size the kernel
407            may use (NLMSG_GOODSIZE), and then realloc to the actual
408            size after reading the message (hence avoiding huge memory
409            usage in case many small messages are kept around) */
410         *need = page_size();
411         if (*need > 8192UL)
412                 *need = 8192UL;
413
414         return 0;
415 }
416
417 /* returns the number of bytes sent, or a negative error code */
418 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
419         union {
420                 struct sockaddr sa;
421                 struct sockaddr_nl nl;
422         } addr = {
423                 .nl.nl_family = AF_NETLINK,
424         };
425         ssize_t k;
426
427         assert_return(nl, -EINVAL);
428         assert_return(m, -EINVAL);
429
430         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
431                         0, &addr.sa, sizeof(addr));
432         if (k < 0)
433                 return (errno == EAGAIN) ? 0 : -errno;
434
435         return k;
436 }
437
438 /* On success, the number of bytes received is returned and *ret points to the received message
439  * which has a valid header and the correct size.
440  * If nothing useful was received 0 is returned.
441  * On failure, a negative error code is returned.
442  */
443 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
444         sd_rtnl_message *m;
445         union {
446                 struct sockaddr sa;
447                 struct sockaddr_nl nl;
448         } addr;
449         socklen_t addr_len;
450         int r;
451         ssize_t k;
452         size_t need;
453
454         assert_return(nl, -EINVAL);
455         assert_return(ret, -EINVAL);
456
457         r = message_receive_need(nl, &need);
458         if (r < 0)
459                 return r;
460
461         r = message_new(&m, need);
462         if (r < 0)
463                 return r;
464
465         addr_len = sizeof(addr);
466
467         k = recvfrom(nl->fd, m->hdr, need,
468                         0, &addr.sa, &addr_len);
469         if (k < 0)
470                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
471         else if (k == 0)
472                 k = -ECONNRESET; /* connection was closed by the kernel */
473         else if (addr_len != sizeof(addr.nl) ||
474                         addr.nl.nl_family != AF_NETLINK)
475                 k = -EIO; /* not a netlink message */
476         else if (addr.nl.nl_pid != 0)
477                 k = 0; /* not from the kernel */
478         else if ((size_t) k < sizeof(struct nlmsghdr) ||
479                         (size_t) k < m->hdr->nlmsg_len)
480                 k = -EIO; /* too small (we do accept too big though) */
481         else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
482                 k = 0; /* not for us */
483
484         if (k > 0)
485                 switch (m->hdr->nlmsg_type) {
486                         /* check that the size matches the message type */
487                         case NLMSG_ERROR:
488                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
489                                         k = -EIO;
490                                 break;
491                         case RTM_NEWLINK:
492                         case RTM_DELLINK:
493                         case RTM_GETLINK:
494                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
495                                         k = -EIO;
496                                 break;
497                         case RTM_NEWADDR:
498                         case RTM_DELADDR:
499                         case RTM_GETADDR:
500                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
501                                         k = -EIO;
502                                 break;
503                         case NLMSG_NOOP:
504                                 k = 0;
505                                 break;
506                         default:
507                                 k = 0; /* ignoring message of unknown type */
508                 }
509
510         if (k <= 0)
511                 sd_rtnl_message_unref(m);
512         else {
513                 /* we probably allocated way too much memory, give it back */
514                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
515                 *ret = m;
516         }
517
518         return k;
519 }