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 *current_container;
41 struct rtattr *next_rta;
42 size_t remaining_size;
47 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
50 assert_return(ret, -EINVAL);
51 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
53 m = new0(sd_rtnl_message, 1);
57 m->hdr = malloc0(initial_size);
63 m->n_ref = REFCNT_INIT;
65 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
73 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
79 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
83 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
84 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
85 (*ret)->hdr->nlmsg_seq = serial;
87 err = NLMSG_DATA((*ret)->hdr);
94 bool message_type_is_route(uint16_t type) {
105 bool message_type_is_link(uint16_t type) {
117 bool message_type_is_addr(uint16_t type) {
128 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
131 rtm = NLMSG_DATA(m->hdr);
133 rtm->rtm_dst_len = prefixlen;
138 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
139 sd_rtnl_message **ret) {
143 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
144 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
145 assert_return(ret, -EINVAL);
147 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
151 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
152 (*ret)->hdr->nlmsg_type = nlmsg_type;
153 if (nlmsg_type == RTM_NEWROUTE)
154 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
156 rtm = NLMSG_DATA((*ret)->hdr);
158 rtm->rtm_family = rtm_family;
159 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
160 rtm->rtm_type = RTN_UNICAST;
161 rtm->rtm_table = RT_TABLE_MAIN;
162 rtm->rtm_protocol = RTPROT_BOOT;
167 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
168 struct ifinfomsg *ifi;
170 ifi = NLMSG_DATA(m->hdr);
172 ifi->ifi_flags = flags;
177 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
178 struct ifinfomsg *ifi;
180 ifi = NLMSG_DATA(m->hdr);
182 ifi->ifi_type = type;
187 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
188 struct ifinfomsg *ifi;
191 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
192 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
193 assert_return(ret, -EINVAL);
195 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
199 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
200 (*ret)->hdr->nlmsg_type = nlmsg_type;
201 if (nlmsg_type == RTM_NEWLINK)
202 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
204 ifi = NLMSG_DATA((*ret)->hdr);
206 ifi->ifi_family = AF_UNSPEC;
207 ifi->ifi_index = index;
208 ifi->ifi_change = 0xffffffff;
213 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) {
214 struct ifaddrmsg *ifa;
217 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
218 assert_return(index > 0, -EINVAL);
219 assert_return(ret, -EINVAL);
221 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
225 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
226 (*ret)->hdr->nlmsg_type = nlmsg_type;
228 ifa = NLMSG_DATA((*ret)->hdr);
230 ifa->ifa_family = family;
231 ifa->ifa_prefixlen = prefixlen;
232 ifa->ifa_flags = flags;
233 ifa->ifa_scope = scope;
234 ifa->ifa_index = index;
239 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
241 assert_se(REFCNT_INC(m->n_ref) >= 2);
246 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
247 if (m && REFCNT_DEC(m->n_ref) <= 0) {
255 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
256 assert_return(m, -EINVAL);
257 assert_return(type, -EINVAL);
259 *type = m->hdr->nlmsg_type;
264 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
265 struct ifinfomsg *ifi;
267 assert_return(m, -EINVAL);
268 assert_return(m->hdr, -EINVAL);
269 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
270 assert_return(ifindex, -EINVAL);
272 ifi = NLMSG_DATA(m->hdr);
274 *ifindex = ifi->ifi_index;
279 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
280 struct ifinfomsg *ifi;
282 assert_return(m, -EINVAL);
283 assert_return(m->hdr, -EINVAL);
284 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
285 assert_return(flags, -EINVAL);
287 ifi = NLMSG_DATA(m->hdr);
289 *flags = ifi->ifi_flags;
294 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
296 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
297 uint32_t rta_length, message_length;
298 struct nlmsghdr *new_hdr;
304 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
305 assert(!data || data_length > 0);
307 /* get the size of the new rta attribute (with padding at the end) */
308 rta_length = RTA_LENGTH(data_length);
309 /* get the new message size (with padding at the end)
311 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
313 /* realloc to fit the new attribute */
314 new_hdr = realloc(m->hdr, message_length);
319 /* get pointer to the attribute we are about to add */
320 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
321 /* update message size */
322 m->hdr->nlmsg_len = message_length;
324 /* we are inside a container, extend it */
325 if (m->current_container)
326 m->current_container->rta_len = (unsigned char *) m->hdr +
328 (unsigned char *) m->current_container;
330 /* fill in the attribute */
331 rta->rta_type = type;
332 rta->rta_len = rta_length;
334 /* this is a container, set pointer */
335 m->current_container = rta;
337 /* we don't deal with the case where the user lies about the type
338 * and gives us too little data (so don't do that)
340 padding = mempcpy(RTA_DATA(rta), data, data_length);
341 /* make sure also the padding at the end of the message is initialized */
342 memset(padding, '\0', (unsigned char *) m->hdr +
344 (unsigned char *) padding);
350 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
352 struct ifaddrmsg *ifa;
355 assert_return(m, -EINVAL);
356 assert_return(data, -EINVAL);
358 sd_rtnl_message_get_type(m, &rtm_type);
360 if (m->current_container) {
366 switch (m->current_container->rta_type) {
370 return add_rtattr(m, type, data, strlen(data) + 1);
391 return add_rtattr(m, type, data, strlen(data) + 1);
395 return add_rtattr(m, type, data, sizeof(uint32_t));
397 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
400 return add_rtattr(m, type, data, ETH_ALEN);
409 return add_rtattr(m, type, data, strlen(data) + 1);
414 ifa = NLMSG_DATA(m->hdr);
415 switch (ifa->ifa_family) {
417 return add_rtattr(m, type, data, sizeof(struct in_addr));
419 return add_rtattr(m, type, data, sizeof(struct in6_addr));
433 rtm = NLMSG_DATA(m->hdr);
434 switch (rtm->rtm_family) {
436 return add_rtattr(m, type, data, sizeof(struct in_addr));
438 return add_rtattr(m, type, data, sizeof(struct in6_addr));
446 return add_rtattr(m, type, data, sizeof(uint32_t));
455 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
458 assert_return(m, -EINVAL);
459 assert_return(!m->current_container, -EINVAL);
461 sd_rtnl_message_get_type(m, &rtm_type);
463 if (message_type_is_link(rtm_type)) {
464 if (type == IFLA_LINKINFO)
465 return add_rtattr(m, type, NULL, 0);
474 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
475 assert_return(m, -EINVAL);
476 assert_return(m->current_container, -EINVAL);
478 m->current_container = NULL;
483 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
492 if (!RTA_OK(m->next_rta, m->remaining_size))
495 /* make sure we don't try to read a container
496 * TODO: add support for entering containers for reading */
497 r = sd_rtnl_message_get_type(m, &rtm_type);
506 if (m->next_rta->rta_type == IFLA_LINKINFO) {
511 *data = RTA_DATA(m->next_rta);
512 *type = m->next_rta->rta_type;
514 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
519 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
523 assert_return(m, -EINVAL);
524 assert_return(data, -EINVAL);
526 r = sd_rtnl_message_get_type(m, &rtm_type);
536 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
538 m->next_rta = IFLA_RTA(ifi);
539 m->remaining_size = IFLA_PAYLOAD(m->hdr);
546 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
548 m->next_rta = IFA_RTA(ifa);
549 m->remaining_size = IFA_PAYLOAD(m->hdr);
556 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
558 m->next_rta = RTM_RTA(rtm);
559 m->remaining_size = RTM_PAYLOAD(m->hdr);
566 return message_read(m, type, data);
569 uint32_t message_get_serial(sd_rtnl_message *m) {
573 return m->hdr->nlmsg_seq;
576 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
577 struct nlmsgerr *err;
579 assert_return(m, -EINVAL);
580 assert_return(m->hdr, -EINVAL);
582 if (m->hdr->nlmsg_type != NLMSG_ERROR)
585 err = NLMSG_DATA(m->hdr);
590 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
598 m->hdr->nlmsg_seq = nl->serial++;
604 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
608 /* ioctl(rtnl->fd, FIONREAD, &need)
609 Does not appear to work on netlink sockets. libnl uses
610 MSG_PEEK instead. I don't know if that is worth the
613 For now we simply use the maximum message size the kernel
614 may use (NLMSG_GOODSIZE), and then realloc to the actual
615 size after reading the message (hence avoiding huge memory
616 usage in case many small messages are kept around) */
624 /* returns the number of bytes sent, or a negative error code */
625 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
628 struct sockaddr_nl nl;
630 .nl.nl_family = AF_NETLINK,
638 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
639 0, &addr.sa, sizeof(addr));
641 return (errno == EAGAIN) ? 0 : -errno;
646 /* On success, the number of bytes received is returned and *ret points to the received message
647 * which has a valid header and the correct size.
648 * If nothing useful was received 0 is returned.
649 * On failure, a negative error code is returned.
651 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
655 struct sockaddr_nl nl;
665 r = message_receive_need(nl, &need);
669 r = message_new(&m, need);
673 addr_len = sizeof(addr);
675 k = recvfrom(nl->fd, m->hdr, need,
676 0, &addr.sa, &addr_len);
678 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
680 k = -ECONNRESET; /* connection was closed by the kernel */
681 else if (addr_len != sizeof(addr.nl) ||
682 addr.nl.nl_family != AF_NETLINK)
683 k = -EIO; /* not a netlink message */
684 else if (addr.nl.nl_pid != 0)
685 k = 0; /* not from the kernel */
686 else if ((size_t) k < sizeof(struct nlmsghdr) ||
687 (size_t) k < m->hdr->nlmsg_len)
688 k = -EIO; /* too small (we do accept too big though) */
689 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
690 k = 0; /* not broadcast and not for us */
693 switch (m->hdr->nlmsg_type) {
694 /* check that the size matches the message type */
696 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
703 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
709 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
715 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
722 k = 0; /* ignoring message of unknown type */
726 sd_rtnl_message_unref(m);
728 /* we probably allocated way too much memory, give it back */
729 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);