1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <linux/rtnetlink.h>
23 #include <netinet/in.h>
24 #include <netinet/ether.h>
32 #include "rtnl-internal.h"
34 struct sd_rtnl_message {
39 struct rtattr *next_rta;
40 size_t remaining_size;
45 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
48 assert_return(ret, -EINVAL);
49 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
51 m = new0(sd_rtnl_message, 1);
55 m->hdr = malloc0(initial_size);
61 m->n_ref = REFCNT_INIT;
63 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
71 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
77 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
81 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
82 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
83 (*ret)->hdr->nlmsg_seq = serial;
85 err = NLMSG_DATA((*ret)->hdr);
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) {
100 assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
101 nlmsg_type == RTM_GETROUTE, -EINVAL);
102 assert_return(ret, -EINVAL);
104 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
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;
113 rtm = NLMSG_DATA((*ret)->hdr);
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;
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;
132 assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
133 assert_return(index > 0, -EINVAL);
134 assert_return(ret, -EINVAL);
136 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
140 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
141 (*ret)->hdr->nlmsg_type = nlmsg_type;
143 ifi = NLMSG_DATA((*ret)->hdr);
145 ifi->ifi_family = AF_UNSPEC;
146 ifi->ifi_index = index;
147 ifi->ifi_type = type;
148 ifi->ifi_flags = flags;
149 ifi->ifi_change = 0xffffffff;
154 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) {
155 struct ifaddrmsg *ifa;
158 assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
159 assert_return(index > 0, -EINVAL);
160 assert_return(ret, -EINVAL);
162 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
166 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
167 (*ret)->hdr->nlmsg_type = nlmsg_type;
169 ifa = NLMSG_DATA((*ret)->hdr);
171 ifa->ifa_family = family;
172 ifa->ifa_prefixlen = prefixlen;
173 ifa->ifa_flags = flags;
174 ifa->ifa_scope = scope;
175 ifa->ifa_index = index;
180 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
182 assert_se(REFCNT_INC(m->n_ref) >= 2);
187 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
188 if (m && REFCNT_DEC(m->n_ref) <= 0) {
196 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
197 assert_return(m, -EINVAL);
198 assert_return(type, -EINVAL);
200 *type = m->hdr->nlmsg_type;
205 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
207 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
208 uint32_t rta_length, message_length;
209 struct nlmsghdr *new_hdr;
213 assert_return(m, -EINVAL);
214 assert_return(m->hdr, -EINVAL);
215 assert_return(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len, -EINVAL);
216 assert_return(data, -EINVAL);
217 assert_return(data_length > 0, -EINVAL);
219 /* get the size of the new rta attribute (with padding at the end) */
220 rta_length = RTA_LENGTH(data_length);
221 /* get the new message size (with padding at the end)
223 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
225 /* realloc to fit the new attribute */
226 new_hdr = realloc(m->hdr, message_length);
231 /* get pointer to the attribute we are about to add */
232 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
233 /* update message size */
234 m->hdr->nlmsg_len = message_length;
236 /* fill in the attribute */
237 rta->rta_type = type;
238 rta->rta_len = rta_length;
239 /* we don't deal with the case where the user lies about the type and gives us
240 * too little data (so don't do that)
242 padding = mempcpy(RTA_DATA(rta), data, data_length);
243 /* make sure also the padding at the end of the message is initialized */
244 memset(padding, '\0', (unsigned char *) m->hdr + m->hdr->nlmsg_len - (unsigned char *) padding);
249 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
251 struct ifaddrmsg *ifa;
254 assert_return(m, -EINVAL);
255 assert_return(data, -EINVAL);
257 sd_rtnl_message_get_type(m, &rtm_type);
266 return add_rtattr(m, type, data, strlen(data) + 1);
268 return add_rtattr(m, type, data, sizeof(uint32_t));
270 return add_rtattr(m, type, data, sizeof(uint32_t));
272 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
275 return add_rtattr(m, type, data, ETH_ALEN);
284 return add_rtattr(m, type, data, strlen(data) + 1);
289 ifa = NLMSG_DATA(m->hdr);
290 switch (ifa->ifa_family) {
292 return add_rtattr(m, type, data, sizeof(struct in_addr));
294 return add_rtattr(m, type, data, sizeof(struct in6_addr));
308 rtm = NLMSG_DATA(m->hdr);
309 switch (rtm->rtm_family) {
311 return add_rtattr(m, type, data, sizeof(struct in_addr));
313 return add_rtattr(m, type, data, sizeof(struct in6_addr));
321 return add_rtattr(m, type, data, sizeof(uint32_t));
330 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
331 assert_return(m, -EINVAL);
332 assert_return(data, -EINVAL);
334 if (!RTA_OK(m->next_rta, m->remaining_size))
337 *data = RTA_DATA(m->next_rta);
338 *type = m->next_rta->rta_type;
340 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
345 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
348 assert_return(m, -EINVAL);
349 assert_return(data, -EINVAL);
351 sd_rtnl_message_get_type(m, &rtm_type);
358 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
360 m->next_rta = IFLA_RTA(ifi);
361 m->remaining_size = IFLA_PAYLOAD(m->hdr);
368 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
370 m->next_rta = IFA_RTA(ifa);
371 m->remaining_size = IFA_PAYLOAD(m->hdr);
378 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
380 m->next_rta = RTM_RTA(rtm);
381 m->remaining_size = RTM_PAYLOAD(m->hdr);
388 return message_read(m, type, data);
391 uint32_t message_get_serial(sd_rtnl_message *m) {
394 return m->hdr->nlmsg_seq;
397 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
398 struct nlmsgerr *err;
400 assert_return(m, -EINVAL);
402 if (m->hdr->nlmsg_type != NLMSG_ERROR)
405 err = NLMSG_DATA(m->hdr);
410 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
414 m->hdr->nlmsg_seq = nl->serial++;
420 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
421 assert_return(rtnl, -EINVAL);
422 assert_return(need, -EINVAL);
424 /* ioctl(rtnl->fd, FIONREAD, &need)
425 Does not appear to work on netlink sockets. libnl uses
426 MSG_PEEK instead. I don't know if that is worth the
429 For now we simply use the maximum message size the kernel
430 may use (NLMSG_GOODSIZE), and then realloc to the actual
431 size after reading the message (hence avoiding huge memory
432 usage in case many small messages are kept around) */
440 /* returns the number of bytes sent, or a negative error code */
441 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
444 struct sockaddr_nl nl;
446 .nl.nl_family = AF_NETLINK,
450 assert_return(nl, -EINVAL);
451 assert_return(m, -EINVAL);
453 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
454 0, &addr.sa, sizeof(addr));
456 return (errno == EAGAIN) ? 0 : -errno;
461 /* On success, the number of bytes received is returned and *ret points to the received message
462 * which has a valid header and the correct size.
463 * If nothing useful was received 0 is returned.
464 * On failure, a negative error code is returned.
466 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
470 struct sockaddr_nl nl;
477 assert_return(nl, -EINVAL);
478 assert_return(ret, -EINVAL);
480 r = message_receive_need(nl, &need);
484 r = message_new(&m, need);
488 addr_len = sizeof(addr);
490 k = recvfrom(nl->fd, m->hdr, need,
491 0, &addr.sa, &addr_len);
493 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
495 k = -ECONNRESET; /* connection was closed by the kernel */
496 else if (addr_len != sizeof(addr.nl) ||
497 addr.nl.nl_family != AF_NETLINK)
498 k = -EIO; /* not a netlink message */
499 else if (addr.nl.nl_pid != 0)
500 k = 0; /* not from the kernel */
501 else if ((size_t) k < sizeof(struct nlmsghdr) ||
502 (size_t) k < m->hdr->nlmsg_len)
503 k = -EIO; /* too small (we do accept too big though) */
504 else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
505 k = 0; /* not for us */
508 switch (m->hdr->nlmsg_type) {
509 /* check that the size matches the message type */
511 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
517 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
523 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
530 k = 0; /* ignoring message of unknown type */
534 sd_rtnl_message_unref(m);
536 /* we probably allocated way too much memory, give it back */
537 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);