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