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 bool message_type_is_route(uint16_t type) {
105 bool message_type_is_link(uint16_t type) {
117 bool message_type_is_addr(uint16_t type) {
128 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
129 unsigned char rtm_dst_len, unsigned char rtm_src_len,
130 unsigned char rtm_tos, unsigned char rtm_table,
131 unsigned char rtm_scope, unsigned char rtm_protocol,
132 unsigned char rtm_type, unsigned rtm_flags, sd_rtnl_message **ret) {
136 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
137 assert_return(ret, -EINVAL);
139 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
143 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
144 (*ret)->hdr->nlmsg_type = nlmsg_type;
145 if (nlmsg_type == RTM_NEWROUTE)
146 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
148 rtm = NLMSG_DATA((*ret)->hdr);
150 rtm->rtm_family = rtm_family;
151 rtm->rtm_dst_len = rtm_dst_len;
152 rtm->rtm_src_len = rtm_src_len;
153 rtm->rtm_tos = rtm_tos;
154 rtm->rtm_table = rtm_table;
155 rtm->rtm_protocol = rtm_protocol;
156 rtm->rtm_scope = rtm_scope;
157 rtm->rtm_type = rtm_type;
158 rtm->rtm_flags = rtm_flags;
163 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned type, unsigned flags, sd_rtnl_message **ret) {
164 struct ifinfomsg *ifi;
167 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
168 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
169 assert_return(ret, -EINVAL);
171 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
175 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
176 (*ret)->hdr->nlmsg_type = nlmsg_type;
177 if (nlmsg_type == RTM_NEWLINK)
178 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
180 ifi = NLMSG_DATA((*ret)->hdr);
182 ifi->ifi_family = AF_UNSPEC;
183 ifi->ifi_index = index;
184 ifi->ifi_type = type;
185 ifi->ifi_flags = flags;
186 ifi->ifi_change = 0xffffffff;
191 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) {
192 struct ifaddrmsg *ifa;
195 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
196 assert_return(index > 0, -EINVAL);
197 assert_return(ret, -EINVAL);
199 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
203 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
204 (*ret)->hdr->nlmsg_type = nlmsg_type;
206 ifa = NLMSG_DATA((*ret)->hdr);
208 ifa->ifa_family = family;
209 ifa->ifa_prefixlen = prefixlen;
210 ifa->ifa_flags = flags;
211 ifa->ifa_scope = scope;
212 ifa->ifa_index = index;
217 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
219 assert_se(REFCNT_INC(m->n_ref) >= 2);
224 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
225 if (m && REFCNT_DEC(m->n_ref) <= 0) {
233 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
234 assert_return(m, -EINVAL);
235 assert_return(type, -EINVAL);
237 *type = m->hdr->nlmsg_type;
242 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
243 struct ifinfomsg *ifi;
245 assert_return(m, -EINVAL);
246 assert_return(m->hdr, -EINVAL);
247 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
248 assert_return(ifindex, -EINVAL);
250 ifi = NLMSG_DATA(m->hdr);
252 *ifindex = ifi->ifi_index;
257 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
258 struct ifinfomsg *ifi;
260 assert_return(m, -EINVAL);
261 assert_return(m->hdr, -EINVAL);
262 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
263 assert_return(flags, -EINVAL);
265 ifi = NLMSG_DATA(m->hdr);
267 *flags = ifi->ifi_flags;
272 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
274 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
275 uint32_t rta_length, message_length;
276 struct nlmsghdr *new_hdr;
282 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
283 assert(!data || data_length > 0);
285 /* get the size of the new rta attribute (with padding at the end) */
286 rta_length = RTA_LENGTH(data_length);
287 /* get the new message size (with padding at the end)
289 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
291 /* realloc to fit the new attribute */
292 new_hdr = realloc(m->hdr, message_length);
297 /* get pointer to the attribute we are about to add */
298 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
299 /* update message size */
300 m->hdr->nlmsg_len = message_length;
302 /* we are inside a container, extend it */
303 if (m->current_container)
304 m->current_container->rta_len = (unsigned char *) m->hdr +
306 (unsigned char *) m->current_container;
308 /* fill in the attribute */
309 rta->rta_type = type;
310 rta->rta_len = rta_length;
312 /* this is a container, set pointer */
313 m->current_container = rta;
315 /* we don't deal with the case where the user lies about the type
316 * and gives us too little data (so don't do that)
318 padding = mempcpy(RTA_DATA(rta), data, data_length);
319 /* make sure also the padding at the end of the message is initialized */
320 memset(padding, '\0', (unsigned char *) m->hdr +
322 (unsigned char *) padding);
328 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
330 struct ifaddrmsg *ifa;
333 assert_return(m, -EINVAL);
334 assert_return(data, -EINVAL);
336 sd_rtnl_message_get_type(m, &rtm_type);
338 if (m->current_container) {
344 switch (m->current_container->rta_type) {
348 return add_rtattr(m, type, data, strlen(data) + 1);
369 return add_rtattr(m, type, data, strlen(data) + 1);
373 return add_rtattr(m, type, data, sizeof(uint32_t));
375 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
378 return add_rtattr(m, type, data, ETH_ALEN);
387 return add_rtattr(m, type, data, strlen(data) + 1);
392 ifa = NLMSG_DATA(m->hdr);
393 switch (ifa->ifa_family) {
395 return add_rtattr(m, type, data, sizeof(struct in_addr));
397 return add_rtattr(m, type, data, sizeof(struct in6_addr));
411 rtm = NLMSG_DATA(m->hdr);
412 switch (rtm->rtm_family) {
414 return add_rtattr(m, type, data, sizeof(struct in_addr));
416 return add_rtattr(m, type, data, sizeof(struct in6_addr));
424 return add_rtattr(m, type, data, sizeof(uint32_t));
433 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
436 assert_return(m, -EINVAL);
437 assert_return(!m->current_container, -EINVAL);
439 sd_rtnl_message_get_type(m, &rtm_type);
441 if (message_type_is_link(rtm_type)) {
442 if (type == IFLA_LINKINFO)
443 return add_rtattr(m, type, NULL, 0);
452 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
453 assert_return(m, -EINVAL);
454 assert_return(m->current_container, -EINVAL);
456 m->current_container = NULL;
461 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
470 if (!RTA_OK(m->next_rta, m->remaining_size))
473 /* make sure we don't try to read a container
474 * TODO: add support for entering containers for reading */
475 r = sd_rtnl_message_get_type(m, &rtm_type);
484 if (m->next_rta->rta_type == IFLA_LINKINFO) {
489 *data = RTA_DATA(m->next_rta);
490 *type = m->next_rta->rta_type;
492 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
497 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
501 assert_return(m, -EINVAL);
502 assert_return(data, -EINVAL);
504 r = sd_rtnl_message_get_type(m, &rtm_type);
514 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
516 m->next_rta = IFLA_RTA(ifi);
517 m->remaining_size = IFLA_PAYLOAD(m->hdr);
524 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
526 m->next_rta = IFA_RTA(ifa);
527 m->remaining_size = IFA_PAYLOAD(m->hdr);
534 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
536 m->next_rta = RTM_RTA(rtm);
537 m->remaining_size = RTM_PAYLOAD(m->hdr);
544 return message_read(m, type, data);
547 uint32_t message_get_serial(sd_rtnl_message *m) {
551 return m->hdr->nlmsg_seq;
554 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
555 struct nlmsgerr *err;
557 assert_return(m, -EINVAL);
558 assert_return(m->hdr, -EINVAL);
560 if (m->hdr->nlmsg_type != NLMSG_ERROR)
563 err = NLMSG_DATA(m->hdr);
568 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
576 m->hdr->nlmsg_seq = nl->serial++;
582 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
586 /* ioctl(rtnl->fd, FIONREAD, &need)
587 Does not appear to work on netlink sockets. libnl uses
588 MSG_PEEK instead. I don't know if that is worth the
591 For now we simply use the maximum message size the kernel
592 may use (NLMSG_GOODSIZE), and then realloc to the actual
593 size after reading the message (hence avoiding huge memory
594 usage in case many small messages are kept around) */
602 /* returns the number of bytes sent, or a negative error code */
603 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
606 struct sockaddr_nl nl;
608 .nl.nl_family = AF_NETLINK,
616 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
617 0, &addr.sa, sizeof(addr));
619 return (errno == EAGAIN) ? 0 : -errno;
624 /* On success, the number of bytes received is returned and *ret points to the received message
625 * which has a valid header and the correct size.
626 * If nothing useful was received 0 is returned.
627 * On failure, a negative error code is returned.
629 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
633 struct sockaddr_nl nl;
643 r = message_receive_need(nl, &need);
647 r = message_new(&m, need);
651 addr_len = sizeof(addr);
653 k = recvfrom(nl->fd, m->hdr, need,
654 0, &addr.sa, &addr_len);
656 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
658 k = -ECONNRESET; /* connection was closed by the kernel */
659 else if (addr_len != sizeof(addr.nl) ||
660 addr.nl.nl_family != AF_NETLINK)
661 k = -EIO; /* not a netlink message */
662 else if (addr.nl.nl_pid != 0)
663 k = 0; /* not from the kernel */
664 else if ((size_t) k < sizeof(struct nlmsghdr) ||
665 (size_t) k < m->hdr->nlmsg_len)
666 k = -EIO; /* too small (we do accept too big though) */
667 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
668 k = 0; /* not broadcast and not for us */
671 switch (m->hdr->nlmsg_type) {
672 /* check that the size matches the message type */
674 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
681 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
687 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
693 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
700 k = 0; /* ignoring message of unknown type */
704 sd_rtnl_message_unref(m);
706 /* we probably allocated way too much memory, give it back */
707 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);