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;
46 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
49 assert_return(ret, -EINVAL);
50 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
52 m = new0(sd_rtnl_message, 1);
56 m->hdr = malloc0(initial_size);
62 m->n_ref = REFCNT_INIT;
64 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
72 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
78 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
82 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
83 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
84 (*ret)->hdr->nlmsg_seq = serial;
86 err = NLMSG_DATA((*ret)->hdr);
93 bool message_type_is_route(uint16_t type) {
104 bool message_type_is_link(uint16_t type) {
116 bool message_type_is_addr(uint16_t type) {
127 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
130 rtm = NLMSG_DATA(m->hdr);
132 rtm->rtm_dst_len = prefixlen;
137 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
138 sd_rtnl_message **ret) {
142 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
143 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
144 assert_return(ret, -EINVAL);
146 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
150 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
151 (*ret)->hdr->nlmsg_type = nlmsg_type;
152 if (nlmsg_type == RTM_NEWROUTE)
153 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
155 rtm = NLMSG_DATA((*ret)->hdr);
157 (*ret)->next_rta = RTM_RTA(rtm);
159 rtm->rtm_family = rtm_family;
160 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
161 rtm->rtm_type = RTN_UNICAST;
162 rtm->rtm_table = RT_TABLE_MAIN;
163 rtm->rtm_protocol = RTPROT_BOOT;
168 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
169 struct ifinfomsg *ifi;
171 ifi = NLMSG_DATA(m->hdr);
173 ifi->ifi_flags = flags;
178 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
179 struct ifinfomsg *ifi;
181 ifi = NLMSG_DATA(m->hdr);
183 ifi->ifi_type = type;
188 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
189 struct ifinfomsg *ifi;
192 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
193 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
194 assert_return(ret, -EINVAL);
196 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
200 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
201 (*ret)->hdr->nlmsg_type = nlmsg_type;
202 if (nlmsg_type == RTM_NEWLINK)
203 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
205 ifi = NLMSG_DATA((*ret)->hdr);
207 ifi->ifi_family = AF_UNSPEC;
208 ifi->ifi_index = index;
209 ifi->ifi_change = 0xffffffff;
211 (*ret)->next_rta = IFLA_RTA(ifi);
216 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) {
217 struct ifaddrmsg *ifa;
220 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
221 assert_return(index > 0, -EINVAL);
222 assert_return(ret, -EINVAL);
224 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
228 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
229 (*ret)->hdr->nlmsg_type = nlmsg_type;
231 ifa = NLMSG_DATA((*ret)->hdr);
233 ifa->ifa_family = family;
234 ifa->ifa_prefixlen = prefixlen;
235 ifa->ifa_flags = flags;
236 ifa->ifa_scope = scope;
237 ifa->ifa_index = index;
239 (*ret)->next_rta = IFA_RTA(ifa);
244 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
246 assert_se(REFCNT_INC(m->n_ref) >= 2);
251 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
252 if (m && REFCNT_DEC(m->n_ref) <= 0) {
260 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
261 assert_return(m, -EINVAL);
262 assert_return(type, -EINVAL);
264 *type = m->hdr->nlmsg_type;
269 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
270 struct ifinfomsg *ifi;
272 assert_return(m, -EINVAL);
273 assert_return(m->hdr, -EINVAL);
274 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
275 assert_return(ifindex, -EINVAL);
277 ifi = NLMSG_DATA(m->hdr);
279 *ifindex = ifi->ifi_index;
284 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
285 struct ifinfomsg *ifi;
287 assert_return(m, -EINVAL);
288 assert_return(m->hdr, -EINVAL);
289 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
290 assert_return(flags, -EINVAL);
292 ifi = NLMSG_DATA(m->hdr);
294 *flags = ifi->ifi_flags;
299 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
301 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
302 uint32_t rta_length, message_length;
303 struct nlmsghdr *new_hdr;
309 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
310 assert(!data || data_length > 0);
312 /* get the size of the new rta attribute (with padding at the end) */
313 rta_length = RTA_LENGTH(data_length);
314 /* get the new message size (with padding at the end)
316 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
318 /* realloc to fit the new attribute */
319 new_hdr = realloc(m->hdr, message_length);
322 /* update the location of the next rta for reading */
323 m->next_rta = (struct rtattr *) ((uint8_t *) m->next_rta +
324 ((uint8_t *) new_hdr -
325 (uint8_t *) m->hdr));
328 /* get pointer to the attribute we are about to add */
329 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
330 /* update message size */
331 m->hdr->nlmsg_len = message_length;
333 /* we are inside a container, extend it */
334 if (m->current_container)
335 m->current_container->rta_len = (uint8_t *) m->hdr +
337 (uint8_t *) m->current_container;
339 /* fill in the attribute */
340 rta->rta_type = type;
341 rta->rta_len = rta_length;
343 /* this is a container, set pointer */
344 m->current_container = rta;
346 /* we don't deal with the case where the user lies about the type
347 * and gives us too little data (so don't do that)
349 padding = mempcpy(RTA_DATA(rta), data, data_length);
350 /* make sure also the padding at the end of the message is initialized */
351 memset(padding, '\0', (uint8_t *) m->hdr +
353 (uint8_t *) padding);
359 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
363 assert_return(m, -EINVAL);
364 assert_return(data, -EINVAL);
366 r = sd_rtnl_message_get_type(m, &rtm_type);
370 /* check that the type is correct */
376 if (m->current_container) {
377 if (m->current_container->rta_type != IFLA_LINKINFO ||
378 type != IFLA_INFO_KIND)
394 if (type != IFA_LABEL)
401 r = add_rtattr(m, type, data, strlen(data) + 1);
408 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
412 assert_return(m, -EINVAL);
414 r = sd_rtnl_message_get_type(m, &rtm_type);
418 /* check that the type is correct */
450 r = add_rtattr(m, type, &data, sizeof(&data));
457 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
458 struct ifaddrmsg *ifa;
463 assert_return(m, -EINVAL);
464 assert_return(data, -EINVAL);
466 r = sd_rtnl_message_get_type(m, &rtm_type);
470 /* check that the type is correct */
480 ifa = NLMSG_DATA(m->hdr);
482 if (ifa->ifa_family != AF_INET)
497 rtm = NLMSG_DATA(m->hdr);
499 if (rtm->rtm_family != AF_INET)
511 r = add_rtattr(m, type, data, sizeof(data));
518 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
519 struct ifaddrmsg *ifa;
524 assert_return(m, -EINVAL);
525 assert_return(data, -EINVAL);
527 r = sd_rtnl_message_get_type(m, &rtm_type);
531 /* check that the type is correct */
541 ifa = NLMSG_DATA(m->hdr);
543 if (ifa->ifa_family != AF_INET6)
558 rtm = NLMSG_DATA(m->hdr);
560 if (rtm->rtm_family != AF_INET6)
571 r = add_rtattr(m, type, data, sizeof(data));
578 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
582 assert_return(m, -EINVAL);
583 assert_return(data, -EINVAL);
585 sd_rtnl_message_get_type(m, &rtm_type);
604 r = add_rtattr(m, type, data, sizeof(data));
611 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
614 assert_return(m, -EINVAL);
615 assert_return(!m->current_container, -EINVAL);
617 sd_rtnl_message_get_type(m, &rtm_type);
619 if (message_type_is_link(rtm_type)) {
620 if (type == IFLA_LINKINFO)
621 return add_rtattr(m, type, NULL, 0);
630 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
631 assert_return(m, -EINVAL);
632 assert_return(m->current_container, -EINVAL);
634 m->current_container = NULL;
639 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
640 size_t remaining_size;
649 remaining_size = (uint8_t *) m->hdr + m->hdr->nlmsg_len - (uint8_t *) m->next_rta;
651 if (!RTA_OK(m->next_rta, remaining_size))
654 /* make sure we don't try to read a container
655 * TODO: add support for entering containers for reading */
656 r = sd_rtnl_message_get_type(m, &rtm_type);
660 if (message_type_is_link(rtm_type) &&
661 m->next_rta->rta_type == IFLA_LINKINFO)
664 *data = RTA_DATA(m->next_rta);
665 *type = m->next_rta->rta_type;
667 m->next_rta = RTA_NEXT(m->next_rta, remaining_size);
672 uint32_t message_get_serial(sd_rtnl_message *m) {
676 return m->hdr->nlmsg_seq;
679 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
680 struct nlmsgerr *err;
682 assert_return(m, -EINVAL);
683 assert_return(m->hdr, -EINVAL);
685 if (m->hdr->nlmsg_type != NLMSG_ERROR)
688 err = NLMSG_DATA(m->hdr);
693 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
701 m->hdr->nlmsg_seq = nl->serial++;
707 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
711 /* ioctl(rtnl->fd, FIONREAD, &need)
712 Does not appear to work on netlink sockets. libnl uses
713 MSG_PEEK instead. I don't know if that is worth the
716 For now we simply use the maximum message size the kernel
717 may use (NLMSG_GOODSIZE), and then realloc to the actual
718 size after reading the message (hence avoiding huge memory
719 usage in case many small messages are kept around) */
727 /* returns the number of bytes sent, or a negative error code */
728 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
731 struct sockaddr_nl nl;
733 .nl.nl_family = AF_NETLINK,
741 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
742 0, &addr.sa, sizeof(addr));
744 return (errno == EAGAIN) ? 0 : -errno;
749 /* On success, the number of bytes received is returned and *ret points to the received message
750 * which has a valid header and the correct size.
751 * If nothing useful was received 0 is returned.
752 * On failure, a negative error code is returned.
754 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
758 struct sockaddr_nl nl;
768 r = message_receive_need(nl, &need);
772 r = message_new(&m, need);
776 addr_len = sizeof(addr);
778 k = recvfrom(nl->fd, m->hdr, need,
779 0, &addr.sa, &addr_len);
781 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
783 k = -ECONNRESET; /* connection was closed by the kernel */
784 else if (addr_len != sizeof(addr.nl) ||
785 addr.nl.nl_family != AF_NETLINK)
786 k = -EIO; /* not a netlink message */
787 else if (addr.nl.nl_pid != 0)
788 k = 0; /* not from the kernel */
789 else if ((size_t) k < sizeof(struct nlmsghdr) ||
790 (size_t) k < m->hdr->nlmsg_len)
791 k = -EIO; /* too small (we do accept too big though) */
792 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
793 k = 0; /* not broadcast and not for us */
796 switch (m->hdr->nlmsg_type) {
797 struct ifinfomsg *ifi;
798 struct ifaddrmsg *ifa;
801 /* check that the size matches the message type */
803 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
810 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
813 ifi = NLMSG_DATA(m->hdr);
814 m->next_rta = IFLA_RTA(ifi);
820 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
823 ifa = NLMSG_DATA(m->hdr);
824 m->next_rta = IFA_RTA(ifa);
830 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
833 rtm = NLMSG_DATA(m->hdr);
834 m->next_rta = RTM_RTA(rtm);
841 k = 0; /* ignoring message of unknown type */
845 sd_rtnl_message_unref(m);
847 /* we probably allocated way too much memory, give it back */
848 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
855 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
856 struct ifinfomsg *ifi;
857 struct ifaddrmsg *ifa;
860 assert_return(m, -EINVAL);
861 assert_return(m->hdr, -EINVAL);
863 switch(m->hdr->nlmsg_type) {
868 ifi = NLMSG_DATA(m->hdr);
870 m->next_rta = IFLA_RTA(ifi);
875 ifa = NLMSG_DATA(m->hdr);
877 m->next_rta = IFA_RTA(ifa);
882 rtm = NLMSG_DATA(m->hdr);
884 m->next_rta = RTM_RTA(rtm);