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;
42 size_t remaining_size;
47 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
50 assert_return(ret, -EINVAL);
51 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
53 m = new0(sd_rtnl_message, 1);
57 m->hdr = malloc0(initial_size);
63 m->n_ref = REFCNT_INIT;
65 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
73 int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
79 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
83 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
84 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
85 (*ret)->hdr->nlmsg_seq = serial;
87 err = NLMSG_DATA((*ret)->hdr);
94 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
95 unsigned char rtm_dst_len, unsigned char rtm_src_len,
96 unsigned char rtm_tos, unsigned char rtm_table,
97 unsigned char rtm_scope, unsigned char rtm_protocol,
98 unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
102 assert_return(nlmsg_type == RTM_NEWROUTE || nlmsg_type == RTM_DELROUTE ||
103 nlmsg_type == RTM_GETROUTE, -EINVAL);
104 assert_return(ret, -EINVAL);
106 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
110 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
111 (*ret)->hdr->nlmsg_type = nlmsg_type;
112 if (nlmsg_type == RTM_NEWROUTE)
113 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
115 rtm = NLMSG_DATA((*ret)->hdr);
117 rtm->rtm_family = rtm_family;
118 rtm->rtm_dst_len = rtm_dst_len;
119 rtm->rtm_src_len = rtm_src_len;
120 rtm->rtm_tos = rtm_tos;
121 rtm->rtm_table = rtm_table;
122 rtm->rtm_protocol = rtm_protocol;
123 rtm->rtm_scope = rtm_scope;
124 rtm->rtm_type = rtm_type;
125 rtm->rtm_flags = rtm_flags;
130 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned type, unsigned flags, sd_rtnl_message **ret) {
131 struct ifinfomsg *ifi;
134 assert_return(nlmsg_type == RTM_NEWLINK || nlmsg_type == RTM_DELLINK ||
135 nlmsg_type == RTM_SETLINK || nlmsg_type == RTM_GETLINK, -EINVAL);
136 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
137 assert_return(ret, -EINVAL);
139 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
143 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
144 (*ret)->hdr->nlmsg_type = nlmsg_type;
145 if (nlmsg_type == RTM_NEWLINK)
146 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
148 ifi = NLMSG_DATA((*ret)->hdr);
150 ifi->ifi_family = AF_UNSPEC;
151 ifi->ifi_index = index;
152 ifi->ifi_type = type;
153 ifi->ifi_flags = flags;
154 ifi->ifi_change = 0xffffffff;
159 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) {
160 struct ifaddrmsg *ifa;
163 assert_return(nlmsg_type == RTM_NEWADDR || nlmsg_type == RTM_DELADDR || nlmsg_type == RTM_GETADDR, -EINVAL);
164 assert_return(index > 0, -EINVAL);
165 assert_return(ret, -EINVAL);
167 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
171 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
172 (*ret)->hdr->nlmsg_type = nlmsg_type;
174 ifa = NLMSG_DATA((*ret)->hdr);
176 ifa->ifa_family = family;
177 ifa->ifa_prefixlen = prefixlen;
178 ifa->ifa_flags = flags;
179 ifa->ifa_scope = scope;
180 ifa->ifa_index = index;
185 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
187 assert_se(REFCNT_INC(m->n_ref) >= 2);
192 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
193 if (m && REFCNT_DEC(m->n_ref) <= 0) {
201 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
202 assert_return(m, -EINVAL);
203 assert_return(type, -EINVAL);
205 *type = m->hdr->nlmsg_type;
210 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
211 struct ifinfomsg *ifi;
213 assert_return(m, -EINVAL);
214 assert_return(ifindex, -EINVAL);
215 assert_return(m->hdr->nlmsg_type == RTM_NEWLINK || m->hdr->nlmsg_type == RTM_DELLINK ||
216 m->hdr->nlmsg_type == RTM_GETLINK || m->hdr->nlmsg_type == RTM_SETLINK, -EINVAL);
218 ifi = NLMSG_DATA(m->hdr);
220 *ifindex = ifi->ifi_index;
225 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
226 struct ifinfomsg *ifi;
228 assert_return(m, -EINVAL);
229 assert_return(flags, -EINVAL);
230 assert_return(m->hdr->nlmsg_type == RTM_NEWLINK || m->hdr->nlmsg_type == RTM_DELLINK ||
231 m->hdr->nlmsg_type == RTM_GETLINK || m->hdr->nlmsg_type == RTM_SETLINK, -EINVAL);
233 ifi = NLMSG_DATA(m->hdr);
235 *flags = ifi->ifi_flags;
240 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
242 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
243 uint32_t rta_length, message_length;
244 struct nlmsghdr *new_hdr;
250 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
251 assert(!data || data_length > 0);
253 /* get the size of the new rta attribute (with padding at the end) */
254 rta_length = RTA_LENGTH(data_length);
255 /* get the new message size (with padding at the end)
257 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
259 /* realloc to fit the new attribute */
260 new_hdr = realloc(m->hdr, message_length);
265 /* get pointer to the attribute we are about to add */
266 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
267 /* update message size */
268 m->hdr->nlmsg_len = message_length;
270 /* we are inside a container, extend it */
271 if (m->current_container)
272 m->current_container->rta_len = (unsigned char *) m->hdr +
274 (unsigned char *) m->current_container;
276 /* fill in the attribute */
277 rta->rta_type = type;
278 rta->rta_len = rta_length;
280 /* this is a container, set pointer */
281 m->current_container = rta;
283 /* we don't deal with the case where the user lies about the type
284 * and gives us too little data (so don't do that)
286 padding = mempcpy(RTA_DATA(rta), data, data_length);
287 /* make sure also the padding at the end of the message is initialized */
288 memset(padding, '\0', (unsigned char *) m->hdr +
290 (unsigned char *) padding);
296 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
298 struct ifaddrmsg *ifa;
301 assert_return(m, -EINVAL);
302 assert_return(data, -EINVAL);
304 sd_rtnl_message_get_type(m, &rtm_type);
306 if (m->current_container) {
312 switch (m->current_container->rta_type) {
316 return add_rtattr(m, type, data, strlen(data) + 1);
337 return add_rtattr(m, type, data, strlen(data) + 1);
341 return add_rtattr(m, type, data, sizeof(uint32_t));
343 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
346 return add_rtattr(m, type, data, ETH_ALEN);
355 return add_rtattr(m, type, data, strlen(data) + 1);
360 ifa = NLMSG_DATA(m->hdr);
361 switch (ifa->ifa_family) {
363 return add_rtattr(m, type, data, sizeof(struct in_addr));
365 return add_rtattr(m, type, data, sizeof(struct in6_addr));
379 rtm = NLMSG_DATA(m->hdr);
380 switch (rtm->rtm_family) {
382 return add_rtattr(m, type, data, sizeof(struct in_addr));
384 return add_rtattr(m, type, data, sizeof(struct in6_addr));
392 return add_rtattr(m, type, data, sizeof(uint32_t));
401 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
404 assert_return(m, -EINVAL);
405 assert_return(!m->current_container, -EINVAL);
407 sd_rtnl_message_get_type(m, &rtm_type);
414 if (type == IFLA_LINKINFO)
415 return add_rtattr(m, type, NULL, 0);
425 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
426 assert_return(m, -EINVAL);
427 assert_return(m->current_container, -EINVAL);
429 m->current_container = NULL;
434 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
443 if (!RTA_OK(m->next_rta, m->remaining_size))
446 /* make sure we don't try to read a container
447 * TODO: add support for entering containers for reading */
448 r = sd_rtnl_message_get_type(m, &rtm_type);
457 if (m->next_rta->rta_type == IFLA_LINKINFO) {
462 *data = RTA_DATA(m->next_rta);
463 *type = m->next_rta->rta_type;
465 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
470 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
474 assert_return(m, -EINVAL);
475 assert_return(data, -EINVAL);
477 r = sd_rtnl_message_get_type(m, &rtm_type);
487 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
489 m->next_rta = IFLA_RTA(ifi);
490 m->remaining_size = IFLA_PAYLOAD(m->hdr);
497 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
499 m->next_rta = IFA_RTA(ifa);
500 m->remaining_size = IFA_PAYLOAD(m->hdr);
507 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
509 m->next_rta = RTM_RTA(rtm);
510 m->remaining_size = RTM_PAYLOAD(m->hdr);
517 return message_read(m, type, data);
520 uint32_t message_get_serial(sd_rtnl_message *m) {
523 return m->hdr->nlmsg_seq;
526 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
527 struct nlmsgerr *err;
529 assert_return(m, -EINVAL);
531 if (m->hdr->nlmsg_type != NLMSG_ERROR)
534 err = NLMSG_DATA(m->hdr);
539 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
543 m->hdr->nlmsg_seq = nl->serial++;
549 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
550 assert_return(rtnl, -EINVAL);
551 assert_return(need, -EINVAL);
553 /* ioctl(rtnl->fd, FIONREAD, &need)
554 Does not appear to work on netlink sockets. libnl uses
555 MSG_PEEK instead. I don't know if that is worth the
558 For now we simply use the maximum message size the kernel
559 may use (NLMSG_GOODSIZE), and then realloc to the actual
560 size after reading the message (hence avoiding huge memory
561 usage in case many small messages are kept around) */
569 /* returns the number of bytes sent, or a negative error code */
570 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
573 struct sockaddr_nl nl;
575 .nl.nl_family = AF_NETLINK,
579 assert_return(nl, -EINVAL);
580 assert_return(m, -EINVAL);
582 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
583 0, &addr.sa, sizeof(addr));
585 return (errno == EAGAIN) ? 0 : -errno;
590 /* On success, the number of bytes received is returned and *ret points to the received message
591 * which has a valid header and the correct size.
592 * If nothing useful was received 0 is returned.
593 * On failure, a negative error code is returned.
595 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
599 struct sockaddr_nl nl;
606 assert_return(nl, -EINVAL);
607 assert_return(ret, -EINVAL);
609 r = message_receive_need(nl, &need);
613 r = message_new(&m, need);
617 addr_len = sizeof(addr);
619 k = recvfrom(nl->fd, m->hdr, need,
620 0, &addr.sa, &addr_len);
622 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
624 k = -ECONNRESET; /* connection was closed by the kernel */
625 else if (addr_len != sizeof(addr.nl) ||
626 addr.nl.nl_family != AF_NETLINK)
627 k = -EIO; /* not a netlink message */
628 else if (addr.nl.nl_pid != 0)
629 k = 0; /* not from the kernel */
630 else if ((size_t) k < sizeof(struct nlmsghdr) ||
631 (size_t) k < m->hdr->nlmsg_len)
632 k = -EIO; /* too small (we do accept too big though) */
633 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
634 k = 0; /* not broadcast and not for us */
637 switch (m->hdr->nlmsg_type) {
638 /* check that the size matches the message type */
640 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
647 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
653 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
660 k = 0; /* ignoring message of unknown type */
664 sd_rtnl_message_unref(m);
666 /* we probably allocated way too much memory, give it back */
667 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);