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(sd_rtnl_message *m, unsigned short type, const void *data) {
361 struct ifaddrmsg *ifa;
364 assert_return(m, -EINVAL);
365 assert_return(data, -EINVAL);
367 sd_rtnl_message_get_type(m, &rtm_type);
369 if (m->current_container) {
375 switch (m->current_container->rta_type) {
379 return add_rtattr(m, type, data, strlen(data) + 1);
400 return add_rtattr(m, type, data, strlen(data) + 1);
404 return add_rtattr(m, type, data, sizeof(uint32_t));
406 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
409 return add_rtattr(m, type, data, ETH_ALEN);
418 return add_rtattr(m, type, data, strlen(data) + 1);
423 ifa = NLMSG_DATA(m->hdr);
424 switch (ifa->ifa_family) {
426 return add_rtattr(m, type, data, sizeof(struct in_addr));
428 return add_rtattr(m, type, data, sizeof(struct in6_addr));
442 rtm = NLMSG_DATA(m->hdr);
443 switch (rtm->rtm_family) {
445 return add_rtattr(m, type, data, sizeof(struct in_addr));
447 return add_rtattr(m, type, data, sizeof(struct in6_addr));
455 return add_rtattr(m, type, data, sizeof(uint32_t));
464 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
467 assert_return(m, -EINVAL);
468 assert_return(!m->current_container, -EINVAL);
470 sd_rtnl_message_get_type(m, &rtm_type);
472 if (message_type_is_link(rtm_type)) {
473 if (type == IFLA_LINKINFO)
474 return add_rtattr(m, type, NULL, 0);
483 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
484 assert_return(m, -EINVAL);
485 assert_return(m->current_container, -EINVAL);
487 m->current_container = NULL;
492 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
493 size_t remaining_size;
502 remaining_size = (uint8_t *) m->hdr + m->hdr->nlmsg_len - (uint8_t *) m->next_rta;
504 if (!RTA_OK(m->next_rta, remaining_size))
507 /* make sure we don't try to read a container
508 * TODO: add support for entering containers for reading */
509 r = sd_rtnl_message_get_type(m, &rtm_type);
513 if (message_type_is_link(rtm_type) &&
514 m->next_rta->rta_type == IFLA_LINKINFO)
517 *data = RTA_DATA(m->next_rta);
518 *type = m->next_rta->rta_type;
520 m->next_rta = RTA_NEXT(m->next_rta, remaining_size);
525 uint32_t message_get_serial(sd_rtnl_message *m) {
529 return m->hdr->nlmsg_seq;
532 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
533 struct nlmsgerr *err;
535 assert_return(m, -EINVAL);
536 assert_return(m->hdr, -EINVAL);
538 if (m->hdr->nlmsg_type != NLMSG_ERROR)
541 err = NLMSG_DATA(m->hdr);
546 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
554 m->hdr->nlmsg_seq = nl->serial++;
560 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
564 /* ioctl(rtnl->fd, FIONREAD, &need)
565 Does not appear to work on netlink sockets. libnl uses
566 MSG_PEEK instead. I don't know if that is worth the
569 For now we simply use the maximum message size the kernel
570 may use (NLMSG_GOODSIZE), and then realloc to the actual
571 size after reading the message (hence avoiding huge memory
572 usage in case many small messages are kept around) */
580 /* returns the number of bytes sent, or a negative error code */
581 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
584 struct sockaddr_nl nl;
586 .nl.nl_family = AF_NETLINK,
594 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
595 0, &addr.sa, sizeof(addr));
597 return (errno == EAGAIN) ? 0 : -errno;
602 /* On success, the number of bytes received is returned and *ret points to the received message
603 * which has a valid header and the correct size.
604 * If nothing useful was received 0 is returned.
605 * On failure, a negative error code is returned.
607 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
611 struct sockaddr_nl nl;
621 r = message_receive_need(nl, &need);
625 r = message_new(&m, need);
629 addr_len = sizeof(addr);
631 k = recvfrom(nl->fd, m->hdr, need,
632 0, &addr.sa, &addr_len);
634 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
636 k = -ECONNRESET; /* connection was closed by the kernel */
637 else if (addr_len != sizeof(addr.nl) ||
638 addr.nl.nl_family != AF_NETLINK)
639 k = -EIO; /* not a netlink message */
640 else if (addr.nl.nl_pid != 0)
641 k = 0; /* not from the kernel */
642 else if ((size_t) k < sizeof(struct nlmsghdr) ||
643 (size_t) k < m->hdr->nlmsg_len)
644 k = -EIO; /* too small (we do accept too big though) */
645 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
646 k = 0; /* not broadcast and not for us */
649 switch (m->hdr->nlmsg_type) {
650 struct ifinfomsg *ifi;
651 struct ifaddrmsg *ifa;
654 /* check that the size matches the message type */
656 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
663 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
666 ifi = NLMSG_DATA(m->hdr);
667 m->next_rta = IFLA_RTA(ifi);
673 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
676 ifa = NLMSG_DATA(m->hdr);
677 m->next_rta = IFA_RTA(ifa);
683 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
686 rtm = NLMSG_DATA(m->hdr);
687 m->next_rta = RTM_RTA(rtm);
694 k = 0; /* ignoring message of unknown type */
698 sd_rtnl_message_unref(m);
700 /* we probably allocated way too much memory, give it back */
701 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
708 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
709 struct ifinfomsg *ifi;
710 struct ifaddrmsg *ifa;
713 assert_return(m, -EINVAL);
714 assert_return(m->hdr, -EINVAL);
716 switch(m->hdr->nlmsg_type) {
721 ifi = NLMSG_DATA(m->hdr);
723 m->next_rta = IFLA_RTA(ifi);
728 ifa = NLMSG_DATA(m->hdr);
730 m->next_rta = IFA_RTA(ifa);
735 rtm = NLMSG_DATA(m->hdr);
737 m->next_rta = RTM_RTA(rtm);