Fixes for netlink layer to prevent overloading from multiple triggered
[oonf.git] / src-plugins / subsystems / os_linux / os_interface_linux.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
16  *   distribution.
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.
20  *
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.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
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.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 /*! activate GUI sources for this file */
47 #define _GNU_SOURCE
48
49 /* must be first because of a problem with linux/rtnetlink.h */
50 #include <sys/socket.h>
51
52 /* and now the rest of the includes */
53 #include <linux/types.h>
54 #include <linux/netlink.h>
55 #include <linux/rtnetlink.h>
56 #include <linux/socket.h>
57 #include <sys/ioctl.h>
58 #include <sys/stat.h>
59 #include <sys/uio.h>
60 #include <sys/types.h>
61 #include <fcntl.h>
62 #include <ifaddrs.h>
63 #include <net/if.h>
64 #include <netinet/in.h>
65 #include <errno.h>
66 #include <unistd.h>
67 #include <sys/time.h>
68 #include <time.h>
69
70 #include "common/common_types.h"
71 #include "common/avl.h"
72 #include "common/avl_comp.h"
73 #include "common/string.h"
74 #include "core/oonf_cfg.h"
75 #include "core/oonf_main.h"
76 #include "core/oonf_subsystem.h"
77 #include "subsystems/oonf_class.h"
78 #include "subsystems/oonf_timer.h"
79 #include "subsystems/os_system.h"
80
81 #include "subsystems/os_interface.h"
82
83 /* Definitions */
84 #define LOG_OS_INTERFACE _oonf_os_interface_subsystem.logging
85
86 /*! proc file entry for activating IPv4 forwarding */
87 #define PROC_IPFORWARD_V4 "/proc/sys/net/ipv4/ip_forward"
88
89 /*! proc file entry for activating IPv6 forwarding */
90 #define PROC_IPFORWARD_V6 "/proc/sys/net/ipv6/conf/all/forwarding"
91
92 /*! proc file entry to deactivate interface specific redirect requests */
93 #define PROC_IF_REDIRECT "/proc/sys/net/ipv4/conf/%s/send_redirects"
94
95 /*! proc file entry to deactivate generic redirect requests */
96 #define PROC_ALL_REDIRECT "/proc/sys/net/ipv4/conf/all/send_redirects"
97
98 /*! proc file entry to deactivate interface specific reverse path filter */
99 #define PROC_IF_SPOOF "/proc/sys/net/ipv4/conf/%s/rp_filter"
100
101 /*! proc file entry to deactivate generic reverse path filter */
102 #define PROC_ALL_SPOOF "/proc/sys/net/ipv4/conf/all/rp_filter"
103
104 /* prototypes */
105 static int _init(void);
106 static void _cleanup(void);
107 static void _early_cfg_init(void);
108
109 static struct os_interface *_add_interface(const char *name);
110 static void _remove_interface(struct os_interface *data);
111
112 static void _init_mesh(struct os_interface *os_if);
113 static void _refresh_mesh(struct os_interface *os_if, char *old_redirect, char *old_spoof);
114 static void _cleanup_mesh(struct os_interface *os_if);
115
116 static void _query_interface_links(void);
117 static void _query_interface_addresses(void);
118
119 static void _cb_rtnetlink_message(struct nlmsghdr *hdr);
120 static void _cb_rtnetlink_error(uint32_t seq, int error);
121 static void _cb_rtnetlink_done(uint32_t seq);
122 static void _cb_rtnetlink_timeout(void);
123 static void _cb_query_error(uint32_t seq, int error);
124 static void _cb_query_done(uint32_t seq);
125 static void _cb_query_timeout(void);
126 static void _address_finished(
127     struct os_interface_ip_change *addr, int error);
128
129 static void _activate_if_routing(void);
130 static void _deactivate_if_routing(void);
131 static int _os_linux_writeToFile(const char *file, char *old, char value);
132
133 static void _cb_delayed_interface_changed(struct oonf_timer_instance *);
134 static int _handle_unused_parameter(const char *arg);
135 static void _cb_cfg_changed(void);
136
137 /* subsystem configuration */
138 static struct cfg_schema_entry _interface_entries[] = {
139   CFG_MAP_BOOL(os_interface, _internal.ignore_mesh, "ignore_mesh", "false",
140     "Suppress os mesh interface configuration"),
141 };
142
143 static struct cfg_schema_section _interface_section = {
144   .type = CFG_INTERFACE_SECTION,
145   .mode = CFG_INTERFACE_SECTION_MODE,
146   .cb_delta_handler = _cb_cfg_changed,
147   .entries = _interface_entries,
148   .entry_count = ARRAYSIZE(_interface_entries),
149 };
150
151 /* subsystem definition */
152 static const char *_dependencies[] = {
153   OONF_CLASS_SUBSYSTEM,
154   OONF_TIMER_SUBSYSTEM,
155   OONF_OS_SYSTEM_SUBSYSTEM,
156 };
157
158 static struct oonf_subsystem _oonf_os_interface_subsystem = {
159   .name = OONF_OS_INTERFACE_SUBSYSTEM,
160   .dependencies = _dependencies,
161   .dependencies_count = ARRAYSIZE(_dependencies),
162   .init = _init,
163   .cleanup = _cleanup,
164   .early_cfg_init = _early_cfg_init,
165   .cfg_section = &_interface_section,
166 };
167 DECLARE_OONF_PLUGIN(_oonf_os_interface_subsystem);
168
169 /* rtnetlink receiver for interface and address events */
170 static struct os_system_netlink _rtnetlink_receiver = {
171   .name = "interface snooper",
172   .used_by = &_oonf_os_interface_subsystem,
173   .cb_message = _cb_rtnetlink_message,
174   .cb_error = _cb_rtnetlink_error,
175   .cb_done = _cb_rtnetlink_done,
176   .cb_timeout = _cb_rtnetlink_timeout,
177 };
178
179 static struct list_entity _rtnetlink_feedback;
180
181 static const uint32_t _rtnetlink_mcast[] = {
182   RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR
183 };
184
185 static struct os_system_netlink _rtnetlink_if_query = {
186   .name = "interface query",
187   .used_by = &_oonf_os_interface_subsystem,
188   .cb_message = _cb_rtnetlink_message,
189   .cb_error = _cb_query_error,
190   .cb_done = _cb_query_done,
191   .cb_timeout = _cb_query_timeout,
192 };
193
194 static bool _link_query_in_progress = false;
195 static bool _address_query_in_progress = false;
196 static bool _trigger_link_query = false;
197 static bool _trigger_address_query = false;
198
199 /* global procfile state before initialization */
200 static char _original_rp_filter;
201 static char _original_icmp_redirect;
202 static char _original_ipv4_forward;
203 static char _original_ipv6_forward;
204
205 /* counter of mesh interfaces for ip_forward configuration */
206 static int _mesh_count = 0;
207
208 /* kernel version check */
209 static bool _is_kernel_2_6_31_or_better;
210
211 /* interface data handling */
212 static struct oonf_class _interface_data_class = {
213   .name = "network interface data",
214   .size = sizeof(struct os_interface),
215 };
216
217 static struct oonf_class _interface_class = {
218   .name = "network interface",
219   .size = sizeof(struct os_interface_listener),
220 };
221
222 static struct oonf_class _interface_ip_class = {
223   .name = "network interface ip",
224   .size = sizeof(struct os_interface_ip),
225 };
226
227 static struct oonf_timer_class _interface_change_timer = {
228   .name = "interface change",
229   .callback = _cb_delayed_interface_changed,
230 };
231
232 static struct avl_tree _interface_data_tree;
233 static const char _ANY_INTERFACE[] = OS_INTERFACE_ANY;
234
235 /**
236  * Initialize os-specific subsystem
237  * @return -1 if an error happened, 0 otherwise
238  */
239 static int
240 _init(void) {
241   if (os_system_linux_netlink_add(&_rtnetlink_receiver, NETLINK_ROUTE)) {
242     return -1;
243   }
244
245   if (os_system_linux_netlink_add(&_rtnetlink_if_query, NETLINK_ROUTE)) {
246     os_system_linux_netlink_remove(&_rtnetlink_receiver);
247     return -1;
248   }
249
250   if (os_system_linux_netlink_add_mc(&_rtnetlink_receiver, _rtnetlink_mcast, ARRAYSIZE(_rtnetlink_mcast))) {
251     os_system_linux_netlink_remove(&_rtnetlink_receiver);
252     os_system_linux_netlink_remove(&_rtnetlink_if_query);
253     return -1;
254   }
255
256   list_init_head(&_rtnetlink_feedback);
257   avl_init(&_interface_data_tree, avl_comp_strcasecmp, false);
258   oonf_class_add(&_interface_data_class);
259   oonf_class_add(&_interface_ip_class);
260   oonf_class_add(&_interface_class);
261   oonf_timer_add(&_interface_change_timer);
262
263   _is_kernel_2_6_31_or_better = os_system_linux_is_minimal_kernel(2,6,31);
264
265   return 0;
266 }
267
268 /**
269  * Cleanup os-specific subsystem
270  */
271 static void
272 _cleanup(void) {
273   struct os_interface_listener *if_listener, *if_listener_it;
274   struct os_interface *os_if, *os_if_it;
275   bool configured;
276
277   avl_for_each_element_safe(&_interface_data_tree, os_if, _node, os_if_it) {
278     configured = os_if->_internal.configured;
279     list_for_each_element_safe(&os_if->_listeners, if_listener, _node, if_listener_it) {
280       os_interface_linux_remove(if_listener);
281     }
282
283     if (configured) {
284       os_if->_internal.configured = false;
285       _remove_interface(os_if);
286     }
287   }
288
289   oonf_timer_remove(&_interface_change_timer);
290   oonf_class_remove(&_interface_ip_class);
291   oonf_class_remove(&_interface_data_class);
292   oonf_class_remove(&_interface_class);
293
294   os_system_linux_netlink_remove(&_rtnetlink_if_query);
295   os_system_linux_netlink_remove(&_rtnetlink_receiver);
296 }
297
298 /**
299  * Handle pre-configuration work
300  */
301 static
302 void _early_cfg_init(void) {
303   oonf_main_set_parameter_handler(_handle_unused_parameter);
304 }
305
306 /**
307  * Add an interface event listener to the operation system
308  * @param if_listener network interface listener
309  */
310 struct os_interface *
311 os_interface_linux_add(struct os_interface_listener *if_listener) {
312   struct os_interface *data;
313
314   if (if_listener->data) {
315     /* interface is already hooked up to data */
316     return if_listener->data;
317   }
318
319   if (!if_listener->name || !if_listener->name[0]) {
320     if_listener->name = _ANY_INTERFACE;
321   }
322
323   data = _add_interface(if_listener->name);
324   if (!data) {
325     return NULL;
326   }
327
328   /* hook into interface data */
329   if_listener->data = data;
330   list_add_tail(&data->_listeners, &if_listener->_node);
331
332   if (if_listener->mesh && if_listener->name != _ANY_INTERFACE) {
333     if (data->_internal.mesh_counter == 0
334         && !data->_internal.ignore_mesh) {
335       _init_mesh(data);
336     }
337     data->_internal.mesh_counter++;
338   }
339
340   /* trigger interface change listener if necessary */
341   if_listener->_dirty = true;
342   oonf_timer_start(&data->_change_timer, 200);
343
344   return data;
345 }
346
347 /**
348  * Remove an interface event listener to the operation system
349  * @param if_listener network interface listener
350  */
351 void
352 os_interface_linux_remove(struct os_interface_listener *if_listener) {
353   struct os_interface *data;
354
355   if (!if_listener->data) {
356     /* interface not hooked up to data */
357     return;
358   }
359
360   OONF_INFO(LOG_OS_INTERFACE, "Remove interface from tracking: %s", if_listener->name);
361
362   if (if_listener->mesh) {
363     if_listener->data->_internal.mesh_counter--;
364     if (!if_listener->data->_internal.mesh_counter) {
365       _cleanup_mesh(if_listener->data);
366     }
367   }
368
369   /* unhook from interface data */
370   data = if_listener->data;
371   if_listener->data = NULL;
372   list_remove(&if_listener->_node);
373
374   /* remove interface if not used anymore */
375   _remove_interface(data);
376 }
377
378 /**
379  * @return tree of os interfaces
380  */
381 struct avl_tree *
382 os_interface_linux_get_tree(void) {
383   return &_interface_data_tree;
384 }
385
386 /**
387  * Trigger the event handler of an interface listener
388  * @param if_listener network interface listener
389  */
390 void
391 os_interface_linux_trigger_handler(struct os_interface_listener *if_listener) {
392   if_listener->_dirty = true;
393   if (!oonf_timer_is_active(&if_listener->data->_change_timer)) {
394     oonf_timer_start(&if_listener->data->_change_timer,
395         OS_INTERFACE_CHANGE_TRIGGER_INTERVAL);
396   }
397 }
398 /**
399  * Set interface up or down
400  * @param os_if network interface
401  * @param up true if interface should be up, false if down
402  * @return -1 if an error happened, 0 otherwise
403  */
404 int
405 os_interface_linux_state_set(struct os_interface *os_if, bool up) {
406   int oldflags;
407   struct ifreq ifr;
408
409   memset(&ifr, 0, sizeof(ifr));
410   strscpy(ifr.ifr_name, os_if->name, IF_NAMESIZE);
411
412   if (ioctl(os_system_linux_linux_get_ioctl_fd(AF_INET),
413       SIOCGIFFLAGS, &ifr) < 0) {
414     OONF_WARN(LOG_OS_INTERFACE,
415         "ioctl SIOCGIFFLAGS (get flags) error on device %s: %s (%d)\n",
416         os_if->name, strerror(errno), errno);
417     return -1;
418   }
419
420   oldflags = ifr.ifr_flags;
421   if (up) {
422     ifr.ifr_flags |= IFF_UP;
423   }
424   else {
425     ifr.ifr_flags &= ~IFF_UP;
426   }
427
428   if (oldflags == ifr.ifr_flags) {
429     /* interface is already up/down */
430     return 0;
431   }
432
433   if (ioctl(os_system_linux_linux_get_ioctl_fd(AF_INET),
434       SIOCSIFFLAGS, &ifr) < 0) {
435     OONF_WARN(LOG_OS_INTERFACE,
436         "ioctl SIOCSIFFLAGS (set flags %s) error on device %s: %s (%d)\n",
437         up ? "up" : "down", os_if->name, strerror(errno), errno);
438     return -1;
439   }
440   return 0;
441 }
442
443 /**
444  * Set or remove an IP address from an interface
445  * @param addr interface address change request
446  * @return -1 if the request could not be sent to the server,
447  *   0 otherwise
448  */
449 int
450 os_interface_linux_address_set(
451     struct os_interface_ip_change *addr) {
452   uint8_t buffer[UIO_MAXIOV];
453   struct nlmsghdr *msg;
454   struct ifaddrmsg *ifaddrreq;
455   int seq;
456 #if defined(OONF_LOG_DEBUG_INFO)
457   struct netaddr_str nbuf;
458 #endif
459
460   memset(buffer, 0, sizeof(buffer));
461
462   /* get pointers for netlink message */
463   msg = (void *)&buffer[0];
464
465   if (addr->set) {
466     msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
467     msg->nlmsg_type = RTM_NEWADDR;
468   }
469   else {
470     msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
471     msg->nlmsg_type = RTM_DELADDR;
472   }
473
474   /* set length of netlink message with ifaddrmsg payload */
475   msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
476
477   OONF_DEBUG(LOG_OS_INTERFACE, "%sset address on if %d: %s",
478       addr->set ? "" : "re", addr->if_index,
479       netaddr_to_string(&nbuf, &addr->address));
480
481   ifaddrreq = NLMSG_DATA(msg);
482   ifaddrreq->ifa_family = netaddr_get_address_family(&addr->address);
483   ifaddrreq->ifa_prefixlen = netaddr_get_prefix_length(&addr->address);
484   ifaddrreq->ifa_index= addr->if_index;
485   ifaddrreq->ifa_scope = addr->scope;
486
487   if (os_system_linux_netlink_addnetaddr(&_rtnetlink_receiver,
488       msg, IFA_LOCAL, &addr->address)) {
489     return -1;
490   }
491
492   /* cannot fail */
493   seq = os_system_linux_netlink_send(&_rtnetlink_receiver, msg);
494
495   if (addr->cb_finished) {
496     list_add_tail(&_rtnetlink_feedback, &addr->_internal._node);
497     addr->_internal.nl_seq = seq;
498   }
499   return 0;
500 }
501
502 /**
503  * Stop processing an interface address change
504  * @param addr interface address change request
505  */
506 void
507 os_interface_linux_address_interrupt(struct os_interface_ip_change *addr) {
508   if (list_is_node_added(&addr->_internal._node)) {
509     /* remove first to prevent any kind of recursive cleanup */
510     list_remove(&addr->_internal._node);
511
512     if (addr->cb_finished) {
513       addr->cb_finished(addr, -1);
514     }
515   }
516 }
517
518 /**
519  * Set the mac address of an interface
520  * @param os_if network interface
521  * @param mac mac address
522  * @return -1 if an error happened, 0 otherwise
523  */
524 int
525 os_interface_linux_mac_set(struct os_interface *os_if, struct netaddr *mac) {
526   struct ifreq if_req;
527   struct netaddr_str nbuf;
528
529   if (netaddr_get_address_family(mac) != AF_MAC48) {
530     OONF_WARN(LOG_OS_INTERFACE, "Interface MAC must mac48, not %s",
531         netaddr_to_string(&nbuf, mac));
532     return -1;
533   }
534
535   memset(&if_req, 0, sizeof(if_req));
536   strscpy(if_req.ifr_name, os_if->name, IF_NAMESIZE);
537
538   if_req.ifr_addr.sa_family = ARPHRD_ETHER;
539   netaddr_to_binary(&if_req.ifr_addr.sa_data, mac, 6);
540
541   if (ioctl(os_system_linux_linux_get_ioctl_fd(AF_INET), SIOCSIFHWADDR, &if_req) < 0) {
542     OONF_WARN(LOG_OS_INTERFACE, "Could not set mac address of '%s': %s (%d)",
543         os_if->name, strerror(errno), errno);
544     return -1;
545   }
546   return 0;
547 }
548
549 /**
550  * Add an interface to the database if not already there
551  * @param name interface name
552  * @return interface representation, NULL if out of memory
553  */
554 static struct os_interface *
555 _add_interface(const char *name) {
556   struct os_interface *data;
557   data = avl_find_element(&_interface_data_tree, name, data, _node);
558   if (!data) {
559     data = oonf_class_malloc(&_interface_data_class);
560     if (!data) {
561       return NULL;
562     }
563
564     OONF_INFO(LOG_OS_INTERFACE, "Add interface to tracking: %s", name);
565
566     /* hook into interface data tree */
567     strscpy(data->name, name, IF_NAMESIZE);
568     data->_node.key = data->name;
569     avl_insert(&_interface_data_tree, &data->_node);
570
571     /* initialize list/tree */
572     avl_init(&data->addresses, avl_comp_netaddr, false);
573     avl_init(&data->peers, avl_comp_netaddr, false);
574     list_init_head(&data->_listeners);
575
576     /* initialize change timer */
577     data->_change_timer.class = &_interface_change_timer;
578
579     /* check if this is the unspecified interface "any" */
580     if (strcmp(data->name, _ANY_INTERFACE) == 0) {
581       data->flags.any = true;
582       data->flags.up = true;
583     }
584
585     /* trigger new queries */
586     _trigger_link_query = true;
587     _trigger_address_query = true;
588
589     data->if_linklocal_v4 = &NETADDR_UNSPEC;
590     data->if_linklocal_v6 = &NETADDR_UNSPEC;
591     data->if_v4 = &NETADDR_UNSPEC;
592     data->if_v6 = &NETADDR_UNSPEC;
593     _query_interface_links();
594   }
595
596   return data;
597 }
598
599 /**
600  * Remove an interface from the database if not used anymore
601  * @param data interface representation
602  */
603 static void
604 _remove_interface(struct os_interface *data) {
605   struct os_interface_ip *ip, *ip_iter;
606
607   if (!list_is_empty(&data->_listeners) || data->_internal.configured) {
608     return;
609   }
610
611   if (data->flags.mesh) {
612     _cleanup_mesh(data);
613   }
614
615   /* remove all addresses */
616   avl_for_each_element_safe(&data->addresses, ip, _node, ip_iter) {
617     avl_remove(&data->addresses, &ip->_node);
618     oonf_class_free(&_interface_ip_class, ip);
619   }
620   avl_for_each_element_safe(&data->peers, ip, _node, ip_iter) {
621     avl_remove(&data->peers, &ip->_node);
622     oonf_class_free(&_interface_ip_class, ip);
623   }
624
625   /* stop change timer */
626   oonf_timer_stop(&data->_change_timer);
627
628   /* remove interface */
629   avl_remove(&_interface_data_tree, &data->_node);
630   oonf_class_free(&_interface_data_class, data);
631 }
632
633 /**
634  * Initialize interface for mesh usage
635  * @param os_if network interface data
636  */
637 static void
638 _init_mesh(struct os_interface *os_if) {
639   if (os_if->flags.loopback || os_if->flags.any) {
640     /* ignore loopback and unspecific interface*/
641     return;
642   }
643
644   if (os_if->flags.mesh) {
645     /* mesh settings already active or not used for this interface */
646     return;
647   }
648   os_if->flags.mesh = true;
649
650   OONF_DEBUG(LOG_OS_INTERFACE, "Init mesh: %s", os_if->name);
651
652   /* handle global ip_forward setting */
653   _mesh_count++;
654   if (_mesh_count == 1) {
655     _activate_if_routing();
656   }
657
658   _refresh_mesh(os_if,
659       &os_if->_internal._original_icmp_redirect,
660       &os_if->_internal._original_ip_spoof);
661 }
662
663 static void
664 _refresh_mesh(struct os_interface *os_if, char *old_redirect, char *old_spoof) {
665   char procfile[FILENAME_MAX];
666   if (os_if->flags.loopback || os_if->flags.any) {
667     /* ignore loopback and unspecific interface*/
668     return;
669   }
670
671   if (!os_if->flags.mesh) {
672     /* this is no mesh interface */
673     return;
674   }
675
676   OONF_DEBUG(LOG_OS_INTERFACE, "Refresh mesh: %s", os_if->name);
677
678   /* Generate the procfile name */
679   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, os_if->name);
680
681   if (_os_linux_writeToFile(procfile, old_redirect, '0')) {
682     OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not disable ICMP redirects! "
683         "You should manually ensure that ICMP redirects are disabled!");
684   }
685
686   /* Generate the procfile name */
687   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, os_if->name);
688
689   if (_os_linux_writeToFile(procfile, old_spoof, '0')) {
690     OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not disable the IP spoof filter! "
691         "You should mannually ensure that IP spoof filtering is disabled!");
692   }
693 }
694
695 /**
696  * Cleanup interface after mesh usage
697  * @param os_if network interface
698  */
699 static void
700 _cleanup_mesh(struct os_interface *os_if) {
701   char procfile[FILENAME_MAX];
702
703   if (os_if->flags.loopback || os_if->flags.any) {
704     /* ignore loopback and unspecific interface*/
705     return;
706   }
707
708   if (!os_if->flags.mesh) {
709     /* mesh settings not active */
710     return;
711   }
712
713   OONF_DEBUG(LOG_OS_INTERFACE, "Cleanup mesh: %s", os_if->name);
714
715   /* Generate the procfile name */
716   snprintf(procfile, sizeof(procfile), PROC_IF_REDIRECT, os_if->name);
717
718   if (_os_linux_writeToFile(procfile, NULL,
719       os_if->_internal._original_icmp_redirect) != 0) {
720     OONF_WARN(LOG_OS_INTERFACE, "Could not restore ICMP redirect flag %s to %c",
721         procfile, os_if->_internal._original_icmp_redirect);
722   }
723
724   /* Generate the procfile name */
725   snprintf(procfile, sizeof(procfile), PROC_IF_SPOOF, os_if->name);
726
727   if (_os_linux_writeToFile(procfile, NULL,
728       os_if->_internal._original_ip_spoof) != 0) {
729     OONF_WARN(LOG_OS_INTERFACE, "Could not restore IP spoof flag %s to %c",
730         procfile, os_if->_internal._original_ip_spoof);
731   }
732
733   /* handle global ip_forward setting */
734   _mesh_count--;
735   if (_mesh_count == 0) {
736     _deactivate_if_routing();
737   }
738
739   return;
740 }
741
742 /**
743  * Set the required settings to allow multihop mesh routing
744  */
745 static void
746 _activate_if_routing(void) {
747   if (_os_linux_writeToFile(PROC_IPFORWARD_V4, &_original_ipv4_forward, '1')) {
748     OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not activate ip_forward for ipv4! "
749         "You should manually ensure that ip_forward for ipv4 is activated!");
750   }
751   if (os_system_is_ipv6_supported()) {
752     if(_os_linux_writeToFile(PROC_IPFORWARD_V6, &_original_ipv6_forward, '1')) {
753       OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not activate ip_forward for ipv6! "
754           "You should manually ensure that ip_forward for ipv6 is activated!");
755     }
756   }
757
758   if (_os_linux_writeToFile(PROC_ALL_REDIRECT, &_original_icmp_redirect, '0')) {
759     OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not disable ICMP redirects! "
760         "You should manually ensure that ICMP redirects are disabled!");
761   }
762
763   /* check kernel version and disable global rp_filter */
764   if (_is_kernel_2_6_31_or_better) {
765     if (_os_linux_writeToFile(PROC_ALL_SPOOF, &_original_rp_filter, '0')) {
766       OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not disable global rp_filter "
767           "(necessary for kernel 2.6.31 and newer)! You should manually "
768           "ensure that rp_filter is disabled!");
769     }
770   }
771 }
772
773 /**
774  * Reset the multihop mesh routing settings to default
775  */
776 static void
777 _deactivate_if_routing(void) {
778   if (_os_linux_writeToFile(PROC_ALL_REDIRECT, NULL, _original_icmp_redirect) != 0) {
779     OONF_WARN(LOG_OS_INTERFACE,
780         "WARNING! Could not restore ICMP redirect flag %s to %c!",
781         PROC_ALL_REDIRECT, _original_icmp_redirect);
782   }
783
784   if (_os_linux_writeToFile(PROC_ALL_SPOOF, NULL, _original_rp_filter)) {
785     OONF_WARN(LOG_OS_INTERFACE,
786         "WARNING! Could not restore global rp_filter flag %s to %c!",
787         PROC_ALL_SPOOF, _original_rp_filter);
788   }
789
790   if (_os_linux_writeToFile(PROC_IPFORWARD_V4, NULL, _original_ipv4_forward)) {
791     OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not restore %s to %c!",
792         PROC_IPFORWARD_V4, _original_ipv4_forward);
793   }
794   if (os_system_is_ipv6_supported()) {
795     if (_os_linux_writeToFile(PROC_IPFORWARD_V6, NULL, _original_ipv6_forward)) {
796       OONF_WARN(LOG_OS_INTERFACE, "WARNING! Could not restore %s to %c",
797           PROC_IPFORWARD_V6, _original_ipv6_forward);
798     }
799   }
800 }
801
802 /**
803  * Overwrite a numeric entry in the procfile system and keep the old
804  * value.
805  * @param file pointer to filename (including full path)
806  * @param old pointer to memory to store old value
807  * @param value new value
808  * @return -1 if an error happened, 0 otherwise
809  */
810 static int
811 _os_linux_writeToFile(const char *file, char *old, char value) {
812   int fd;
813   char rv;
814
815   if (value == 0) {
816     /* ignore */
817     return 0;
818   }
819
820   if ((fd = open(file, O_RDWR)) < 0) {
821     OONF_WARN(LOG_OS_INTERFACE,
822       "Error, cannot open proc entry %s: %s (%d)\n",
823       file, strerror(errno), errno);
824     return -1;
825   }
826
827   if (read(fd, &rv, 1) != 1) {
828     OONF_WARN(LOG_OS_INTERFACE,
829       "Error, cannot read proc entry %s: %s (%d)\n",
830       file, strerror(errno), errno);
831     close(fd);
832     return -1;
833   }
834
835   if (rv != value) {
836     if (lseek(fd, SEEK_SET, 0) == -1) {
837       OONF_WARN(LOG_OS_INTERFACE,
838         "Error, cannot rewind to start on proc entry %s: %s (%d)\n",
839         file, strerror(errno), errno);
840       close(fd);
841       return -1;
842     }
843
844     if (write(fd, &value, 1) != 1) {
845       OONF_WARN(LOG_OS_INTERFACE,
846         "Error, cannot write '%c' to proc entry %s: %s (%d)\n",
847         value, file, strerror(errno), errno);
848     }
849
850     OONF_DEBUG(LOG_OS_INTERFACE, "Writing '%c' (was %c) to %s", value, rv, file);
851   }
852
853   close(fd);
854
855   if (old && rv != value) {
856     *old = rv;
857   }
858
859   return 0;
860 }
861
862 /**
863  * Query a dump of all interface link data
864  */
865 static void
866 _query_interface_links(void) {
867   uint8_t buffer[UIO_MAXIOV];
868   struct nlmsghdr *msg;
869   struct ifinfomsg *ifi;
870 #if defined(OONF_LOG_DEBUG_INFO)
871 #endif
872
873   if (_link_query_in_progress || _address_query_in_progress) {
874     return;
875   }
876
877   OONF_DEBUG(LOG_OS_INTERFACE, "Request all interface links");
878
879   _trigger_link_query = false;
880   _link_query_in_progress = true;
881
882   /* get pointers for netlink message */
883   msg = (void *)&buffer[0];
884
885   /* get link level data */
886   memset(buffer, 0, sizeof(buffer));
887   msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
888   msg->nlmsg_type = RTM_GETLINK;
889
890   /* set length of netlink message with ifinfomsg payload */
891   msg->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
892
893   ifi = NLMSG_DATA(msg);
894   ifi->ifi_family = AF_NETLINK;
895
896   /* we don't care for the sequence number */
897   os_system_linux_netlink_send(&_rtnetlink_if_query, msg);
898 }
899
900 /**
901  * Query a dump of all interface link data
902  */
903 static void
904 _query_interface_addresses(void) {
905   uint8_t buffer[UIO_MAXIOV];
906   struct nlmsghdr *msg;
907   struct ifaddrmsg *ifa;
908
909   if (_link_query_in_progress || _address_query_in_progress) {
910     return;
911   }
912
913   _trigger_address_query = false;
914   _address_query_in_progress = true;
915
916   OONF_DEBUG(LOG_OS_INTERFACE, "Request all interface addresses");
917
918   /* get pointers for netlink message */
919   msg = (void *)&buffer[0];
920
921   /* get IP level data */
922   memset(buffer, 0, sizeof(buffer));
923   msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
924   msg->nlmsg_type = RTM_GETADDR;
925
926   /* set length of netlink message with ifaddrmsg payload */
927   msg->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa));
928
929   ifa = NLMSG_DATA(msg);
930   ifa->ifa_family = AF_UNSPEC;
931
932   /* we don't care for the sequence number */
933   os_system_linux_netlink_send(&_rtnetlink_if_query, msg);
934 }
935
936 /**
937  * Trigger all change listeners of a network interface
938  * @param os_if network interface
939  */
940 static void
941 _trigger_if_change(struct os_interface *os_if) {
942   struct os_interface_listener *if_listener;
943
944   if (!oonf_timer_is_active(&os_if->_change_timer)) {
945     /* inform listeners the interface changed */
946     oonf_timer_start(&os_if->_change_timer, 200);
947
948     list_for_each_element(&os_if->_listeners, if_listener, _node) {
949       /* each interface should be informed */
950       if_listener->_dirty = true;
951     }
952   }
953 }
954
955 /**
956  * Trigger all change listeners of a network interface.
957  * Trigger also all change listeners of the wildcard interface "any"
958  * @param os_if network interface
959  */
960 static void
961 _trigger_if_change_including_any(struct os_interface *os_if) {
962   _trigger_if_change(os_if);
963
964   os_if = avl_find_element(
965       &_interface_data_tree, OS_INTERFACE_ANY, os_if, _node);
966   if (os_if) {
967     _trigger_if_change(os_if);
968   }
969 }
970
971 /**
972  * Parse an incoming LINK information from netlink
973  * @param ifname interface name
974  * @param msg netlink message
975  */
976 static void
977 _link_parse_nlmsg(const char *ifname, struct nlmsghdr *msg) {
978   struct ifinfomsg *ifi_msg;
979   struct rtattr *ifi_attr;
980   int ifi_len;
981   struct netaddr addr;
982   struct os_interface *ifdata;
983   int iflink;
984   bool old_up;
985 #if defined(OONF_LOG_DEBUG_INFO)
986   struct netaddr_str nbuf;
987 #endif
988
989   ifi_msg = NLMSG_DATA(msg);
990   ifi_attr = (struct rtattr *) IFLA_RTA(ifi_msg);
991   ifi_len = RTM_PAYLOAD(msg);
992
993   ifdata = avl_find_element(&_interface_data_tree, ifname, ifdata, _node);
994   if (!ifdata) {
995     return;
996   }
997
998   old_up = ifdata->flags.up;
999   ifdata->flags.up = (ifi_msg->ifi_flags & IFF_UP) != 0;
1000   ifdata->flags.promisc = (ifi_msg->ifi_flags & IFF_PROMISC) != 0;
1001   ifdata->flags.pointtopoint = (ifi_msg->ifi_flags & IFF_POINTOPOINT) != 0;
1002   ifdata->flags.loopback = (ifi_msg->ifi_flags & IFF_LOOPBACK) != 0;
1003   ifdata->flags.unicast_only = (ifi_msg->ifi_flags & IFF_MULTICAST) == 0;
1004
1005   OONF_DEBUG(LOG_OS_INTERFACE, "Parse IFI_LINK %s (%u): %c%c%c%c%c",
1006       ifname, ifi_msg->ifi_index,
1007       ifdata->flags.up ? 'u' : '-',
1008       ifdata->flags.promisc ? 'p' : '-',
1009       ifdata->flags.pointtopoint ? 'P' : '-',
1010       ifdata->flags.loopback ? 'l' : '-',
1011       ifdata->flags.unicast_only ? 'U' : '-');
1012
1013   ifdata->index = ifi_msg->ifi_index;
1014   ifdata->base_index = ifdata->index;
1015
1016   if (!old_up && ifdata->flags.up && ifdata->flags.mesh && !ifdata->_internal.ignore_mesh) {
1017     /* refresh mesh parameters, might be gone for LTE-sticks */
1018     _refresh_mesh(ifdata, NULL, NULL);
1019   }
1020   for(; RTA_OK(ifi_attr, ifi_len); ifi_attr = RTA_NEXT(ifi_attr,ifi_len)) {
1021     switch(ifi_attr->rta_type) {
1022       case IFLA_ADDRESS:
1023         netaddr_from_binary(&addr, RTA_DATA(ifi_attr), RTA_PAYLOAD(ifi_attr), AF_MAC48);
1024         OONF_DEBUG(LOG_OS_INTERFACE, "Link: %s", netaddr_to_string(&nbuf, &addr));
1025
1026         if (msg->nlmsg_type == RTM_NEWLINK) {
1027           memcpy(&ifdata->mac, &addr, sizeof(addr));
1028         }
1029         break;
1030       case IFLA_LINK:
1031         memcpy(&iflink, RTA_DATA(ifi_attr), RTA_PAYLOAD(ifi_attr));
1032
1033         OONF_INFO(LOG_OS_INTERFACE, "Base interface index for %s (%u): %u",
1034             ifdata->name, ifdata->index, iflink);
1035         ifdata->base_index = iflink;
1036         break;
1037       default:
1038         //OONF_DEBUG(LOG_OS_INTERFACE, "ifi_attr_type: %u", ifi_attr->rta_type);
1039         break;
1040     }
1041   }
1042
1043   if (!ifdata->_link_initialized) {
1044     ifdata->_link_initialized = true;
1045     OONF_INFO(LOG_OS_INTERFACE, "Interface %s link data initialized",
1046         ifdata->name);
1047   }
1048   _trigger_if_change_including_any(ifdata);
1049 }
1050
1051 /**
1052  * Update the links for routable/ll addresses of a network interface
1053  * @param os_if network interface
1054  */
1055 static void
1056 _update_address_shortcuts(struct os_interface *os_if) {
1057   struct os_interface_ip *ip;
1058   bool ipv4_ll, ipv6_ll, ipv4_routable, ipv6_routable;
1059 #if defined(OONF_LOG_DEBUG_INFO)
1060   struct netaddr_str nbuf;
1061 #endif
1062
1063   OONF_DEBUG(LOG_OS_INTERFACE, "Update address shortcuts for interface %s", os_if->name);
1064
1065   /* update address shortcuts */
1066   os_if->if_v4 = &NETADDR_UNSPEC;
1067   os_if->if_v6 = &NETADDR_UNSPEC;
1068   os_if->if_linklocal_v4 = &NETADDR_UNSPEC;
1069   os_if->if_linklocal_v6 = &NETADDR_UNSPEC;
1070
1071   avl_for_each_element(&os_if->addresses, ip, _node) {
1072     OONF_DEBUG(LOG_OS_INTERFACE, "Interface has %s",
1073         netaddr_to_string(&nbuf, &ip->address));
1074     ipv4_ll = netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, &ip->address);
1075     ipv6_ll = netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &ip->address);
1076
1077     ipv4_routable = !ipv4_ll
1078         && netaddr_get_address_family(&ip->address) == AF_INET
1079         && !netaddr_is_in_subnet(&NETADDR_IPV4_LOOPBACK_NET, &ip->address)
1080         && !netaddr_is_in_subnet(&NETADDR_IPV4_MULTICAST, &ip->address);
1081     ipv6_routable = !ipv6_ll
1082         && netaddr_get_address_family(&ip->address) == AF_INET6
1083         && (netaddr_is_in_subnet(&NETADDR_IPV6_ULA, &ip->address)
1084             || netaddr_is_in_subnet(&NETADDR_IPV6_GLOBAL, &ip->address));
1085
1086     if (netaddr_is_unspec(os_if->if_v4) && ipv4_routable) {
1087       OONF_DEBUG(LOG_OS_INTERFACE, "IPv4 is %s",
1088           netaddr_to_string(&nbuf, &ip->address));
1089       os_if->if_v4 = &ip->address;
1090     }
1091     if (netaddr_is_unspec(os_if->if_v6) && ipv6_routable) {
1092       OONF_DEBUG(LOG_OS_INTERFACE, "IPv6 is %s",
1093           netaddr_to_string(&nbuf, &ip->address));
1094       os_if->if_v6 = &ip->address;
1095     }
1096     if (netaddr_is_unspec(os_if->if_linklocal_v4) && ipv4_ll) {
1097       OONF_DEBUG(LOG_OS_INTERFACE, "Linklocal IPv4 is %s",
1098           netaddr_to_string(&nbuf, &ip->address));
1099       os_if->if_linklocal_v4 = &ip->address;
1100     }
1101     if (netaddr_is_unspec(os_if->if_linklocal_v6) && ipv6_ll) {
1102       OONF_DEBUG(LOG_OS_INTERFACE, "Linklocal IPv6 is %s",
1103           netaddr_to_string(&nbuf, &ip->address));
1104       os_if->if_linklocal_v6 = &ip->address;
1105     }
1106   }
1107 }
1108
1109 /**
1110  * Add an IP address/prefix to a network interface
1111  * @param os_if network interface
1112  * @param prefixed_addr full IP address with prefix length
1113  * @param peer true if this is a peer address, false otherwise
1114  */
1115 static void
1116 _add_address(struct os_interface *os_if, struct netaddr *prefixed_addr, bool peer) {
1117   struct os_interface_ip *ip;
1118   struct avl_tree *tree;
1119 #if defined(OONF_LOG_INFO)
1120   struct netaddr_str nbuf;
1121 #endif
1122
1123   tree = peer ? &os_if->peers : &os_if->addresses;
1124
1125   ip = avl_find_element(tree, prefixed_addr, ip, _node);
1126   if (!ip) {
1127     ip = oonf_class_malloc(&_interface_ip_class);
1128     if (!ip) {
1129       return;
1130     }
1131
1132     /* establish key and add to tree */
1133     memcpy(&ip->prefixed_addr, prefixed_addr, sizeof(*prefixed_addr));
1134     ip->_node.key = &ip->prefixed_addr;
1135     avl_insert(tree, &ip->_node);
1136
1137     /* add back pointer */
1138     ip->interf = os_if;
1139   }
1140
1141   OONF_INFO(LOG_OS_INTERFACE, "Add address to %s%s: %s",
1142       os_if->name, peer ? " (peer)" : "",
1143       netaddr_to_string(&nbuf, prefixed_addr));
1144
1145   /* copy sanitized addresses */
1146   memcpy(&ip->address, prefixed_addr, sizeof(*prefixed_addr));
1147   netaddr_set_prefix_length(&ip->address, netaddr_get_maxprefix(&ip->address));
1148   netaddr_truncate(&ip->prefix, prefixed_addr);
1149 }
1150
1151 /**
1152  * Remove an IP address/prefix from a network interface
1153  * @param os_if network interface
1154  * @param prefixed_addr full IP address with prefix length
1155  * @param peer true if this is a peer address, false otherwise
1156  */
1157 static void
1158 _remove_address(struct os_interface *os_if, struct netaddr *prefixed_addr, bool peer) {
1159   struct os_interface_ip *ip;
1160   struct avl_tree *tree;
1161 #if defined(OONF_LOG_INFO)
1162   struct netaddr_str nbuf;
1163 #endif
1164
1165   tree = peer ? &os_if->peers : &os_if->addresses;
1166   ip = avl_find_element(tree, prefixed_addr, ip, _node);
1167   if (!ip) {
1168     return;
1169   }
1170
1171   OONF_INFO(LOG_OS_INTERFACE, "Remove address from %s%s: %s",
1172       os_if->name, peer ? " (peer)" : "",
1173       netaddr_to_string(&nbuf, prefixed_addr));
1174
1175   avl_remove(tree, &ip->_node);
1176   oonf_class_free(&_interface_ip_class, ip);
1177 }
1178
1179 /**
1180  * Parse an incoming IP address information from netlink
1181  * @param ifname name of interface
1182  * @param msg netlink message
1183  */
1184 static void
1185 _address_parse_nlmsg(const char *ifname, struct nlmsghdr *msg) {
1186   struct ifaddrmsg *ifa_msg;
1187   struct rtattr *ifa_attr;
1188   int ifa_len;
1189   struct os_interface *ifdata;
1190   struct netaddr ifa_local, ifa_address;
1191   bool update;
1192
1193   ifa_msg = NLMSG_DATA(msg);
1194   ifa_attr = IFA_RTA(ifa_msg);
1195   ifa_len = RTM_PAYLOAD(msg);
1196
1197   ifdata = avl_find_element(&_interface_data_tree, ifname, ifdata, _node);
1198   if (!ifdata) {
1199     return;
1200   }
1201
1202   OONF_DEBUG(LOG_OS_INTERFACE, "Parse IFA_GETADDR %s (%u) (len=%u)",
1203       ifname, ifa_msg->ifa_index, ifa_len);
1204
1205   update = false;
1206   netaddr_invalidate(&ifa_local);
1207   netaddr_invalidate(&ifa_address);
1208
1209   for(; RTA_OK(ifa_attr, ifa_len); ifa_attr = RTA_NEXT(ifa_attr,ifa_len)) {
1210     switch(ifa_attr->rta_type) {
1211       case IFA_ADDRESS:
1212         netaddr_from_binary_prefix(&ifa_address,
1213             RTA_DATA(ifa_attr), RTA_PAYLOAD(ifa_attr), 0,
1214                 ifa_msg->ifa_prefixlen);
1215         if (netaddr_is_unspec(&ifa_local)) {
1216           memcpy(&ifa_local, &ifa_address, sizeof(ifa_local));
1217         }
1218         break;
1219       case IFA_LOCAL:
1220         netaddr_from_binary_prefix(&ifa_local,
1221             RTA_DATA(ifa_attr), RTA_PAYLOAD(ifa_attr), 0,
1222                 ifa_msg->ifa_prefixlen);
1223         if (netaddr_is_unspec(&ifa_address)) {
1224           memcpy(&ifa_address, &ifa_local, sizeof(ifa_address));
1225         }
1226         break;
1227       default:
1228         OONF_DEBUG(LOG_OS_INTERFACE, "ifa_attr_type: %u", ifa_attr->rta_type);
1229         break;
1230     }
1231   }
1232
1233   if (!netaddr_is_unspec(&ifa_local)) {
1234     if (msg->nlmsg_type == RTM_NEWADDR) {
1235       _add_address(ifdata, &ifa_local, false);
1236     }
1237     else {
1238       _remove_address(ifdata, &ifa_local, false);
1239     }
1240
1241     _update_address_shortcuts(ifdata);
1242     update = true;
1243   }
1244
1245   if (netaddr_cmp(&ifa_local, &ifa_address)) {
1246     if (msg->nlmsg_type == RTM_NEWADDR) {
1247       _add_address(ifdata, &ifa_address, true);
1248     }
1249     else {
1250       _remove_address(ifdata, &ifa_address, true);
1251     }
1252
1253     update = true;
1254   }
1255
1256   if (update) {
1257     if (!ifdata->_addr_initialized) {
1258       ifdata->_addr_initialized = true;
1259       OONF_INFO(LOG_OS_INTERFACE, "Interface %s address data initialized",
1260           ifdata->name);
1261     }
1262     _trigger_if_change_including_any(ifdata);
1263   }
1264 }
1265
1266 /**
1267  * Handle incoming rtnetlink multicast messages for interface listeners
1268  * @param hdr pointer to netlink message
1269  */
1270 static void
1271 _cb_rtnetlink_message(struct nlmsghdr *hdr) {
1272   struct ifinfomsg *ifi;
1273   struct ifaddrmsg *ifa;
1274   char ifname[IF_NAMESIZE];
1275
1276   if (hdr->nlmsg_type == RTM_NEWLINK || hdr->nlmsg_type == RTM_DELLINK) {
1277     ifi = (struct ifinfomsg *) NLMSG_DATA(hdr);
1278     if (!if_indextoname(ifi->ifi_index, ifname)) {
1279       return;
1280     }
1281
1282     OONF_DEBUG(LOG_OS_INTERFACE, "Linkstatus of interface (%s) %d changed",
1283         ifname, ifi->ifi_index);
1284     _link_parse_nlmsg(ifname, hdr);
1285   }
1286
1287   else if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_type == RTM_DELADDR) {
1288     ifa = (struct ifaddrmsg *) NLMSG_DATA(hdr);
1289     if (!if_indextoname(ifa->ifa_index, ifname)) {
1290       return;
1291     }
1292
1293     OONF_DEBUG(LOG_OS_INTERFACE, "Address of interface %s (%u) changed",
1294         ifname, ifa->ifa_index);
1295     _address_parse_nlmsg(ifname, hdr);
1296   }
1297   else {
1298     OONF_DEBUG(LOG_OS_INTERFACE, "Message type: %u", hdr->nlmsg_type);
1299   }
1300 }
1301
1302 /**
1303  * Handle feedback from netlink socket
1304  * @param seq sequence number of netlink message
1305  * @param error error code
1306  */
1307 static void
1308 _cb_rtnetlink_error(uint32_t seq, int error) {
1309   struct os_interface_ip_change *addr;
1310
1311   OONF_INFO(LOG_OS_INTERFACE, "Netlink socket provided feedback: %d %d", seq, error);
1312
1313   /* transform into errno number */
1314   list_for_each_element(&_rtnetlink_feedback, addr, _internal._node) {
1315     if (seq == addr->_internal.nl_seq) {
1316       _address_finished(addr, error);
1317       break;
1318     }
1319   }
1320 }
1321
1322 /**
1323  * Handle ack timeout from netlink socket
1324  */
1325 static void
1326 _cb_rtnetlink_timeout(void) {
1327   struct os_interface_ip_change *addr;
1328
1329   OONF_INFO(LOG_OS_INTERFACE, "Netlink socket timed out");
1330
1331   list_for_each_element(&_rtnetlink_feedback, addr, _internal._node) {
1332     _address_finished(addr, -1);
1333   }
1334 }
1335
1336 /**
1337  * Handle done from multipart netlink messages
1338  * @param seq sequence number of netlink message
1339  */
1340 static void
1341 _cb_rtnetlink_done(uint32_t seq) {
1342   struct os_interface_ip_change *addr;
1343
1344   OONF_INFO(LOG_OS_INTERFACE, "Netlink operation finished: %u", seq);
1345
1346   list_for_each_element(&_rtnetlink_feedback, addr, _internal._node) {
1347     if (seq == addr->_internal.nl_seq) {
1348       _address_finished(addr, 0);
1349       break;
1350     }
1351   }
1352 }
1353
1354 /**
1355  * Stop processing of an ip address command and set error code
1356  * for callback
1357  * @param addr pointer to os_system_address
1358  * @param error error code, 0 if no error
1359  */
1360 static void
1361 _address_finished(struct os_interface_ip_change *addr, int error) {
1362   if (list_is_node_added(&addr->_internal._node)) {
1363     /* remove first to prevent any kind of recursive cleanup */
1364     list_remove(&addr->_internal._node);
1365
1366     if (addr->cb_finished) {
1367       addr->cb_finished(addr, error);
1368     }
1369   }
1370 }
1371
1372 /**
1373  * Handle switching between netlink query for links and addresses
1374  */
1375 static void
1376 _process_end_of_query(void) {
1377   if (_link_query_in_progress) {
1378     _link_query_in_progress = false;
1379
1380     if (_trigger_address_query) {
1381       _query_interface_addresses();
1382     }
1383     else if (_trigger_link_query) {
1384       _query_interface_links();
1385     }
1386   }
1387   else {
1388     _address_query_in_progress = false;
1389
1390     if (_trigger_link_query) {
1391       _query_interface_links();
1392     }
1393     else if (_trigger_address_query) {
1394       _query_interface_addresses();
1395     }
1396   }
1397 }
1398
1399 /**
1400  * Handle a netlink query that did not work out
1401  */
1402 static void
1403 _process_bad_end_of_query(void) {
1404   /* reactivate query that has failed */
1405   if (_link_query_in_progress) {
1406     _trigger_link_query = true;
1407   }
1408   if (_address_query_in_progress) {
1409     _trigger_address_query = true;
1410   }
1411   _process_end_of_query();
1412 }
1413
1414 /**
1415  * Handle an incoming netlink query error
1416  * @param seq sequence number of netlink message
1417  * @param error error code
1418  */
1419 static void
1420 _cb_query_error(uint32_t seq __attribute((unused)),
1421     int error __attribute((unused))) {
1422   OONF_DEBUG(LOG_OS_INTERFACE, "Received error %d for query %u", error, seq);
1423   _process_bad_end_of_query();
1424 }
1425
1426 /**
1427  * Handle a successful netlink query
1428  * @param seq sequence number of netlink message
1429  */
1430 static void
1431 _cb_query_done(uint32_t seq __attribute((unused))) {
1432   OONF_DEBUG(LOG_OS_INTERFACE, "Query %u done", seq);
1433   _process_end_of_query();
1434 }
1435
1436 /**
1437  * Handle a timeout of a netlink query
1438  */
1439 static void
1440 _cb_query_timeout(void) {
1441   OONF_DEBUG(LOG_OS_INTERFACE, "Query timeout");
1442   _process_bad_end_of_query();
1443 }
1444
1445 /**
1446  * Handle timer that announces interface state/address changes
1447  * @param timer timer instance
1448  */
1449 static void
1450 _cb_delayed_interface_changed(struct oonf_timer_instance *timer) {
1451   struct os_interface *data;
1452   struct os_interface_listener *interf, *interf_it;
1453   bool error;
1454
1455   data = container_of(timer, struct os_interface, _change_timer);
1456
1457   if (!data->flags.any
1458       && (!data->_link_initialized || !data->_addr_initialized)) {
1459     /* wait until we have all the data */
1460     return;
1461   }
1462
1463   OONF_INFO(LOG_OS_INTERFACE, "Interface %s (%u) changed",
1464       data->name, data->index);
1465
1466   error = false;
1467   list_for_each_element_safe(&data->_listeners, interf, _node, interf_it) {
1468     if (!interf->_dirty) {
1469       continue;
1470     }
1471
1472     if (interf->if_changed && interf->if_changed(interf)) {
1473       /* interface change handler had a problem and wants to re-trigger */
1474       error = true;
1475     }
1476     else {
1477       /* everything fine, job done */
1478       interf->_dirty = false;
1479     }
1480   }
1481
1482   if (error) {
1483     /* re-trigger */
1484     oonf_timer_start(timer, 200);
1485   }
1486 }
1487
1488 /**
1489  * Transform remaining parameters into interface sections
1490  * @param arg command line parameter
1491  * @return always 0 (ok)
1492  */
1493 static int
1494 _handle_unused_parameter(const char *arg) {
1495   const char *ifname;
1496   char ifbuf[IF_NAMESIZE];
1497
1498   ifname = cfg_get_phy_if(ifbuf, arg);
1499
1500   cfg_db_add_namedsection(oonf_cfg_get_rawdb(), CFG_INTERFACE_SECTION, ifname);
1501   return 0;
1502 }
1503
1504 /**
1505  * configuration of interface section changed
1506  */
1507 static void
1508 _cb_cfg_changed(void) {
1509   struct os_interface *data;
1510   int result;
1511
1512   /* get pointer to interface if available */
1513   data = avl_find_element(&_interface_data_tree,
1514       _interface_section.section_name, data, _node);
1515
1516   if (_interface_section.post && !data) {
1517     /* make sure interface data is available */
1518     data = _add_interface(_interface_section.section_name);
1519     if (!data) {
1520       return;
1521     }
1522   }
1523
1524   /* overwrite settings */
1525   if (data) {
1526     result = cfg_schema_tobin(data, _interface_section.post,
1527         _interface_entries, ARRAYSIZE(_interface_entries));
1528     if (result) {
1529       OONF_WARN(LOG_OS_INTERFACE,
1530           "Could not convert "CFG_INTERFACE_SECTION" '%s' to binary (%d)",
1531           data->name, -(result+1));
1532       return;
1533     }
1534   }
1535
1536   if (!_interface_section.post) {
1537     /* try to remove old interface */
1538     if (data) {
1539       data->_internal.configured = false;
1540
1541       if (!data->_internal.ignore_mesh
1542          && data->_internal.mesh_counter > 0) {
1543         /* reactivate mesh settings */
1544         _cleanup_mesh(data);
1545       }
1546
1547       /* remove allocated instance (if no listener is left) */
1548       _remove_interface(data);
1549     }
1550     return;
1551   }
1552
1553   /* mark interface as configured */
1554   data->_internal.configured = true;
1555
1556   if (data->_internal.ignore_mesh || data->_internal.mesh_counter == 0) {
1557     /* restore original os mesh configuration if necessary */
1558     _cleanup_mesh(data);
1559   }
1560   else {
1561     /* set os mesh configuration if necessary */
1562     _init_mesh(data);
1563   }
1564 }