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 assert_return(m, -EINVAL);
133 assert_return(m->hdr, -EINVAL);
134 assert_return(message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
136 rtm = NLMSG_DATA(m->hdr);
138 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
139 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
142 rtm->rtm_dst_len = prefixlen;
147 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
148 sd_rtnl_message **ret) {
152 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
153 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
154 assert_return(ret, -EINVAL);
156 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
160 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
161 (*ret)->hdr->nlmsg_type = nlmsg_type;
162 if (nlmsg_type == RTM_NEWROUTE)
163 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
165 rtm = NLMSG_DATA((*ret)->hdr);
167 UPDATE_RTA(*ret, RTM_RTA(rtm));
169 rtm->rtm_family = rtm_family;
170 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
171 rtm->rtm_type = RTN_UNICAST;
172 rtm->rtm_table = RT_TABLE_MAIN;
173 rtm->rtm_protocol = RTPROT_BOOT;
178 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
179 struct ifinfomsg *ifi;
181 assert_return(m, -EINVAL);
182 assert_return(m->hdr, -EINVAL);
183 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
185 ifi = NLMSG_DATA(m->hdr);
187 ifi->ifi_flags = flags;
189 ifi->ifi_change = change;
191 ifi->ifi_change = 0xffffffff;
196 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
197 struct ifinfomsg *ifi;
199 assert_return(m, -EINVAL);
200 assert_return(m->hdr, -EINVAL);
201 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
203 ifi = NLMSG_DATA(m->hdr);
205 ifi->ifi_type = type;
210 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
211 struct ifinfomsg *ifi;
214 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
215 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
216 assert_return(ret, -EINVAL);
218 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
222 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
223 (*ret)->hdr->nlmsg_type = nlmsg_type;
224 if (nlmsg_type == RTM_NEWLINK)
225 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
227 ifi = NLMSG_DATA((*ret)->hdr);
229 ifi->ifi_family = AF_UNSPEC;
230 ifi->ifi_index = index;
232 UPDATE_RTA(*ret, IFLA_RTA(ifi));
237 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
238 struct ifaddrmsg *ifa;
240 assert_return(m, -EINVAL);
241 assert_return(m->hdr, -EINVAL);
242 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
244 ifa = NLMSG_DATA(m->hdr);
246 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
247 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
250 ifa->ifa_prefixlen = prefixlen;
255 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
256 struct ifaddrmsg *ifa;
258 assert_return(m, -EINVAL);
259 assert_return(m->hdr, -EINVAL);
260 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
262 ifa = NLMSG_DATA(m->hdr);
264 ifa->ifa_flags = flags;
269 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
270 struct ifaddrmsg *ifa;
272 assert_return(m, -EINVAL);
273 assert_return(m->hdr, -EINVAL);
274 assert_return(message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
276 ifa = NLMSG_DATA(m->hdr);
278 ifa->ifa_scope = scope;
283 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family,
284 sd_rtnl_message **ret) {
285 struct ifaddrmsg *ifa;
288 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
289 assert_return(index > 0, -EINVAL);
290 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
291 assert_return(ret, -EINVAL);
293 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
297 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
298 (*ret)->hdr->nlmsg_type = nlmsg_type;
300 ifa = NLMSG_DATA((*ret)->hdr);
302 ifa->ifa_index = index;
303 ifa->ifa_family = family;
304 if (family == AF_INET)
305 ifa->ifa_prefixlen = 32;
306 else if (family == AF_INET6)
307 ifa->ifa_prefixlen = 128;
309 UPDATE_RTA(*ret, IFA_RTA(ifa));
314 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
316 assert_se(REFCNT_INC(m->n_ref) >= 2);
321 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
322 if (m && REFCNT_DEC(m->n_ref) <= 0) {
330 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
331 assert_return(m, -EINVAL);
332 assert_return(type, -EINVAL);
334 *type = m->hdr->nlmsg_type;
339 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
340 struct ifinfomsg *ifi;
342 assert_return(m, -EINVAL);
343 assert_return(m->hdr, -EINVAL);
344 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
345 assert_return(ifindex, -EINVAL);
347 ifi = NLMSG_DATA(m->hdr);
349 *ifindex = ifi->ifi_index;
354 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
355 struct ifinfomsg *ifi;
357 assert_return(m, -EINVAL);
358 assert_return(m->hdr, -EINVAL);
359 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
360 assert_return(flags, -EINVAL);
362 ifi = NLMSG_DATA(m->hdr);
364 *flags = ifi->ifi_flags;
369 /* If successful the updated message will be correctly aligned, if
370 unsuccessful the old message is untouched. */
371 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
372 uint32_t rta_length, message_length;
373 struct nlmsghdr *new_hdr;
379 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
380 assert(!data || data_length > 0);
382 /* get the size of the new rta attribute (with padding at the end) */
383 rta_length = RTA_LENGTH(data_length);
385 /* get the new message size (with padding at the end) */
386 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
388 /* realloc to fit the new attribute */
389 new_hdr = realloc(m->hdr, message_length);
394 /* get pointer to the attribute we are about to add */
395 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
397 /* if we are inside a container, extend it */
398 if (CURRENT_CONTAINER(m))
399 CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
401 /* fill in the attribute */
402 rta->rta_type = type;
403 rta->rta_len = rta_length;
405 /* this is the start of a new container */
406 m->container_offset = m->hdr->nlmsg_len;
408 /* we don't deal with the case where the user lies about the type
409 * and gives us too little data (so don't do that)
411 padding = mempcpy(RTA_DATA(rta), data, data_length);
412 /* make sure also the padding at the end of the message is initialized */
414 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
417 /* update message size */
418 m->hdr->nlmsg_len = message_length;
423 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
427 assert_return(m, -EINVAL);
428 assert_return(data, -EINVAL);
430 r = sd_rtnl_message_get_type(m, &rtm_type);
434 /* check that the type is correct */
440 if (CURRENT_CONTAINER(m)) {
441 if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
442 type != IFLA_INFO_KIND)
458 if (type != IFA_LABEL)
465 r = add_rtattr(m, type, data, strlen(data) + 1);
472 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
476 assert_return(m, -EINVAL);
478 r = sd_rtnl_message_get_type(m, &rtm_type);
482 /* check that the type is correct */
499 r = add_rtattr(m, type, &data, sizeof(uint16_t));
506 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
510 assert_return(m, -EINVAL);
512 r = sd_rtnl_message_get_type(m, &rtm_type);
516 /* check that the type is correct */
548 r = add_rtattr(m, type, &data, sizeof(uint32_t));
555 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
556 struct ifaddrmsg *ifa;
561 assert_return(m, -EINVAL);
562 assert_return(data, -EINVAL);
564 r = sd_rtnl_message_get_type(m, &rtm_type);
568 /* check that the type is correct */
578 ifa = NLMSG_DATA(m->hdr);
580 if (ifa->ifa_family != AF_INET)
595 rtm = NLMSG_DATA(m->hdr);
597 if (rtm->rtm_family != AF_INET)
609 r = add_rtattr(m, type, data, sizeof(struct in_addr));
616 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
617 struct ifaddrmsg *ifa;
622 assert_return(m, -EINVAL);
623 assert_return(data, -EINVAL);
625 r = sd_rtnl_message_get_type(m, &rtm_type);
629 /* check that the type is correct */
639 ifa = NLMSG_DATA(m->hdr);
641 if (ifa->ifa_family != AF_INET6)
656 rtm = NLMSG_DATA(m->hdr);
658 if (rtm->rtm_family != AF_INET6)
669 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
676 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
680 assert_return(m, -EINVAL);
681 assert_return(data, -EINVAL);
683 sd_rtnl_message_get_type(m, &rtm_type);
702 r = add_rtattr(m, type, data, ETH_ALEN);
709 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
712 assert_return(m, -EINVAL);
713 assert_return(!CURRENT_CONTAINER(m), -EINVAL);
715 sd_rtnl_message_get_type(m, &rtm_type);
717 if (message_type_is_link(rtm_type)) {
718 if (type == IFLA_LINKINFO)
719 return add_rtattr(m, type, NULL, 0);
728 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
729 assert_return(m, -EINVAL);
730 assert_return(CURRENT_CONTAINER(m), -EINVAL);
732 m->container_offset = 0;
737 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
738 size_t remaining_size;
743 assert(m->next_rta_offset);
747 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
749 if (!RTA_OK(NEXT_RTA(m), remaining_size))
752 /* make sure we don't try to read a container
753 * TODO: add support for entering containers for reading */
754 r = sd_rtnl_message_get_type(m, &rtm_type);
758 if (message_type_is_link(rtm_type) &&
759 NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
762 *data = RTA_DATA(NEXT_RTA(m));
763 *type = NEXT_RTA(m)->rta_type;
765 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
770 uint32_t message_get_serial(sd_rtnl_message *m) {
774 return m->hdr->nlmsg_seq;
777 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
778 struct nlmsgerr *err;
780 assert_return(m, -EINVAL);
781 assert_return(m->hdr, -EINVAL);
783 if (m->hdr->nlmsg_type != NLMSG_ERROR)
786 err = NLMSG_DATA(m->hdr);
791 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
799 m->hdr->nlmsg_seq = nl->serial++;
805 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
809 /* ioctl(rtnl->fd, FIONREAD, &need)
810 Does not appear to work on netlink sockets. libnl uses
811 MSG_PEEK instead. I don't know if that is worth the
814 For now we simply use the maximum message size the kernel
815 may use (NLMSG_GOODSIZE), and then realloc to the actual
816 size after reading the message (hence avoiding huge memory
817 usage in case many small messages are kept around) */
825 /* returns the number of bytes sent, or a negative error code */
826 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
829 struct sockaddr_nl nl;
831 .nl.nl_family = AF_NETLINK,
839 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
840 0, &addr.sa, sizeof(addr));
842 return (errno == EAGAIN) ? 0 : -errno;
847 /* On success, the number of bytes received is returned and *ret points to the received message
848 * which has a valid header and the correct size.
849 * If nothing useful was received 0 is returned.
850 * On failure, a negative error code is returned.
852 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
856 struct sockaddr_nl nl;
866 r = message_receive_need(nl, &need);
870 r = message_new(&m, need);
874 addr_len = sizeof(addr);
876 k = recvfrom(nl->fd, m->hdr, need,
877 0, &addr.sa, &addr_len);
879 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
881 k = -ECONNRESET; /* connection was closed by the kernel */
882 else if (addr_len != sizeof(addr.nl) ||
883 addr.nl.nl_family != AF_NETLINK)
884 k = -EIO; /* not a netlink message */
885 else if (addr.nl.nl_pid != 0)
886 k = 0; /* not from the kernel */
887 else if ((size_t) k < sizeof(struct nlmsghdr) ||
888 (size_t) k < m->hdr->nlmsg_len)
889 k = -EIO; /* too small (we do accept too big though) */
890 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
891 k = 0; /* not broadcast and not for us */
894 switch (m->hdr->nlmsg_type) {
895 struct ifinfomsg *ifi;
896 struct ifaddrmsg *ifa;
899 /* check that the size matches the message type */
901 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
908 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
911 ifi = NLMSG_DATA(m->hdr);
912 UPDATE_RTA(m, IFLA_RTA(ifi));
918 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
921 ifa = NLMSG_DATA(m->hdr);
922 UPDATE_RTA(m, IFA_RTA(ifa));
928 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
931 rtm = NLMSG_DATA(m->hdr);
932 UPDATE_RTA(m, RTM_RTA(rtm));
939 k = 0; /* ignoring message of unknown type */
943 sd_rtnl_message_unref(m);
945 /* we probably allocated way too much memory, give it back */
946 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
953 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
954 struct ifinfomsg *ifi;
955 struct ifaddrmsg *ifa;
958 assert_return(m, -EINVAL);
959 assert_return(m->hdr, -EINVAL);
961 switch(m->hdr->nlmsg_type) {
966 ifi = NLMSG_DATA(m->hdr);
967 UPDATE_RTA(m, IFLA_RTA(ifi));
973 ifa = NLMSG_DATA(m->hdr);
974 UPDATE_RTA(m, IFA_RTA(ifa));
980 rtm = NLMSG_DATA(m->hdr);
981 UPDATE_RTA(m, RTM_RTA(rtm));