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 int type, unsigned int 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 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
227 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
228 uint32_t rta_length, message_length;
229 struct nlmsghdr *new_hdr;
235 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
236 assert(!data || data_length > 0);
238 /* get the size of the new rta attribute (with padding at the end) */
239 rta_length = RTA_LENGTH(data_length);
240 /* get the new message size (with padding at the end)
242 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
244 /* realloc to fit the new attribute */
245 new_hdr = realloc(m->hdr, message_length);
250 /* get pointer to the attribute we are about to add */
251 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
252 /* update message size */
253 m->hdr->nlmsg_len = message_length;
255 /* we are inside a container, extend it */
256 if (m->current_container)
257 m->current_container->rta_len = (unsigned char *) m->hdr +
259 (unsigned char *) m->current_container;
261 /* fill in the attribute */
262 rta->rta_type = type;
263 rta->rta_len = rta_length;
265 /* this is a container, set pointer */
266 m->current_container = rta;
268 /* we don't deal with the case where the user lies about the type
269 * and gives us too little data (so don't do that)
271 padding = mempcpy(RTA_DATA(rta), data, data_length);
272 /* make sure also the padding at the end of the message is initialized */
273 memset(padding, '\0', (unsigned char *) m->hdr +
275 (unsigned char *) padding);
281 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
283 struct ifaddrmsg *ifa;
286 assert_return(m, -EINVAL);
287 assert_return(data, -EINVAL);
289 sd_rtnl_message_get_type(m, &rtm_type);
291 if (m->current_container) {
297 switch (m->current_container->rta_type) {
301 return add_rtattr(m, type, data, strlen(data) + 1);
322 return add_rtattr(m, type, data, strlen(data) + 1);
325 return add_rtattr(m, type, data, sizeof(uint32_t));
327 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
330 return add_rtattr(m, type, data, ETH_ALEN);
339 return add_rtattr(m, type, data, strlen(data) + 1);
344 ifa = NLMSG_DATA(m->hdr);
345 switch (ifa->ifa_family) {
347 return add_rtattr(m, type, data, sizeof(struct in_addr));
349 return add_rtattr(m, type, data, sizeof(struct in6_addr));
363 rtm = NLMSG_DATA(m->hdr);
364 switch (rtm->rtm_family) {
366 return add_rtattr(m, type, data, sizeof(struct in_addr));
368 return add_rtattr(m, type, data, sizeof(struct in6_addr));
376 return add_rtattr(m, type, data, sizeof(uint32_t));
385 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
388 assert_return(m, -EINVAL);
389 assert_return(!m->current_container, -EINVAL);
391 sd_rtnl_message_get_type(m, &rtm_type);
398 if (type == IFLA_LINKINFO)
399 return add_rtattr(m, type, NULL, 0);
409 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
410 assert_return(m, -EINVAL);
411 assert_return(m->current_container, -EINVAL);
413 m->current_container = NULL;
418 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
427 if (!RTA_OK(m->next_rta, m->remaining_size))
430 /* make sure we don't try to read a container
431 * TODO: add support for entering containers for reading */
432 r = sd_rtnl_message_get_type(m, &rtm_type);
441 if (m->next_rta->rta_type == IFLA_LINKINFO) {
446 *data = RTA_DATA(m->next_rta);
447 *type = m->next_rta->rta_type;
449 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
454 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
458 assert_return(m, -EINVAL);
459 assert_return(data, -EINVAL);
461 r = sd_rtnl_message_get_type(m, &rtm_type);
471 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
473 m->next_rta = IFLA_RTA(ifi);
474 m->remaining_size = IFLA_PAYLOAD(m->hdr);
481 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
483 m->next_rta = IFA_RTA(ifa);
484 m->remaining_size = IFA_PAYLOAD(m->hdr);
491 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
493 m->next_rta = RTM_RTA(rtm);
494 m->remaining_size = RTM_PAYLOAD(m->hdr);
501 return message_read(m, type, data);
504 uint32_t message_get_serial(sd_rtnl_message *m) {
507 return m->hdr->nlmsg_seq;
510 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
511 struct nlmsgerr *err;
513 assert_return(m, -EINVAL);
515 if (m->hdr->nlmsg_type != NLMSG_ERROR)
518 err = NLMSG_DATA(m->hdr);
523 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
527 m->hdr->nlmsg_seq = nl->serial++;
533 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
534 assert_return(rtnl, -EINVAL);
535 assert_return(need, -EINVAL);
537 /* ioctl(rtnl->fd, FIONREAD, &need)
538 Does not appear to work on netlink sockets. libnl uses
539 MSG_PEEK instead. I don't know if that is worth the
542 For now we simply use the maximum message size the kernel
543 may use (NLMSG_GOODSIZE), and then realloc to the actual
544 size after reading the message (hence avoiding huge memory
545 usage in case many small messages are kept around) */
553 /* returns the number of bytes sent, or a negative error code */
554 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
557 struct sockaddr_nl nl;
559 .nl.nl_family = AF_NETLINK,
563 assert_return(nl, -EINVAL);
564 assert_return(m, -EINVAL);
566 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
567 0, &addr.sa, sizeof(addr));
569 return (errno == EAGAIN) ? 0 : -errno;
574 /* On success, the number of bytes received is returned and *ret points to the received message
575 * which has a valid header and the correct size.
576 * If nothing useful was received 0 is returned.
577 * On failure, a negative error code is returned.
579 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
583 struct sockaddr_nl nl;
590 assert_return(nl, -EINVAL);
591 assert_return(ret, -EINVAL);
593 r = message_receive_need(nl, &need);
597 r = message_new(&m, need);
601 addr_len = sizeof(addr);
603 k = recvfrom(nl->fd, m->hdr, need,
604 0, &addr.sa, &addr_len);
606 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
608 k = -ECONNRESET; /* connection was closed by the kernel */
609 else if (addr_len != sizeof(addr.nl) ||
610 addr.nl.nl_family != AF_NETLINK)
611 k = -EIO; /* not a netlink message */
612 else if (addr.nl.nl_pid != 0)
613 k = 0; /* not from the kernel */
614 else if ((size_t) k < sizeof(struct nlmsghdr) ||
615 (size_t) k < m->hdr->nlmsg_len)
616 k = -EIO; /* too small (we do accept too big though) */
617 else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
618 k = 0; /* not for us */
621 switch (m->hdr->nlmsg_type) {
622 /* check that the size matches the message type */
624 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
631 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
637 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
644 k = 0; /* ignoring message of unknown type */
648 sd_rtnl_message_unref(m);
650 /* we probably allocated way too much memory, give it back */
651 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);