chiark / gitweb /
udev: declare some symbols static
[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         char *padding;
191
192         assert_return(m, -EINVAL);
193         assert_return(m->hdr, -EINVAL);
194         assert_return(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len, -EINVAL);
195         assert_return(data, -EINVAL);
196         assert_return(data_length > 0, -EINVAL);
197
198         /* get the size of the new rta attribute (with padding at the end) */
199         rta_length = RTA_LENGTH(data_length);
200         /* get the new message size (with padding at the end)
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         padding = mempcpy(RTA_DATA(rta), data, data_length);
222         /* make sure also the padding at the end of the message is initialized */
223         memset(padding, '\0', (unsigned char *) m->hdr + m->hdr->nlmsg_len - (unsigned char *) padding);
224
225         return 0;
226 }
227
228 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
229         uint16_t rtm_type;
230         struct ifaddrmsg *ifa;
231         struct rtmsg *rtm;
232
233         assert_return(m, -EINVAL);
234         assert_return(data, -EINVAL);
235
236         sd_rtnl_message_get_type(m, &rtm_type);
237
238         switch (rtm_type) {
239                 case RTM_NEWLINK:
240                 case RTM_DELLINK:
241                 case RTM_GETLINK:
242                         switch (type) {
243                                 case IFLA_IFNAME:
244                                 case IFLA_QDISC:
245                                         return add_rtattr(m, type, data, strlen(data) + 1);
246                                 case IFLA_MTU:
247                                         return add_rtattr(m, type, data, sizeof(uint32_t));
248                                 case IFLA_LINK:
249                                         return add_rtattr(m, type, data, sizeof(uint32_t));
250                                 case IFLA_STATS:
251                                         return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
252                                 case IFLA_ADDRESS:
253                                 case IFLA_BROADCAST:
254                                         return add_rtattr(m, type, data, ETH_ALEN);
255                                 default:
256                                         return -ENOTSUP;
257                         }
258                 case RTM_NEWADDR:
259                 case RTM_DELADDR:
260                 case RTM_GETADDR:
261                         switch (type) {
262                                 case IFA_LABEL:
263                                         return add_rtattr(m, type, data, strlen(data) + 1);
264                                 case IFA_ADDRESS:
265                                 case IFA_LOCAL:
266                                 case IFA_BROADCAST:
267                                 case IFA_ANYCAST:
268                                         ifa = NLMSG_DATA(m->hdr);
269                                         switch (ifa->ifa_family) {
270                                                 case AF_INET:
271                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
272                                                 case AF_INET6:
273                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
274                                                 default:
275                                                         return -EINVAL;
276                                         }
277                                 default:
278                                         return -ENOTSUP;
279                         }
280                 case RTM_NEWROUTE:
281                 case RTM_DELROUTE:
282                 case RTM_GETROUTE:
283                         switch (type) {
284                                 case RTA_DST:
285                                 case RTA_SRC:
286                                 case RTA_GATEWAY:
287                                         rtm = NLMSG_DATA(m->hdr);
288                                         switch (rtm->rtm_family) {
289                                                 case AF_INET:
290                                                         return add_rtattr(m, type, data, sizeof(struct in_addr));
291                                                 case AF_INET6:
292                                                         return add_rtattr(m, type, data, sizeof(struct in6_addr));
293                                                 default:
294                                                         return -EINVAL;
295                                         }
296                                 case RTA_TABLE:
297                                 case RTA_PRIORITY:
298                                 case RTA_IIF:
299                                 case RTA_OIF:
300                                         return add_rtattr(m, type, data, sizeof(uint32_t));
301                                 default:
302                                         return -ENOTSUP;
303                         }
304                 default:
305                         return -ENOTSUP;
306         }
307 }
308
309 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
310         assert_return(m, -EINVAL);
311         assert_return(data, -EINVAL);
312
313         if (!RTA_OK(m->next_rta, m->remaining_size))
314                 return 0;
315
316         *data = RTA_DATA(m->next_rta);
317         *type = m->next_rta->rta_type;
318
319         m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
320
321         return 1;
322 }
323
324 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
325         uint16_t rtm_type;
326
327         assert_return(m, -EINVAL);
328         assert_return(data, -EINVAL);
329
330         sd_rtnl_message_get_type(m, &rtm_type);
331
332         switch (rtm_type) {
333                 case RTM_NEWLINK:
334                 case RTM_DELLINK:
335                 case RTM_GETLINK:
336                         if (!m->next_rta) {
337                                 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
338
339                                 m->next_rta = IFLA_RTA(ifi);
340                                 m->remaining_size = IFLA_PAYLOAD(m->hdr);
341                         }
342                         break;
343                 case RTM_NEWADDR:
344                 case RTM_DELADDR:
345                 case RTM_GETADDR:
346                         if (!m->next_rta) {
347                                 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
348
349                                 m->next_rta = IFA_RTA(ifa);
350                                 m->remaining_size = IFA_PAYLOAD(m->hdr);
351                         }
352                         break;
353                 case RTM_NEWROUTE:
354                 case RTM_DELROUTE:
355                 case RTM_GETROUTE:
356                         if (!m->next_rta) {
357                                 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
358
359                                 m->next_rta = RTM_RTA(rtm);
360                                 m->remaining_size = RTM_PAYLOAD(m->hdr);
361                         }
362                         break;
363                 default:
364                         return -ENOTSUP;
365         }
366
367         return message_read(m, type, data);
368 }
369
370 int message_get_serial(sd_rtnl_message *m) {
371         assert(m);
372
373         return m->hdr->nlmsg_seq;
374 }
375
376 int message_get_errno(sd_rtnl_message *m) {
377         struct nlmsgerr *err;
378
379         assert(m);
380
381         if (m->hdr->nlmsg_type != NLMSG_ERROR)
382                 return 0;
383
384         err = NLMSG_DATA(m->hdr);
385
386         return err->error;
387 }
388
389 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
390         if (m->sealed)
391                 return -EPERM;
392
393         m->hdr->nlmsg_seq = nl->serial++;
394         m->sealed = true;
395
396         return 0;
397 }
398
399 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
400         assert_return(rtnl, -EINVAL);
401         assert_return(need, -EINVAL);
402
403         /* ioctl(rtnl->fd, FIONREAD, &need)
404            Does not appear to work on netlink sockets. libnl uses
405            MSG_PEEK instead. I don't know if that is worth the
406            extra roundtrip.
407
408            For now we simply use the maximum message size the kernel
409            may use (NLMSG_GOODSIZE), and then realloc to the actual
410            size after reading the message (hence avoiding huge memory
411            usage in case many small messages are kept around) */
412         *need = page_size();
413         if (*need > 8192UL)
414                 *need = 8192UL;
415
416         return 0;
417 }
418
419 /* returns the number of bytes sent, or a negative error code */
420 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
421         union {
422                 struct sockaddr sa;
423                 struct sockaddr_nl nl;
424         } addr = {
425                 .nl.nl_family = AF_NETLINK,
426         };
427         ssize_t k;
428
429         assert_return(nl, -EINVAL);
430         assert_return(m, -EINVAL);
431
432         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
433                         0, &addr.sa, sizeof(addr));
434         if (k < 0)
435                 return (errno == EAGAIN) ? 0 : -errno;
436
437         return k;
438 }
439
440 /* On success, the number of bytes received is returned and *ret points to the received message
441  * which has a valid header and the correct size.
442  * If nothing useful was received 0 is returned.
443  * On failure, a negative error code is returned.
444  */
445 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
446         sd_rtnl_message *m;
447         union {
448                 struct sockaddr sa;
449                 struct sockaddr_nl nl;
450         } addr;
451         socklen_t addr_len;
452         int r;
453         ssize_t k;
454         size_t need;
455
456         assert_return(nl, -EINVAL);
457         assert_return(ret, -EINVAL);
458
459         r = message_receive_need(nl, &need);
460         if (r < 0)
461                 return r;
462
463         r = message_new(&m, need);
464         if (r < 0)
465                 return r;
466
467         addr_len = sizeof(addr);
468
469         k = recvfrom(nl->fd, m->hdr, need,
470                         0, &addr.sa, &addr_len);
471         if (k < 0)
472                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
473         else if (k == 0)
474                 k = -ECONNRESET; /* connection was closed by the kernel */
475         else if (addr_len != sizeof(addr.nl) ||
476                         addr.nl.nl_family != AF_NETLINK)
477                 k = -EIO; /* not a netlink message */
478         else if (addr.nl.nl_pid != 0)
479                 k = 0; /* not from the kernel */
480         else if ((size_t) k < sizeof(struct nlmsghdr) ||
481                         (size_t) k < m->hdr->nlmsg_len)
482                 k = -EIO; /* too small (we do accept too big though) */
483         else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
484                 k = 0; /* not for us */
485
486         if (k > 0)
487                 switch (m->hdr->nlmsg_type) {
488                         /* check that the size matches the message type */
489                         case NLMSG_ERROR:
490                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
491                                         k = -EIO;
492                                 break;
493                         case RTM_NEWLINK:
494                         case RTM_DELLINK:
495                         case RTM_GETLINK:
496                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
497                                         k = -EIO;
498                                 break;
499                         case RTM_NEWADDR:
500                         case RTM_DELADDR:
501                         case RTM_GETADDR:
502                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
503                                         k = -EIO;
504                                 break;
505                         case NLMSG_NOOP:
506                                 k = 0;
507                                 break;
508                         default:
509                                 k = 0; /* ignoring message of unknown type */
510                 }
511
512         if (k <= 0)
513                 sd_rtnl_message_unref(m);
514         else {
515                 /* we probably allocated way too much memory, give it back */
516                 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
517                 *ret = m;
518         }
519
520         return k;
521 }