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 ||
133 nlmsg_type == RTM_SETLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
134 assert_return(index > 0, -EINVAL);
135 assert_return(ret, -EINVAL);
137 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
141 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
142 (*ret)->hdr->nlmsg_type = nlmsg_type;
144 ifi = NLMSG_DATA((*ret)->hdr);
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;
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;
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);
163 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
167 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
168 (*ret)->hdr->nlmsg_type = nlmsg_type;
170 ifa = NLMSG_DATA((*ret)->hdr);
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;
181 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
183 assert_se(REFCNT_INC(m->n_ref) >= 2);
188 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
189 if (m && REFCNT_DEC(m->n_ref) <= 0) {
197 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
198 assert_return(m, -EINVAL);
199 assert_return(type, -EINVAL);
201 *type = m->hdr->nlmsg_type;
206 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
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;
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);
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)
224 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
226 /* realloc to fit the new attribute */
227 new_hdr = realloc(m->hdr, message_length);
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;
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)
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);
250 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
252 struct ifaddrmsg *ifa;
255 assert_return(m, -EINVAL);
256 assert_return(data, -EINVAL);
258 sd_rtnl_message_get_type(m, &rtm_type);
269 return add_rtattr(m, type, data, strlen(data) + 1);
272 return add_rtattr(m, type, data, sizeof(uint32_t));
274 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
277 return add_rtattr(m, type, data, ETH_ALEN);
286 return add_rtattr(m, type, data, strlen(data) + 1);
291 ifa = NLMSG_DATA(m->hdr);
292 switch (ifa->ifa_family) {
294 return add_rtattr(m, type, data, sizeof(struct in_addr));
296 return add_rtattr(m, type, data, sizeof(struct in6_addr));
310 rtm = NLMSG_DATA(m->hdr);
311 switch (rtm->rtm_family) {
313 return add_rtattr(m, type, data, sizeof(struct in_addr));
315 return add_rtattr(m, type, data, sizeof(struct in6_addr));
323 return add_rtattr(m, type, data, sizeof(uint32_t));
332 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
333 assert_return(m, -EINVAL);
334 assert_return(data, -EINVAL);
336 if (!RTA_OK(m->next_rta, m->remaining_size))
339 *data = RTA_DATA(m->next_rta);
340 *type = m->next_rta->rta_type;
342 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
347 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
350 assert_return(m, -EINVAL);
351 assert_return(data, -EINVAL);
353 sd_rtnl_message_get_type(m, &rtm_type);
361 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
363 m->next_rta = IFLA_RTA(ifi);
364 m->remaining_size = IFLA_PAYLOAD(m->hdr);
371 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
373 m->next_rta = IFA_RTA(ifa);
374 m->remaining_size = IFA_PAYLOAD(m->hdr);
381 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
383 m->next_rta = RTM_RTA(rtm);
384 m->remaining_size = RTM_PAYLOAD(m->hdr);
391 return message_read(m, type, data);
394 uint32_t message_get_serial(sd_rtnl_message *m) {
397 return m->hdr->nlmsg_seq;
400 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
401 struct nlmsgerr *err;
403 assert_return(m, -EINVAL);
405 if (m->hdr->nlmsg_type != NLMSG_ERROR)
408 err = NLMSG_DATA(m->hdr);
413 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
417 m->hdr->nlmsg_seq = nl->serial++;
423 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
424 assert_return(rtnl, -EINVAL);
425 assert_return(need, -EINVAL);
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
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) */
443 /* returns the number of bytes sent, or a negative error code */
444 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
447 struct sockaddr_nl nl;
449 .nl.nl_family = AF_NETLINK,
453 assert_return(nl, -EINVAL);
454 assert_return(m, -EINVAL);
456 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
457 0, &addr.sa, sizeof(addr));
459 return (errno == EAGAIN) ? 0 : -errno;
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.
469 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
473 struct sockaddr_nl nl;
480 assert_return(nl, -EINVAL);
481 assert_return(ret, -EINVAL);
483 r = message_receive_need(nl, &need);
487 r = message_new(&m, need);
491 addr_len = sizeof(addr);
493 k = recvfrom(nl->fd, m->hdr, need,
494 0, &addr.sa, &addr_len);
496 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
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 */
511 switch (m->hdr->nlmsg_type) {
512 /* check that the size matches the message type */
514 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
521 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
527 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
534 k = 0; /* ignoring message of unknown type */
538 sd_rtnl_message_unref(m);
540 /* we probably allocated way too much memory, give it back */
541 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);