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