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_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
411 assert_return(m, -EINVAL);
413 r = sd_rtnl_message_get_type(m, &rtm_type);
417 /* check that the type is correct */
434 r = add_rtattr(m, type, &data, sizeof(uint16_t));
441 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
445 assert_return(m, -EINVAL);
447 r = sd_rtnl_message_get_type(m, &rtm_type);
451 /* check that the type is correct */
483 r = add_rtattr(m, type, &data, sizeof(uint32_t));
490 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
491 struct ifaddrmsg *ifa;
496 assert_return(m, -EINVAL);
497 assert_return(data, -EINVAL);
499 r = sd_rtnl_message_get_type(m, &rtm_type);
503 /* check that the type is correct */
513 ifa = NLMSG_DATA(m->hdr);
515 if (ifa->ifa_family != AF_INET)
530 rtm = NLMSG_DATA(m->hdr);
532 if (rtm->rtm_family != AF_INET)
544 r = add_rtattr(m, type, data, sizeof(struct in_addr));
551 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
552 struct ifaddrmsg *ifa;
557 assert_return(m, -EINVAL);
558 assert_return(data, -EINVAL);
560 r = sd_rtnl_message_get_type(m, &rtm_type);
564 /* check that the type is correct */
574 ifa = NLMSG_DATA(m->hdr);
576 if (ifa->ifa_family != AF_INET6)
591 rtm = NLMSG_DATA(m->hdr);
593 if (rtm->rtm_family != AF_INET6)
604 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
611 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
615 assert_return(m, -EINVAL);
616 assert_return(data, -EINVAL);
618 sd_rtnl_message_get_type(m, &rtm_type);
637 r = add_rtattr(m, type, data, ETH_ALEN);
644 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
647 assert_return(m, -EINVAL);
648 assert_return(!CURRENT_CONTAINER(m), -EINVAL);
650 sd_rtnl_message_get_type(m, &rtm_type);
652 if (message_type_is_link(rtm_type)) {
653 if (type == IFLA_LINKINFO)
654 return add_rtattr(m, type, NULL, 0);
663 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
664 assert_return(m, -EINVAL);
665 assert_return(CURRENT_CONTAINER(m), -EINVAL);
667 m->container_offset = 0;
672 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
673 size_t remaining_size;
678 assert(m->next_rta_offset);
682 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
684 if (!RTA_OK(NEXT_RTA(m), remaining_size))
687 /* make sure we don't try to read a container
688 * TODO: add support for entering containers for reading */
689 r = sd_rtnl_message_get_type(m, &rtm_type);
693 if (message_type_is_link(rtm_type) &&
694 NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
697 *data = RTA_DATA(NEXT_RTA(m));
698 *type = NEXT_RTA(m)->rta_type;
700 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
705 uint32_t message_get_serial(sd_rtnl_message *m) {
709 return m->hdr->nlmsg_seq;
712 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
713 struct nlmsgerr *err;
715 assert_return(m, -EINVAL);
716 assert_return(m->hdr, -EINVAL);
718 if (m->hdr->nlmsg_type != NLMSG_ERROR)
721 err = NLMSG_DATA(m->hdr);
726 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
734 m->hdr->nlmsg_seq = nl->serial++;
740 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
744 /* ioctl(rtnl->fd, FIONREAD, &need)
745 Does not appear to work on netlink sockets. libnl uses
746 MSG_PEEK instead. I don't know if that is worth the
749 For now we simply use the maximum message size the kernel
750 may use (NLMSG_GOODSIZE), and then realloc to the actual
751 size after reading the message (hence avoiding huge memory
752 usage in case many small messages are kept around) */
760 /* returns the number of bytes sent, or a negative error code */
761 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
764 struct sockaddr_nl nl;
766 .nl.nl_family = AF_NETLINK,
774 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
775 0, &addr.sa, sizeof(addr));
777 return (errno == EAGAIN) ? 0 : -errno;
782 /* On success, the number of bytes received is returned and *ret points to the received message
783 * which has a valid header and the correct size.
784 * If nothing useful was received 0 is returned.
785 * On failure, a negative error code is returned.
787 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
791 struct sockaddr_nl nl;
801 r = message_receive_need(nl, &need);
805 r = message_new(&m, need);
809 addr_len = sizeof(addr);
811 k = recvfrom(nl->fd, m->hdr, need,
812 0, &addr.sa, &addr_len);
814 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
816 k = -ECONNRESET; /* connection was closed by the kernel */
817 else if (addr_len != sizeof(addr.nl) ||
818 addr.nl.nl_family != AF_NETLINK)
819 k = -EIO; /* not a netlink message */
820 else if (addr.nl.nl_pid != 0)
821 k = 0; /* not from the kernel */
822 else if ((size_t) k < sizeof(struct nlmsghdr) ||
823 (size_t) k < m->hdr->nlmsg_len)
824 k = -EIO; /* too small (we do accept too big though) */
825 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
826 k = 0; /* not broadcast and not for us */
829 switch (m->hdr->nlmsg_type) {
830 struct ifinfomsg *ifi;
831 struct ifaddrmsg *ifa;
834 /* check that the size matches the message type */
836 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
843 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
846 ifi = NLMSG_DATA(m->hdr);
847 UPDATE_RTA(m, IFLA_RTA(ifi));
853 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
856 ifa = NLMSG_DATA(m->hdr);
857 UPDATE_RTA(m, IFA_RTA(ifa));
863 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
866 rtm = NLMSG_DATA(m->hdr);
867 UPDATE_RTA(m, RTM_RTA(rtm));
874 k = 0; /* ignoring message of unknown type */
878 sd_rtnl_message_unref(m);
880 /* we probably allocated way too much memory, give it back */
881 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
888 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
889 struct ifinfomsg *ifi;
890 struct ifaddrmsg *ifa;
893 assert_return(m, -EINVAL);
894 assert_return(m->hdr, -EINVAL);
896 switch(m->hdr->nlmsg_type) {
901 ifi = NLMSG_DATA(m->hdr);
902 UPDATE_RTA(m, IFLA_RTA(ifi));
908 ifa = NLMSG_DATA(m->hdr);
909 UPDATE_RTA(m, IFA_RTA(ifa));
915 rtm = NLMSG_DATA(m->hdr);
916 UPDATE_RTA(m, RTM_RTA(rtm));