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 {
38 size_t container_offset; /* offset from hdr to container start */
39 size_t next_rta_offset; /* offset from hdr to next rta */
44 #define CURRENT_CONTAINER(m) ((m)->container_offset ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offset) : NULL)
45 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
46 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
48 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
51 assert_return(ret, -EINVAL);
52 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
54 m = new0(sd_rtnl_message, 1);
58 m->hdr = malloc0(initial_size);
64 m->n_ref = REFCNT_INIT;
66 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
74 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
80 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
84 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
85 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
86 (*ret)->hdr->nlmsg_seq = serial;
88 err = NLMSG_DATA((*ret)->hdr);
95 bool message_type_is_route(uint16_t type) {
106 bool message_type_is_link(uint16_t type) {
118 bool message_type_is_addr(uint16_t type) {
129 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
132 rtm = NLMSG_DATA(m->hdr);
134 rtm->rtm_dst_len = prefixlen;
139 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
140 sd_rtnl_message **ret) {
144 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
145 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
146 assert_return(ret, -EINVAL);
148 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
152 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
153 (*ret)->hdr->nlmsg_type = nlmsg_type;
154 if (nlmsg_type == RTM_NEWROUTE)
155 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
157 rtm = NLMSG_DATA((*ret)->hdr);
159 UPDATE_RTA(*ret, RTM_RTA(rtm));
161 rtm->rtm_family = rtm_family;
162 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
163 rtm->rtm_type = RTN_UNICAST;
164 rtm->rtm_table = RT_TABLE_MAIN;
165 rtm->rtm_protocol = RTPROT_BOOT;
170 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
171 struct ifinfomsg *ifi;
173 ifi = NLMSG_DATA(m->hdr);
175 ifi->ifi_flags = flags;
177 ifi->ifi_change = change;
179 ifi->ifi_change = 0xffffffff;
184 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
185 struct ifinfomsg *ifi;
187 ifi = NLMSG_DATA(m->hdr);
189 ifi->ifi_type = type;
194 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
195 struct ifinfomsg *ifi;
198 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
199 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
200 assert_return(ret, -EINVAL);
202 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
206 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
207 (*ret)->hdr->nlmsg_type = nlmsg_type;
208 if (nlmsg_type == RTM_NEWLINK)
209 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
211 ifi = NLMSG_DATA((*ret)->hdr);
213 ifi->ifi_family = AF_UNSPEC;
214 ifi->ifi_index = index;
216 UPDATE_RTA(*ret, IFLA_RTA(ifi));
221 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) {
222 struct ifaddrmsg *ifa;
225 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
226 assert_return(index > 0, -EINVAL);
227 assert_return(ret, -EINVAL);
229 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
233 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
234 (*ret)->hdr->nlmsg_type = nlmsg_type;
236 ifa = NLMSG_DATA((*ret)->hdr);
238 ifa->ifa_family = family;
239 ifa->ifa_prefixlen = prefixlen;
240 ifa->ifa_flags = flags;
241 ifa->ifa_scope = scope;
242 ifa->ifa_index = index;
244 UPDATE_RTA(*ret, IFA_RTA(ifa));
249 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
251 assert_se(REFCNT_INC(m->n_ref) >= 2);
256 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
257 if (m && REFCNT_DEC(m->n_ref) <= 0) {
265 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
266 assert_return(m, -EINVAL);
267 assert_return(type, -EINVAL);
269 *type = m->hdr->nlmsg_type;
274 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
275 struct ifinfomsg *ifi;
277 assert_return(m, -EINVAL);
278 assert_return(m->hdr, -EINVAL);
279 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
280 assert_return(ifindex, -EINVAL);
282 ifi = NLMSG_DATA(m->hdr);
284 *ifindex = ifi->ifi_index;
289 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
290 struct ifinfomsg *ifi;
292 assert_return(m, -EINVAL);
293 assert_return(m->hdr, -EINVAL);
294 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
295 assert_return(flags, -EINVAL);
297 ifi = NLMSG_DATA(m->hdr);
299 *flags = ifi->ifi_flags;
304 /* If successful the updated message will be correctly aligned, if
305 unsuccessful the old message is untouched. */
306 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
307 uint32_t rta_length, message_length;
308 struct nlmsghdr *new_hdr;
314 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
315 assert(!data || data_length > 0);
317 /* get the size of the new rta attribute (with padding at the end) */
318 rta_length = RTA_LENGTH(data_length);
320 /* get the new message size (with padding at the end) */
321 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
323 /* realloc to fit the new attribute */
324 new_hdr = realloc(m->hdr, message_length);
329 /* get pointer to the attribute we are about to add */
330 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
332 /* if we are inside a container, extend it */
333 if (CURRENT_CONTAINER(m))
334 CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
336 /* fill in the attribute */
337 rta->rta_type = type;
338 rta->rta_len = rta_length;
340 /* this is the start of a new container */
341 m->container_offset = m->hdr->nlmsg_len;
343 /* we don't deal with the case where the user lies about the type
344 * and gives us too little data (so don't do that)
346 padding = mempcpy(RTA_DATA(rta), data, data_length);
347 /* make sure also the padding at the end of the message is initialized */
349 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
352 /* update message size */
353 m->hdr->nlmsg_len = message_length;
358 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
362 assert_return(m, -EINVAL);
363 assert_return(data, -EINVAL);
365 r = sd_rtnl_message_get_type(m, &rtm_type);
369 /* check that the type is correct */
375 if (CURRENT_CONTAINER(m)) {
376 if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
377 type != IFLA_INFO_KIND)
393 if (type != IFA_LABEL)
400 r = add_rtattr(m, type, data, strlen(data) + 1);
407 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
411 assert_return(m, -EINVAL);
413 r = sd_rtnl_message_get_type(m, &rtm_type);
417 /* check that the type is correct */
449 r = add_rtattr(m, type, &data, sizeof(uint32_t));
456 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
457 struct ifaddrmsg *ifa;
462 assert_return(m, -EINVAL);
463 assert_return(data, -EINVAL);
465 r = sd_rtnl_message_get_type(m, &rtm_type);
469 /* check that the type is correct */
479 ifa = NLMSG_DATA(m->hdr);
481 if (ifa->ifa_family != AF_INET)
496 rtm = NLMSG_DATA(m->hdr);
498 if (rtm->rtm_family != AF_INET)
510 r = add_rtattr(m, type, data, sizeof(struct in_addr));
517 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
518 struct ifaddrmsg *ifa;
523 assert_return(m, -EINVAL);
524 assert_return(data, -EINVAL);
526 r = sd_rtnl_message_get_type(m, &rtm_type);
530 /* check that the type is correct */
540 ifa = NLMSG_DATA(m->hdr);
542 if (ifa->ifa_family != AF_INET6)
557 rtm = NLMSG_DATA(m->hdr);
559 if (rtm->rtm_family != AF_INET6)
570 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
577 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
581 assert_return(m, -EINVAL);
582 assert_return(data, -EINVAL);
584 sd_rtnl_message_get_type(m, &rtm_type);
603 r = add_rtattr(m, type, data, ETH_ALEN);
610 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
613 assert_return(m, -EINVAL);
614 assert_return(!CURRENT_CONTAINER(m), -EINVAL);
616 sd_rtnl_message_get_type(m, &rtm_type);
618 if (message_type_is_link(rtm_type)) {
619 if (type == IFLA_LINKINFO)
620 return add_rtattr(m, type, NULL, 0);
629 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
630 assert_return(m, -EINVAL);
631 assert_return(CURRENT_CONTAINER(m), -EINVAL);
633 m->container_offset = 0;
638 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
639 size_t remaining_size;
644 assert(m->next_rta_offset);
648 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
650 if (!RTA_OK(NEXT_RTA(m), remaining_size))
653 /* make sure we don't try to read a container
654 * TODO: add support for entering containers for reading */
655 r = sd_rtnl_message_get_type(m, &rtm_type);
659 if (message_type_is_link(rtm_type) &&
660 NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
663 *data = RTA_DATA(NEXT_RTA(m));
664 *type = NEXT_RTA(m)->rta_type;
666 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
671 uint32_t message_get_serial(sd_rtnl_message *m) {
675 return m->hdr->nlmsg_seq;
678 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
679 struct nlmsgerr *err;
681 assert_return(m, -EINVAL);
682 assert_return(m->hdr, -EINVAL);
684 if (m->hdr->nlmsg_type != NLMSG_ERROR)
687 err = NLMSG_DATA(m->hdr);
692 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
700 m->hdr->nlmsg_seq = nl->serial++;
706 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
710 /* ioctl(rtnl->fd, FIONREAD, &need)
711 Does not appear to work on netlink sockets. libnl uses
712 MSG_PEEK instead. I don't know if that is worth the
715 For now we simply use the maximum message size the kernel
716 may use (NLMSG_GOODSIZE), and then realloc to the actual
717 size after reading the message (hence avoiding huge memory
718 usage in case many small messages are kept around) */
726 /* returns the number of bytes sent, or a negative error code */
727 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
730 struct sockaddr_nl nl;
732 .nl.nl_family = AF_NETLINK,
740 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
741 0, &addr.sa, sizeof(addr));
743 return (errno == EAGAIN) ? 0 : -errno;
748 /* On success, the number of bytes received is returned and *ret points to the received message
749 * which has a valid header and the correct size.
750 * If nothing useful was received 0 is returned.
751 * On failure, a negative error code is returned.
753 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
757 struct sockaddr_nl nl;
767 r = message_receive_need(nl, &need);
771 r = message_new(&m, need);
775 addr_len = sizeof(addr);
777 k = recvfrom(nl->fd, m->hdr, need,
778 0, &addr.sa, &addr_len);
780 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
782 k = -ECONNRESET; /* connection was closed by the kernel */
783 else if (addr_len != sizeof(addr.nl) ||
784 addr.nl.nl_family != AF_NETLINK)
785 k = -EIO; /* not a netlink message */
786 else if (addr.nl.nl_pid != 0)
787 k = 0; /* not from the kernel */
788 else if ((size_t) k < sizeof(struct nlmsghdr) ||
789 (size_t) k < m->hdr->nlmsg_len)
790 k = -EIO; /* too small (we do accept too big though) */
791 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
792 k = 0; /* not broadcast and not for us */
795 switch (m->hdr->nlmsg_type) {
796 struct ifinfomsg *ifi;
797 struct ifaddrmsg *ifa;
800 /* check that the size matches the message type */
802 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
809 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
812 ifi = NLMSG_DATA(m->hdr);
813 UPDATE_RTA(m, IFLA_RTA(ifi));
819 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
822 ifa = NLMSG_DATA(m->hdr);
823 UPDATE_RTA(m, IFA_RTA(ifa));
829 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
832 rtm = NLMSG_DATA(m->hdr);
833 UPDATE_RTA(m, RTM_RTA(rtm));
840 k = 0; /* ignoring message of unknown type */
844 sd_rtnl_message_unref(m);
846 /* we probably allocated way too much memory, give it back */
847 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
854 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
855 struct ifinfomsg *ifi;
856 struct ifaddrmsg *ifa;
859 assert_return(m, -EINVAL);
860 assert_return(m->hdr, -EINVAL);
862 switch(m->hdr->nlmsg_type) {
867 ifi = NLMSG_DATA(m->hdr);
868 UPDATE_RTA(m, IFLA_RTA(ifi));
874 ifa = NLMSG_DATA(m->hdr);
875 UPDATE_RTA(m, IFA_RTA(ifa));
881 rtm = NLMSG_DATA(m->hdr);
882 UPDATE_RTA(m, RTM_RTA(rtm));