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) {
171 struct ifinfomsg *ifi;
173 ifi = NLMSG_DATA(m->hdr);
175 ifi->ifi_flags = flags;
176 ifi->ifi_change = 0xffffffff;
181 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
182 struct ifinfomsg *ifi;
184 ifi = NLMSG_DATA(m->hdr);
186 ifi->ifi_type = type;
191 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
192 struct ifinfomsg *ifi;
195 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
196 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
197 assert_return(ret, -EINVAL);
199 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
203 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
204 (*ret)->hdr->nlmsg_type = nlmsg_type;
205 if (nlmsg_type == RTM_NEWLINK)
206 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
208 ifi = NLMSG_DATA((*ret)->hdr);
210 ifi->ifi_family = AF_UNSPEC;
211 ifi->ifi_index = index;
213 UPDATE_RTA(*ret, IFLA_RTA(ifi));
218 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) {
219 struct ifaddrmsg *ifa;
222 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
223 assert_return(index > 0, -EINVAL);
224 assert_return(ret, -EINVAL);
226 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
230 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
231 (*ret)->hdr->nlmsg_type = nlmsg_type;
233 ifa = NLMSG_DATA((*ret)->hdr);
235 ifa->ifa_family = family;
236 ifa->ifa_prefixlen = prefixlen;
237 ifa->ifa_flags = flags;
238 ifa->ifa_scope = scope;
239 ifa->ifa_index = index;
241 UPDATE_RTA(*ret, IFA_RTA(ifa));
246 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
248 assert_se(REFCNT_INC(m->n_ref) >= 2);
253 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
254 if (m && REFCNT_DEC(m->n_ref) <= 0) {
262 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
263 assert_return(m, -EINVAL);
264 assert_return(type, -EINVAL);
266 *type = m->hdr->nlmsg_type;
271 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
272 struct ifinfomsg *ifi;
274 assert_return(m, -EINVAL);
275 assert_return(m->hdr, -EINVAL);
276 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
277 assert_return(ifindex, -EINVAL);
279 ifi = NLMSG_DATA(m->hdr);
281 *ifindex = ifi->ifi_index;
286 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
287 struct ifinfomsg *ifi;
289 assert_return(m, -EINVAL);
290 assert_return(m->hdr, -EINVAL);
291 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
292 assert_return(flags, -EINVAL);
294 ifi = NLMSG_DATA(m->hdr);
296 *flags = ifi->ifi_flags;
301 /* If successful the updated message will be correctly aligned, if
302 unsuccessful the old message is untouched. */
303 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
304 uint32_t rta_length, message_length;
305 struct nlmsghdr *new_hdr;
311 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
312 assert(!data || data_length > 0);
314 /* get the size of the new rta attribute (with padding at the end) */
315 rta_length = RTA_LENGTH(data_length);
317 /* get the new message size (with padding at the end) */
318 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
320 /* realloc to fit the new attribute */
321 new_hdr = realloc(m->hdr, message_length);
326 /* get pointer to the attribute we are about to add */
327 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
329 /* if we are inside a container, extend it */
330 if (CURRENT_CONTAINER(m))
331 CURRENT_CONTAINER(m)->rta_len += message_length - m->hdr->nlmsg_len;
333 /* fill in the attribute */
334 rta->rta_type = type;
335 rta->rta_len = rta_length;
337 /* this is the start of a new container */
338 m->container_offset = m->hdr->nlmsg_len;
340 /* we don't deal with the case where the user lies about the type
341 * and gives us too little data (so don't do that)
343 padding = mempcpy(RTA_DATA(rta), data, data_length);
344 /* make sure also the padding at the end of the message is initialized */
346 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
349 /* update message size */
350 m->hdr->nlmsg_len = message_length;
355 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
359 assert_return(m, -EINVAL);
360 assert_return(data, -EINVAL);
362 r = sd_rtnl_message_get_type(m, &rtm_type);
366 /* check that the type is correct */
372 if (CURRENT_CONTAINER(m)) {
373 if (CURRENT_CONTAINER(m)->rta_type != IFLA_LINKINFO ||
374 type != IFLA_INFO_KIND)
390 if (type != IFA_LABEL)
397 r = add_rtattr(m, type, data, strlen(data) + 1);
404 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
408 assert_return(m, -EINVAL);
410 r = sd_rtnl_message_get_type(m, &rtm_type);
414 /* check that the type is correct */
446 r = add_rtattr(m, type, &data, sizeof(uint32_t));
453 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
454 struct ifaddrmsg *ifa;
459 assert_return(m, -EINVAL);
460 assert_return(data, -EINVAL);
462 r = sd_rtnl_message_get_type(m, &rtm_type);
466 /* check that the type is correct */
476 ifa = NLMSG_DATA(m->hdr);
478 if (ifa->ifa_family != AF_INET)
493 rtm = NLMSG_DATA(m->hdr);
495 if (rtm->rtm_family != AF_INET)
507 r = add_rtattr(m, type, data, sizeof(struct in_addr));
514 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
515 struct ifaddrmsg *ifa;
520 assert_return(m, -EINVAL);
521 assert_return(data, -EINVAL);
523 r = sd_rtnl_message_get_type(m, &rtm_type);
527 /* check that the type is correct */
537 ifa = NLMSG_DATA(m->hdr);
539 if (ifa->ifa_family != AF_INET6)
554 rtm = NLMSG_DATA(m->hdr);
556 if (rtm->rtm_family != AF_INET6)
567 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
574 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
578 assert_return(m, -EINVAL);
579 assert_return(data, -EINVAL);
581 sd_rtnl_message_get_type(m, &rtm_type);
600 r = add_rtattr(m, type, data, ETH_ALEN);
607 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
610 assert_return(m, -EINVAL);
611 assert_return(!CURRENT_CONTAINER(m), -EINVAL);
613 sd_rtnl_message_get_type(m, &rtm_type);
615 if (message_type_is_link(rtm_type)) {
616 if (type == IFLA_LINKINFO)
617 return add_rtattr(m, type, NULL, 0);
626 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
627 assert_return(m, -EINVAL);
628 assert_return(CURRENT_CONTAINER(m), -EINVAL);
630 m->container_offset = 0;
635 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
636 size_t remaining_size;
641 assert(m->next_rta_offset);
645 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
647 if (!RTA_OK(NEXT_RTA(m), remaining_size))
650 /* make sure we don't try to read a container
651 * TODO: add support for entering containers for reading */
652 r = sd_rtnl_message_get_type(m, &rtm_type);
656 if (message_type_is_link(rtm_type) &&
657 NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
660 *data = RTA_DATA(NEXT_RTA(m));
661 *type = NEXT_RTA(m)->rta_type;
663 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
668 uint32_t message_get_serial(sd_rtnl_message *m) {
672 return m->hdr->nlmsg_seq;
675 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
676 struct nlmsgerr *err;
678 assert_return(m, -EINVAL);
679 assert_return(m->hdr, -EINVAL);
681 if (m->hdr->nlmsg_type != NLMSG_ERROR)
684 err = NLMSG_DATA(m->hdr);
689 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
697 m->hdr->nlmsg_seq = nl->serial++;
703 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
707 /* ioctl(rtnl->fd, FIONREAD, &need)
708 Does not appear to work on netlink sockets. libnl uses
709 MSG_PEEK instead. I don't know if that is worth the
712 For now we simply use the maximum message size the kernel
713 may use (NLMSG_GOODSIZE), and then realloc to the actual
714 size after reading the message (hence avoiding huge memory
715 usage in case many small messages are kept around) */
723 /* returns the number of bytes sent, or a negative error code */
724 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
727 struct sockaddr_nl nl;
729 .nl.nl_family = AF_NETLINK,
737 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
738 0, &addr.sa, sizeof(addr));
740 return (errno == EAGAIN) ? 0 : -errno;
745 /* On success, the number of bytes received is returned and *ret points to the received message
746 * which has a valid header and the correct size.
747 * If nothing useful was received 0 is returned.
748 * On failure, a negative error code is returned.
750 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
754 struct sockaddr_nl nl;
764 r = message_receive_need(nl, &need);
768 r = message_new(&m, need);
772 addr_len = sizeof(addr);
774 k = recvfrom(nl->fd, m->hdr, need,
775 0, &addr.sa, &addr_len);
777 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
779 k = -ECONNRESET; /* connection was closed by the kernel */
780 else if (addr_len != sizeof(addr.nl) ||
781 addr.nl.nl_family != AF_NETLINK)
782 k = -EIO; /* not a netlink message */
783 else if (addr.nl.nl_pid != 0)
784 k = 0; /* not from the kernel */
785 else if ((size_t) k < sizeof(struct nlmsghdr) ||
786 (size_t) k < m->hdr->nlmsg_len)
787 k = -EIO; /* too small (we do accept too big though) */
788 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
789 k = 0; /* not broadcast and not for us */
792 switch (m->hdr->nlmsg_type) {
793 struct ifinfomsg *ifi;
794 struct ifaddrmsg *ifa;
797 /* check that the size matches the message type */
799 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
806 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
809 ifi = NLMSG_DATA(m->hdr);
810 UPDATE_RTA(m, IFLA_RTA(ifi));
816 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
819 ifa = NLMSG_DATA(m->hdr);
820 UPDATE_RTA(m, IFA_RTA(ifa));
826 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
829 rtm = NLMSG_DATA(m->hdr);
830 UPDATE_RTA(m, RTM_RTA(rtm));
837 k = 0; /* ignoring message of unknown type */
841 sd_rtnl_message_unref(m);
843 /* we probably allocated way too much memory, give it back */
844 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
851 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
852 struct ifinfomsg *ifi;
853 struct ifaddrmsg *ifa;
856 assert_return(m, -EINVAL);
857 assert_return(m->hdr, -EINVAL);
859 switch(m->hdr->nlmsg_type) {
864 ifi = NLMSG_DATA(m->hdr);
865 UPDATE_RTA(m, IFLA_RTA(ifi));
871 ifa = NLMSG_DATA(m->hdr);
872 UPDATE_RTA(m, IFA_RTA(ifa));
878 rtm = NLMSG_DATA(m->hdr);
879 UPDATE_RTA(m, RTM_RTA(rtm));