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);
326 return add_rtattr(m, type, data, sizeof(uint32_t));
328 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
331 return add_rtattr(m, type, data, ETH_ALEN);
340 return add_rtattr(m, type, data, strlen(data) + 1);
345 ifa = NLMSG_DATA(m->hdr);
346 switch (ifa->ifa_family) {
348 return add_rtattr(m, type, data, sizeof(struct in_addr));
350 return add_rtattr(m, type, data, sizeof(struct in6_addr));
364 rtm = NLMSG_DATA(m->hdr);
365 switch (rtm->rtm_family) {
367 return add_rtattr(m, type, data, sizeof(struct in_addr));
369 return add_rtattr(m, type, data, sizeof(struct in6_addr));
377 return add_rtattr(m, type, data, sizeof(uint32_t));
386 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
389 assert_return(m, -EINVAL);
390 assert_return(!m->current_container, -EINVAL);
392 sd_rtnl_message_get_type(m, &rtm_type);
399 if (type == IFLA_LINKINFO)
400 return add_rtattr(m, type, NULL, 0);
410 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
411 assert_return(m, -EINVAL);
412 assert_return(m->current_container, -EINVAL);
414 m->current_container = NULL;
419 static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
428 if (!RTA_OK(m->next_rta, m->remaining_size))
431 /* make sure we don't try to read a container
432 * TODO: add support for entering containers for reading */
433 r = sd_rtnl_message_get_type(m, &rtm_type);
442 if (m->next_rta->rta_type == IFLA_LINKINFO) {
447 *data = RTA_DATA(m->next_rta);
448 *type = m->next_rta->rta_type;
450 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
455 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
459 assert_return(m, -EINVAL);
460 assert_return(data, -EINVAL);
462 r = sd_rtnl_message_get_type(m, &rtm_type);
472 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
474 m->next_rta = IFLA_RTA(ifi);
475 m->remaining_size = IFLA_PAYLOAD(m->hdr);
482 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
484 m->next_rta = IFA_RTA(ifa);
485 m->remaining_size = IFA_PAYLOAD(m->hdr);
492 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
494 m->next_rta = RTM_RTA(rtm);
495 m->remaining_size = RTM_PAYLOAD(m->hdr);
502 return message_read(m, type, data);
505 uint32_t message_get_serial(sd_rtnl_message *m) {
508 return m->hdr->nlmsg_seq;
511 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
512 struct nlmsgerr *err;
514 assert_return(m, -EINVAL);
516 if (m->hdr->nlmsg_type != NLMSG_ERROR)
519 err = NLMSG_DATA(m->hdr);
524 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
528 m->hdr->nlmsg_seq = nl->serial++;
534 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
535 assert_return(rtnl, -EINVAL);
536 assert_return(need, -EINVAL);
538 /* ioctl(rtnl->fd, FIONREAD, &need)
539 Does not appear to work on netlink sockets. libnl uses
540 MSG_PEEK instead. I don't know if that is worth the
543 For now we simply use the maximum message size the kernel
544 may use (NLMSG_GOODSIZE), and then realloc to the actual
545 size after reading the message (hence avoiding huge memory
546 usage in case many small messages are kept around) */
554 /* returns the number of bytes sent, or a negative error code */
555 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
558 struct sockaddr_nl nl;
560 .nl.nl_family = AF_NETLINK,
564 assert_return(nl, -EINVAL);
565 assert_return(m, -EINVAL);
567 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
568 0, &addr.sa, sizeof(addr));
570 return (errno == EAGAIN) ? 0 : -errno;
575 /* On success, the number of bytes received is returned and *ret points to the received message
576 * which has a valid header and the correct size.
577 * If nothing useful was received 0 is returned.
578 * On failure, a negative error code is returned.
580 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
584 struct sockaddr_nl nl;
591 assert_return(nl, -EINVAL);
592 assert_return(ret, -EINVAL);
594 r = message_receive_need(nl, &need);
598 r = message_new(&m, need);
602 addr_len = sizeof(addr);
604 k = recvfrom(nl->fd, m->hdr, need,
605 0, &addr.sa, &addr_len);
607 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
609 k = -ECONNRESET; /* connection was closed by the kernel */
610 else if (addr_len != sizeof(addr.nl) ||
611 addr.nl.nl_family != AF_NETLINK)
612 k = -EIO; /* not a netlink message */
613 else if (addr.nl.nl_pid != 0)
614 k = 0; /* not from the kernel */
615 else if ((size_t) k < sizeof(struct nlmsghdr) ||
616 (size_t) k < m->hdr->nlmsg_len)
617 k = -EIO; /* too small (we do accept too big though) */
618 else if (m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
619 k = 0; /* not for us */
622 switch (m->hdr->nlmsg_type) {
623 /* check that the size matches the message type */
625 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
632 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
638 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
645 k = 0; /* ignoring message of unknown type */
649 sd_rtnl_message_unref(m);
651 /* we probably allocated way too much memory, give it back */
652 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);