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