3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of olsr.org, olsrd nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * Visit http://www.olsr.org for more information.
36 * If you find this software useful feel free to make a donation
37 * to the project. For more information see the website or contact
38 * the copyright holders.
42 /* must be first because of a problem with linux/rtnetlink.h */
43 #include <sys/socket.h>
45 /* and now the rest of the includes */
46 #include <linux/rtnetlink.h>
47 #include <linux/types.h>
49 #include <netinet/in.h>
50 #include <sys/ioctl.h>
54 #include "common/common_types.h"
55 #include "common/string.h"
56 #include "olsr_interface.h"
57 #include "olsr_socket.h"
59 #include "os_system.h"
61 #define OS_SYSTEM_NETLINK_TIMEOUT 100
63 static void _cb_handle_netlink_timerout(void *);
64 static void _netlink_handler(int fd, void *data,
65 bool event_read, bool event_write);
66 static void _handle_rtnetlink(struct nlmsghdr *hdr);
68 static void _handle_nl_err(struct os_system_netlink *, struct nlmsghdr *);
71 static int _ioctl_fd = -1;
73 /* static buffers for receiving/sending a netlink message */
74 static struct sockaddr_nl _netlink_nladdr = {
75 .nl_family = AF_NETLINK
78 static struct iovec _netlink_rcv_iov;
79 static struct msghdr _netlink_rcv_msg = {
81 sizeof(_netlink_nladdr),
89 static struct nlmsghdr _netlink_hdr_done = {
90 .nlmsg_len = sizeof(struct nlmsghdr),
91 .nlmsg_type = NLMSG_DONE
94 static struct iovec _netlink_send_iov[2] = {
96 { &_netlink_hdr_done, sizeof(_netlink_hdr_done) },
99 static struct msghdr _netlink_send_msg = {
101 sizeof(_netlink_nladdr),
102 &_netlink_send_iov[0],
109 /* netlink timeout handling */
110 static struct olsr_timer_info *_netlink_timer;
112 /* built in rtnetlink multicast receiver */
113 static struct os_system_netlink _rtnetlink_receiver;
115 OLSR_SUBSYSTEM_STATE(_os_system_state);
118 * Initialize os-specific subsystem
119 * @return -1 if an error happened, 0 otherwise
122 os_system_init(void) {
123 if (olsr_subsystem_is_initialized(&_os_system_state)) {
127 if ((_netlink_timer =
128 olsr_timer_add("rtnetlink feedback timer", _cb_handle_netlink_timerout, false)) == NULL) {
129 OLSR_WARN(LOG_OS_SYSTEM, "Cannot allocate timer class for netlink timeout");
133 _ioctl_fd = socket(AF_INET, SOCK_DGRAM, 0);
134 if (_ioctl_fd == -1) {
135 OLSR_WARN(LOG_OS_SYSTEM, "Cannot open ioctl socket: %s (%d)",
136 strerror(errno), errno);
137 olsr_timer_remove(_netlink_timer);
141 if (os_system_netlink_add(&_rtnetlink_receiver, NETLINK_ROUTE,
142 RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR)) {
143 olsr_timer_remove(_netlink_timer);
147 _rtnetlink_receiver.cb_message = _handle_rtnetlink;
148 olsr_subsystem_init(&_os_system_state);
153 * Cleanup os-specific subsystem
156 os_system_cleanup(void) {
157 if (olsr_subsystem_cleanup(&_os_system_state))
160 os_system_netlink_remove(&_rtnetlink_receiver);
161 olsr_timer_remove(_netlink_timer);
166 * Set interface up or down
167 * @param dev pointer to name of interface
168 * @param up true if interface should be up, false if down
169 * @return -1 if an error happened, 0 otherwise
172 os_system_set_interface_state(const char *dev, bool up) {
176 memset(&ifr, 0, sizeof(ifr));
177 strscpy(ifr.ifr_name, dev, IFNAMSIZ);
179 if (ioctl(_ioctl_fd, SIOCGIFFLAGS, &ifr) < 0) {
180 OLSR_WARN(LOG_OS_SYSTEM,
181 "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
182 dev, strerror(errno), errno);
186 oldflags = ifr.ifr_flags;
188 ifr.ifr_flags |= IFF_UP;
191 ifr.ifr_flags &= ~IFF_UP;
194 if (oldflags == ifr.ifr_flags) {
195 /* interface is already up/down */
199 if (ioctl(_ioctl_fd, SIOCSIFFLAGS, &ifr) < 0) {
200 OLSR_WARN(LOG_OS_SYSTEM,
201 "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
202 up ? "up" : "down", dev, strerror(errno), errno);
209 * Open a new bidirectional netlink socket
210 * @param nl pointer to uninitialized netlink socket handler
211 * @param protocol protocol id (NETLINK_ROUTING for example)
212 * @param multicast multicast groups this socket should listen to
213 * @return -1 if an error happened, 0 otherwise
216 os_system_netlink_add(struct os_system_netlink *nl, int protocol, uint32_t multicast) {
217 struct sockaddr_nl addr;
219 memset(nl, 0, sizeof(*nl));
221 nl->socket.fd = socket(PF_NETLINK, SOCK_RAW, protocol);
222 if (nl->socket.fd < 0) {
223 OLSR_WARN(LOG_OS_SYSTEM, "Cannot open sync rtnetlink socket: %s (%d)",
224 strerror(errno), errno);
225 goto os_add_netlink_fail;
228 if (abuf_init(&nl->out)) {
229 OLSR_WARN_OOM(LOG_OS_SYSTEM);
230 goto os_add_netlink_fail;
233 nl->in = calloc(1, UIO_MAXIOV);
234 if (nl->in == NULL) {
235 OLSR_WARN_OOM(LOG_OS_SYSTEM);
236 goto os_add_netlink_fail;
240 memset(&addr, 0, sizeof(addr));
241 addr.nl_family = AF_NETLINK;
242 addr.nl_groups = multicast;
244 /* kernel will assign appropriate number instead of pid */
245 /* addr.nl_pid = 0; */
247 if (bind(nl->socket.fd, (struct sockaddr *)&addr, sizeof(addr))<0) {
248 OLSR_WARN(LOG_OS_SYSTEM, "Could not bind netlink socket: %s (%d)",
249 strerror(errno), errno);
250 goto os_add_netlink_fail;
253 nl->socket.process = _netlink_handler;
254 nl->socket.event_read = true;
255 nl->socket.data = nl;
256 olsr_socket_add(&nl->socket);
261 if (nl->socket.fd != -1) {
262 close(nl->socket.fd);
270 * Close a netlink socket handler
271 * @param nl pointer to handler
274 os_system_netlink_remove(struct os_system_netlink *nl) {
275 olsr_socket_remove(&nl->socket);
277 close(nl->socket.fd);
283 * Add a netlink message to the outgoign queue of a handler
284 * @param nl pointer to netlink handler
285 * @param nl_hdr pointer to netlink message
286 * @return sequence number used for message
289 os_system_netlink_send(struct os_system_netlink *nl,
290 struct nlmsghdr *nl_hdr) {
293 nl_hdr->nlmsg_seq = nl->seq_used;
294 nl_hdr->nlmsg_flags |= NLM_F_ACK | NLM_F_MULTI;
296 abuf_memcpy(&nl->out, nl_hdr, nl_hdr->nlmsg_len);
299 olsr_socket_set_write(&nl->socket, true);
304 * Add an attribute to a netlink message
305 * @param n pointer to netlink header
306 * @param type type of netlink attribute
307 * @param data pointer to data of netlink attribute
308 * @param len length of data of netlink attribute
309 * @return -1 if netlink message got too large, 0 otherwise
312 os_system_netlink_addreq(struct nlmsghdr *n,
313 int type, const void *data, int len)
316 size_t aligned_msg_len, aligned_attr_len;
318 /* calculate aligned length of message and new attribute */
319 aligned_msg_len = NLMSG_ALIGN(n->nlmsg_len);
320 aligned_attr_len = RTA_LENGTH(len);
322 if (aligned_msg_len + aligned_attr_len > UIO_MAXIOV) {
323 OLSR_WARN(LOG_OS_SYSTEM, "Netlink message got too large!");
326 rta = (struct rtattr *)((void*)((char *)n + aligned_msg_len));
327 rta->rta_type = type;
328 rta->rta_len = aligned_attr_len;
330 n->nlmsg_len = aligned_msg_len + aligned_attr_len;
332 memcpy(RTA_DATA(rta), data, len);
337 * Handle timeout of netlink acks
338 * @param ptr pointer to netlink handler
341 _cb_handle_netlink_timerout(void *ptr) {
342 struct os_system_netlink *nl = ptr;
346 if (nl->cb_timeout) {
354 * Send all netlink messages in the outgoing queue to the kernel
355 * @param nl pointer to netlink handler
358 _flush_netlink_buffer(struct os_system_netlink *nl) {
361 /* start feedback timer */
362 olsr_timer_set(&nl->timeout, OS_SYSTEM_NETLINK_TIMEOUT*10, 0, nl, _netlink_timer);
364 /* send outgoing message */
365 _netlink_send_iov[0].iov_base = abuf_getptr(&nl->out);
366 _netlink_send_iov[0].iov_len = abuf_getlen(&nl->out);
368 if ((ret = sendmsg(nl->socket.fd, &_netlink_send_msg, 0)) <= 0) {
369 OLSR_WARN(LOG_OS_SYSTEM,
370 "Cannot send data to netlink socket (%d: %s)",
371 errno, strerror(errno));
374 OLSR_DEBUG(LOG_OS_SYSTEM, "Sent %zd/%zu bytes for netlink seqno: %d",
375 ret, abuf_getlen(&nl->out), nl->seq_used);
376 nl->seq_sent = nl->seq_used;
377 abuf_clear(&nl->out);
379 olsr_socket_set_write(&nl->socket, false);
384 * Handler for incoming async netlink messages
391 _netlink_handler(int fd, void *data, bool event_read, bool event_write) {
392 struct os_system_netlink *nl;
397 OLSR_DEBUG(LOG_OS_SYSTEM, "Got netlink message (%d/%d)", event_read, event_write);
400 _flush_netlink_buffer(nl);
407 /* handle incoming messages */
408 _netlink_rcv_iov.iov_base = nl->in;
409 _netlink_rcv_iov.iov_len = UIO_MAXIOV;
410 if ((ret = recvmsg(fd, &_netlink_rcv_msg, MSG_DONTWAIT)) < 0) {
411 if (errno != EAGAIN) {
412 OLSR_WARN(LOG_OS_SYSTEM,"netlink recvmsg error: %s (%d)\n",
413 strerror(errno), errno);
418 /* loop through netlink headers */
420 for (nh = nl->in; NLMSG_OK (nh, len); nh = NLMSG_NEXT (nh, len)) {
421 OLSR_DEBUG(LOG_OS_SYSTEM,
422 "Netlink message received: type %d\n", nl->in->nlmsg_type);
424 switch (nh->nlmsg_type) {
429 /* End of a multipart netlink message reached */
433 /* Feedback for async netlink message */
434 _handle_nl_err(nl, nh);
438 if (nl->cb_message) {
447 * Handle incoming rtnetlink multicast messages for interface listeners
448 * @param hdr pointer to netlink message
451 _handle_rtnetlink(struct nlmsghdr *hdr) {
452 struct ifinfomsg *ifi;
453 struct ifaddrmsg *ifa;
455 char if_name[IF_NAMESIZE];
457 if (hdr->nlmsg_type == RTM_NEWLINK || hdr->nlmsg_type == RTM_DELLINK) {
458 ifi = (struct ifinfomsg *) NLMSG_DATA(hdr);
460 if (if_indextoname(ifi->ifi_index, if_name) == NULL) {
461 OLSR_WARN(LOG_OS_SYSTEM,
462 "Failed to convert if-index to name: %d", ifi->ifi_index);
466 OLSR_DEBUG(LOG_OS_SYSTEM, "Linkstatus of interface '%s' changed", if_name);
467 olsr_interface_trigger_change(if_name);
470 else if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_type == RTM_DELADDR) {
471 ifa = (struct ifaddrmsg *) NLMSG_DATA(hdr);
473 if (if_indextoname(ifa->ifa_index, if_name) == NULL) {
474 OLSR_WARN(LOG_OS_SYSTEM,
475 "Failed to convert if-index to name: %d", ifa->ifa_index);
479 OLSR_DEBUG(LOG_OS_SYSTEM, "Address of interface '%s' changed", if_name);
480 olsr_interface_trigger_change(if_name);
485 * Handle result code in netlink message
486 * @param nl pointer to netlink handler
487 * @param nh pointer to netlink message
490 _handle_nl_err(struct os_system_netlink *nl, struct nlmsghdr *nh) {
491 struct nlmsgerr *err;
493 err = (struct nlmsgerr *) NLMSG_DATA(nh);
495 OLSR_DEBUG(LOG_OS_SYSTEM, "Received netlink feedback (%u bytes): %d",
496 nh->nlmsg_len, err->error);
498 if (nl->cb_feedback) {
499 nl->cb_feedback(err->msg.nlmsg_seq, err->error);
501 if (nl->msg_in_transit > 0) {
502 nl->msg_in_transit--;
504 if (nl->msg_in_transit == 0) {
505 olsr_timer_stop(nl->timeout);