Fix dependencies and graph files
[oonf.git] / src-plugins / subsystems / oonf_interface.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2013, 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 #include <netinet/in.h>
43
44 #include "common/common_types.h"
45 #include "common/avl.h"
46 #include "common/avl_comp.h"
47 #include "common/list.h"
48 #include "common/netaddr.h"
49 #include "common/netaddr_acl.h"
50 #include "common/string.h"
51
52 #include "core/oonf_cfg.h"
53 #include "core/oonf_logging.h"
54 #include "core/oonf_main.h"
55 #include "core/oonf_subsystem.h"
56 #include "subsystems/oonf_class.h"
57 #include "subsystems/oonf_timer.h"
58 #include "subsystems/os_interface.h"
59 #include "subsystems/os_system.h"
60
61 #include "subsystems/oonf_interface.h"
62
63 /* Definitions */
64 #define LOG_INTERFACE _oonf_interface_subsystem.logging
65
66 /* timeinterval to delay change in interface to trigger actions */
67 #define OONF_INTERFACE_CHANGE_INTERVAL 100
68
69 /* prototypes */
70 static int _init(void);
71 static void _cleanup(void);
72 static void _early_cfg_init(void);
73
74 static const struct netaddr *_get_fixed_prefix(
75     int af_type, struct netaddr_acl *filter);
76 static const struct netaddr *_get_exact_match_bindaddress(
77     int af_type, struct netaddr_acl *filter, struct os_interface_data *ifdata);
78 static const struct netaddr *_get_matching_bindaddress(
79     int af_type, struct netaddr_acl *filter, struct os_interface_data *ifdata);
80
81 static struct os_interface *_interface_add(const char *, bool mesh);
82 static void _interface_remove(struct os_interface *interf, bool mesh);
83 static int _handle_unused_parameter(const char *);
84 static void _cb_change_handler(void *);
85 static void _trigger_change_timer(struct os_interface *);
86
87 /* global tree of known interfaces */
88 static struct avl_tree _oonf_interface_tree;
89
90 /* subsystem definition */
91 static const char *_dependencies[] = {
92   OONF_CLASS_SUBSYSTEM,
93   OONF_TIMER_SUBSYSTEM,
94   OONF_OS_SYSTEM_SUBSYSTEM,
95   OONF_OS_INTERFACE_SUBSYSTEM,
96 };
97
98 static struct oonf_subsystem _oonf_interface_subsystem = {
99   .name = OONF_INTERFACE_SUBSYSTEM,
100   .dependencies = _dependencies,
101   .dependencies_count = ARRAYSIZE(_dependencies),
102   .early_cfg_init = _early_cfg_init,
103   .init = _init,
104   .cleanup = _cleanup,
105 };
106 DECLARE_OONF_PLUGIN(_oonf_interface_subsystem);
107
108 static struct list_entity _interface_listener;
109 static struct oonf_timer_class _change_timer_info = {
110   .name = "Interface change",
111   .callback = _cb_change_handler,
112 };
113
114 static struct os_interface_if_listener _iflistener = {
115   .if_changed = oonf_interface_trigger_change,
116 };
117
118 static struct oonf_class _if_class = {
119   .name = OONF_CLASS_INTERFACE,
120   .size = sizeof(struct os_interface),
121 };
122
123 /**
124  * Initialize interface subsystem
125  * @return always returns 0
126  */
127 static int
128 _init(void) {
129   /* initialize data structures */
130   oonf_timer_add(&_change_timer_info);
131   oonf_class_add(&_if_class);
132
133   avl_init(&_oonf_interface_tree, avl_comp_strcasecmp, false);
134   list_init_head(&_interface_listener);
135
136   os_interface_listener_add(&_iflistener);
137   return 0;
138 }
139
140 /**
141  * Cleanup interface subsystem
142  */
143 static void
144 _cleanup(void) {
145   struct oonf_interface_listener *listener, *l_it;
146
147   list_for_each_element_safe(&_interface_listener, listener, _node, l_it) {
148     oonf_interface_remove_listener(listener);
149   }
150
151   os_interface_listener_remove(&_iflistener);
152   oonf_class_remove(&_if_class);
153   oonf_timer_remove(&_change_timer_info);
154 }
155
156 static
157 void _early_cfg_init(void) {
158   oonf_main_set_parameter_handler(_handle_unused_parameter);
159 }
160
161 /**
162  * Add a listener to a specific interface
163  * @param listener initialized listener object
164  * @return -1 if an error happened, 0 otherwise
165  */
166 int
167 oonf_interface_add_listener(
168     struct oonf_interface_listener *listener) {
169   if (list_is_node_added(&listener->_node)) {
170     return 0;
171   }
172
173   OONF_DEBUG(LOG_INTERFACE, "Add listener for interface %s", listener->name);
174
175   if (listener->name) {
176     listener->interface = _interface_add(listener->name, listener->mesh);
177     if (listener->interface == NULL) {
178       return -1;
179     }
180   }
181
182   list_add_tail(&_interface_listener, &listener->_node);
183   return 0;
184 }
185
186 /**
187  * Removes a listener to an interface object
188  * @param listener pointer to listener object
189  */
190 void
191 oonf_interface_remove_listener(
192     struct oonf_interface_listener *listener) {
193   if (!list_is_node_added(&listener->_node)) {
194     return;
195   }
196
197   OONF_DEBUG(LOG_INTERFACE, "Remove listener for interface %s", listener->name);
198
199   if (listener->interface) {
200     _interface_remove(listener->interface, listener->mesh);
201   }
202
203   list_remove(&listener->_node);
204 }
205
206 /**
207  * Trigger a potential change in the interface settings. Normally
208  * called by os_system code
209  * @param name interface name
210  * @param down true if interface is going down
211  */
212 void
213 oonf_interface_trigger_change(unsigned if_index, bool down) {
214   char if_name[IF_NAMESIZE];
215   struct os_interface *interf = NULL, *if_ptr;
216
217   if (if_indextoname(if_index, if_name) != NULL) {
218     interf = avl_find_element(&_oonf_interface_tree, if_name, interf, _node);
219   }
220
221   if (interf == NULL) {
222     avl_for_each_element(&_oonf_interface_tree, if_ptr, _node) {
223       if (if_ptr->data.index == if_index) {
224         interf = if_ptr;
225       }
226     }
227   }
228
229   if (interf == NULL) {
230     OONF_INFO(LOG_INTERFACE, "Unknown interface update: %d", if_index);
231     return;
232   }
233   if (down) {
234     interf->data.up = false;
235   }
236
237   oonf_interface_trigger_handler(interf);
238 }
239
240 /**
241  * Trigger the interface change handler after a short waiting period
242  * to accumulate multiple change events.
243  * @param interf pointer to olsr interface
244  */
245 void
246 oonf_interface_trigger_handler(struct os_interface *interf) {
247   /* trigger interface reload in 100 ms */
248   OONF_DEBUG(LOG_INTERFACE, "Change of interface %s was triggered", interf->data.name);
249
250   _trigger_change_timer(interf);
251 }
252
253 /**
254  * @param name interface name
255  * @param buf optional pointer to helper buffer, if not NULL and the
256  *   interface data wasn't cached, it will be read into the helper
257  *   buffer directly.
258  * @return pointer to olsr interface data, NULL if not found
259  */
260 struct os_interface_data *
261 oonf_interface_get_data(const char *name, struct os_interface_data *buf) {
262   struct os_interface *interf;
263
264   interf = avl_find_element(&_oonf_interface_tree, name, interf, _node);
265   if (interf == NULL) {
266     if (buf) {
267       if (os_interface_update(buf, name)) {
268         return NULL;
269       }
270       return buf;
271     }
272     return NULL;
273   }
274
275   return &interf->data;
276 }
277
278 /**
279  * Search for an interface by its index
280  * @param ifindex index of the interface
281  * @return interface data, NULL if not found
282  */
283 struct os_interface_data *
284 oonf_interface_get_data_by_ifindex(unsigned ifindex) {
285   struct os_interface *interf;
286
287   avl_for_each_element(&_oonf_interface_tree, interf, _node) {
288     if (interf->data.index == ifindex) {
289       return &interf->data;
290     }
291   }
292   return NULL;
293 }
294
295 /**
296  * Search for an interface by its base-index
297  * @param ifindex index of the interface
298  * @return first fitting interface data, NULL if not found
299  */
300 struct os_interface_data *
301 oonf_interface_get_data_by_ifbaseindex(unsigned ifindex) {
302   struct os_interface *interf;
303
304   avl_for_each_element(&_oonf_interface_tree, interf, _node) {
305     if (interf->data.base_index == ifindex) {
306       return &interf->data;
307     }
308   }
309   return NULL;
310 }
311
312 /**
313  * Get the prefix of an interface fitting to a destination address
314  * @param destination destination address
315  * @param ifdata interface data, NULL to search over all interfaces
316  * @return network prefix (including full host), NULL if not found
317  */
318 const struct netaddr *
319 oonf_interface_get_prefix_from_dst(
320     struct netaddr *destination, struct os_interface_data *ifdata) {
321   struct os_interface *interf;
322   const struct netaddr *result;
323   size_t i;
324 #ifdef OONF_LOG_DEBUG_INFO
325   struct netaddr_str nbuf1, nbuf2;
326 #endif
327
328   if (ifdata == NULL) {
329     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
330       result = oonf_interface_get_prefix_from_dst(destination, &interf->data);
331       if (result) {
332         return result;
333       }
334     }
335     return NULL;
336   }
337
338   for (i=0; i<ifdata->prefixcount; i++) {
339     if (netaddr_is_in_subnet(&ifdata->prefixes[i], destination)) {
340       OONF_DEBUG(LOG_INTERFACE, "destination %s query matched if prefix: %s",
341           netaddr_to_string(&nbuf1, destination),
342           netaddr_to_string(&nbuf2, &ifdata->prefixes[i]));
343
344       return &ifdata->prefixes[i];
345     }
346   }
347
348   return NULL;
349 }
350
351 /**
352  * Calculate the IP address a socket should bind to
353  * @param filter filter for IP address to bind on
354  * @param ifdata interface to bind to socket on, NULL if not
355  *   bound to an interface.
356  * @return 0 if an IP was calculated, -1 otherwise
357  */
358 const struct netaddr *
359 oonf_interface_get_bindaddress(int af_type,
360     struct netaddr_acl *filter, struct os_interface_data *ifdata) {
361   const struct netaddr *result;
362   size_t i;
363 #ifdef OONF_LOG_DEBUG_INFO
364   struct netaddr_str nbuf;
365 #endif
366
367   OONF_DEBUG(LOG_INTERFACE, "Find bindto (%s) for acl (if=%s):",
368       af_type == AF_INET ? "ipv4" : "ipv6",
369       !ifdata ? "any" : ifdata->name);
370
371   for (i=0; i<filter->accept_count; i++) {
372     OONF_DEBUG_NH(LOG_INTERFACE, "\taccept: %s", netaddr_to_string(&nbuf, &filter->accept[i]));
373   }
374   for (i=0; i<filter->reject_count; i++) {
375     OONF_DEBUG_NH(LOG_INTERFACE, "\treject: %s", netaddr_to_string(&nbuf, &filter->reject[i]));
376   }
377   OONF_DEBUG_NH(LOG_INTERFACE, "\t%s_first, %s_default",
378       filter->reject_first ? "reject" : "accept",
379       filter->accept_default ? "accept" : "reject");
380
381   result = NULL;
382   if (ifdata == NULL) {
383     OONF_DEBUG(LOG_INTERFACE, "Look for fixed prefix");
384     result = _get_fixed_prefix(af_type, filter);
385   }
386   if (!result) {
387     OONF_DEBUG(LOG_INTERFACE, "Look for exact match");
388     result = _get_exact_match_bindaddress(af_type, filter, ifdata);
389   }
390   if (!result) {
391     OONF_DEBUG(LOG_INTERFACE, "Look for prefix match");
392     result = _get_matching_bindaddress(af_type, filter, ifdata);
393   }
394   OONF_DEBUG_NH(LOG_INTERFACE, "Bind to '%s'", netaddr_to_string(&nbuf, result));
395   return result;
396 }
397
398 struct avl_tree *
399 oonf_interface_get_tree(void) {
400   return &_oonf_interface_tree;
401 }
402
403 /**
404  * Checks if the whole ACL is one maximum length address
405  * (or two, one for each possible address type).
406  * @param af_type requested address family
407  * @param filter filter to parse
408  * @return pointer to address to bind socket to, NULL if no match
409  */
410 static const struct netaddr *
411 _get_fixed_prefix(int af_type, struct netaddr_acl *filter) {
412   const struct netaddr *first, *second;
413   if (filter->reject_count > 0) {
414     return NULL;
415   }
416
417   if (filter->accept_count == 0 || filter->accept_count > 2) {
418     return NULL;
419   }
420
421   first = &filter->accept[0];
422   if (netaddr_get_prefix_length(first) != netaddr_get_maxprefix(first)) {
423     return NULL;
424   }
425
426   if (filter->accept_count == 2) {
427     second = &filter->accept[1];
428
429     if (netaddr_get_address_family(first) ==
430         netaddr_get_address_family(second)) {
431       /* must be two different address families */
432       return NULL;
433     }
434
435     if (netaddr_get_prefix_length(second) != netaddr_get_maxprefix(second)) {
436       return NULL;
437     }
438     if (netaddr_get_address_family(second) == af_type) {
439       return second;
440     }
441   }
442
443   if (netaddr_get_address_family(first) == af_type) {
444     return first;
445   }
446   return NULL;
447 }
448
449 /**
450  * Finds an IP on an/all interfaces that matches an exact (maximum length)
451  * filter rule
452  *
453  * @param af_type address family type to look for
454  * @param filter filter that must be matched
455  * @param ifdata interface to look through, NULL for all interfaces
456  * @return pointer to address to bind socket to, NULL if no match
457  */
458 static const struct netaddr *
459 _get_exact_match_bindaddress(int af_type, struct netaddr_acl *filter,
460     struct os_interface_data *ifdata) {
461   struct os_interface *interf;
462   const struct netaddr *result;
463   size_t i,j;
464
465   /* handle the 'all interfaces' case */
466   if (ifdata == NULL) {
467     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
468       if ((result = _get_exact_match_bindaddress(af_type, filter, &interf->data)) != NULL) {
469         return result;
470       }
471     }
472     return NULL;
473   }
474
475   /* run through all filters */
476   for (i=0; i<filter->accept_count; i++) {
477     /* look for maximum prefix length filters */
478     if (netaddr_get_prefix_length(&filter->accept[i]) != netaddr_get_af_maxprefix(af_type)) {
479       continue;
480     }
481
482     /* run through all interface addresses and look for match */
483     for (j=0; j<ifdata->addrcount; j++) {
484       if (netaddr_cmp(&ifdata->addresses[j], &filter->accept[i]) == 0) {
485         return &filter->accept[i];
486       }
487     }
488   }
489
490   /* no exact match found */
491   return NULL;
492 }
493
494 /**
495  * Finds an IP on an/all interfaces that matches a filter rule
496  *
497  * @param af_type address family type to look for
498  * @param filter filter that must be matched
499  * @param ifdata interface to look through, NULL for all interfaces
500  * @return pointer to address to bind socket to, NULL if no match
501  */
502 static const struct netaddr *
503 _get_matching_bindaddress(int af_type, struct netaddr_acl *filter,
504     struct os_interface_data *ifdata) {
505   struct os_interface *interf;
506   const struct netaddr *result;
507   size_t i;
508
509   /* handle the 'all interfaces' case */
510   if (ifdata == NULL) {
511     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
512       if ((result = _get_matching_bindaddress(af_type, filter, &interf->data)) != NULL) {
513         return result;
514       }
515     }
516     return NULL;
517   }
518
519   /* run through interface address list looking for filter match */
520   for (i=0; i<ifdata->addrcount; i++) {
521     if (netaddr_get_address_family(&ifdata->addresses[i]) != af_type) {
522       continue;
523     }
524
525     if (netaddr_acl_check_accept(filter, &ifdata->addresses[i])) {
526       return &ifdata->addresses[i];
527     }
528   }
529   return NULL;
530 }
531
532 /**
533  * Add an interface to the listener system
534  * @param if_index index of interface
535  * @param mesh true if interface is used for mesh traffic
536  * @return pointer to interface struct, NULL if an error happened
537  */
538 static struct os_interface *
539 _interface_add(const char *name, bool mesh) {
540   struct os_interface *interf;
541
542   interf = avl_find_element(&_oonf_interface_tree, name, interf, _node);
543   if (!interf) {
544     /* allocate new interface */
545     interf = oonf_class_malloc(&_if_class);
546     if (interf == NULL) {
547       return NULL;
548     }
549
550     /* hookup */
551     strscpy(interf->data.name, name, sizeof(interf->data.name));
552     interf->_node.key = interf->data.name;
553     avl_insert(&_oonf_interface_tree, &interf->_node);
554
555     interf->data.index = if_nametoindex(name);
556
557     interf->_change_timer.class = &_change_timer_info;
558     interf->_change_timer.cb_context = interf;
559
560     /* initialize data of interface */
561     os_interface_update(&interf->data, name);
562   }
563
564   /* update reference counters */
565   interf->usage_counter++;
566   if(mesh) {
567     if (interf->mesh_counter == 0) {
568       os_interface_init_mesh(interf);
569     }
570     interf->mesh_counter++;
571   }
572
573   OONF_INFO(LOG_INTERFACE, "interface '%s' has reference count %u", name, interf->usage_counter);
574
575   /* trigger update */
576   if (interf->usage_counter == 1) {
577     /* new interface */
578     _cb_change_handler(interf);
579   }
580   else {
581     /* existing one, delay update */
582     _trigger_change_timer(interf);
583   }
584
585   return interf;
586 }
587
588 /**
589  * Remove an interface from the listener system. If multiple listeners
590  * share an interface, this will only decrease the reference counter.
591  * @param interf pointer to os_interface
592  */
593 static void
594 _interface_remove(struct os_interface *interf, bool mesh) {
595   /* handle mesh interface flag */
596   if (mesh) {
597     interf->mesh_counter--;
598
599     if (interf->mesh_counter < 1) {
600       /* no mesh interface anymore, remove routing settings */
601       os_interface_cleanup_mesh(interf);
602     }
603   }
604
605   interf->usage_counter--;
606   OONF_INFO(LOG_INTERFACE, "Interface '%s' has reference count %u", interf->data.name, interf->usage_counter);
607
608   if (interf->usage_counter > 0) {
609     return;
610   }
611
612   if (interf->data.addresses) {
613     free(interf->data.addresses);
614   }
615   avl_remove(&_oonf_interface_tree, &interf->_node);
616
617   oonf_timer_stop(&interf->_change_timer);
618   oonf_class_free(&_if_class, interf);
619 }
620
621 /**
622  * Timer callback to handle potential change of data of an interface
623  * @param ptr pointer to interface object
624  */
625 static void
626 _cb_change_handler(void *ptr) {
627   struct os_interface_data old_data, new_data;
628   struct oonf_interface_listener *listener, *l_it;
629   struct os_interface *interf;
630
631   interf = ptr;
632
633   OONF_DEBUG(LOG_INTERFACE, "Change of interface %s in progress", interf->data.name);
634
635   /* read interface data */
636   memset(&new_data, 0, sizeof(new_data));
637   if (os_interface_update(&new_data, interf->data.name)) {
638     /* an error happened, try again */
639     OONF_INFO(LOG_INTERFACE, "Could not query os network interface %s, trying again soon",
640         interf->data.name);
641     _trigger_change_timer(interf);
642     return;
643   }
644
645   /* something changed ?
646   if (memcmp(&interf->data, &new_data, sizeof(new_data)) == 0) {
647     return;
648   }
649 */
650   /* copy data to interface object, but remember the old data */
651   memcpy(&old_data, &interf->data, sizeof(old_data));
652   memcpy(&interf->data, &new_data, sizeof(interf->data));
653
654   /* call listeners */
655   list_for_each_element_safe(&_interface_listener, listener, _node, l_it) {
656     if (listener->process != NULL
657         && (listener->name == NULL
658             || strcasecmp(listener->name, interf->data.name) == 0)) {
659       listener->old = &old_data;
660       listener->process(listener);
661       listener->old = NULL;
662     }
663   }
664
665   if (old_data.addresses) {
666     free (old_data.addresses);
667   }
668 }
669
670 /**
671  * Activate the change timer of an interface object
672  * @param interf pointer to interface object
673  */
674 static void
675 _trigger_change_timer(struct os_interface *interf) {
676   oonf_timer_set(&interf->_change_timer, OONF_INTERFACE_CHANGE_INTERVAL);
677 }
678
679 static int
680 _handle_unused_parameter(const char *arg) {
681   cfg_db_add_namedsection(oonf_cfg_get_rawdb(), CFG_INTERFACE_SECTION, arg);
682   return 0;
683 }