porting routing code from stable to master (and change many arm-nowarn-alignments)
[olsrd.git] / src / interfaces.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, 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 "defs.h"
43 #include "interfaces.h"
44 #include "ifnet.h"
45 #include "scheduler.h"
46 #include "olsr.h"
47 #include "log.h"
48 #include "parser.h"
49 #include "net_olsr.h"
50 #include "ipcalc.h"
51 #include "common/string.h"
52 #include "common/avl.h"
53 #include "olsr_logging.h"
54 #include "valgrind/valgrind.h"
55
56 #include <signal.h>
57 #include <unistd.h>
58 #include <assert.h>
59
60 /* The interface list head */
61 struct list_entity interface_head;
62
63 /* tree of lost interface IPs */
64 struct avl_tree interface_lost_tree;
65
66 /* Ifchange functions */
67 struct ifchgf {
68   ifchg_cb_func function;
69   struct ifchgf *next;
70 };
71
72 static struct ifchgf *ifchgf_list = NULL;
73
74
75 /* Some cookies for stats keeping */
76 struct olsr_cookie_info *interface_mem_cookie = NULL;
77 struct olsr_cookie_info *interface_poll_timer_cookie = NULL;
78 struct olsr_cookie_info *interface_lost_mem_cookie = NULL;
79
80 struct olsr_cookie_info *hello_gen_timer_cookie = NULL;
81 struct olsr_cookie_info *tc_gen_timer_cookie = NULL;
82 struct olsr_cookie_info *mid_gen_timer_cookie = NULL;
83 struct olsr_cookie_info *hna_gen_timer_cookie = NULL;
84 struct olsr_cookie_info *buffer_hold_timer_cookie = NULL;
85
86 static void check_interface_updates(void *);
87
88 /**
89  * Do initialization of various data needed for network interface management.
90  * This function also tries to set up the given interfaces.
91  *
92  * @return if more than zero interfaces were configured
93  */
94 bool
95 init_interfaces(void)
96 {
97   struct olsr_if_config *tmp_if;
98
99   /* Initial values */
100   list_init_head(&interface_head);
101   avl_init(&interface_lost_tree, avl_comp_default, false, NULL);
102
103   /*
104    * Get some cookies for getting stats to ease troubleshooting.
105    */
106   interface_mem_cookie = olsr_alloc_cookie("Interface", OLSR_COOKIE_TYPE_MEMORY);
107   olsr_cookie_set_memory_size(interface_mem_cookie, sizeof(struct interface));
108
109   interface_lost_mem_cookie = olsr_alloc_cookie("Interface lost", OLSR_COOKIE_TYPE_MEMORY);
110   olsr_cookie_set_memory_size(interface_lost_mem_cookie, sizeof(struct interface_lost));
111
112   interface_poll_timer_cookie = olsr_alloc_cookie("Interface Polling", OLSR_COOKIE_TYPE_TIMER);
113   buffer_hold_timer_cookie = olsr_alloc_cookie("Buffer Hold", OLSR_COOKIE_TYPE_TIMER);
114
115   hello_gen_timer_cookie = olsr_alloc_cookie("Hello Generation", OLSR_COOKIE_TYPE_TIMER);
116   tc_gen_timer_cookie = olsr_alloc_cookie("TC Generation", OLSR_COOKIE_TYPE_TIMER);
117   mid_gen_timer_cookie = olsr_alloc_cookie("MID Generation", OLSR_COOKIE_TYPE_TIMER);
118   hna_gen_timer_cookie = olsr_alloc_cookie("HNA Generation", OLSR_COOKIE_TYPE_TIMER);
119
120   OLSR_INFO(LOG_INTERFACE, "\n ---- Interface configuration ---- \n\n");
121
122   /* Run trough all interfaces immediately */
123   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
124     chk_if_up(tmp_if);
125   }
126
127   /* Kick a periodic timer for the network interface update function */
128   olsr_start_timer(olsr_cnf->nic_chgs_pollrate, 5,
129                    OLSR_TIMER_PERIODIC, &check_interface_updates, NULL, interface_poll_timer_cookie);
130
131   return (!list_is_empty(&interface_head));
132 }
133
134 static void remove_lost_interface_ip(struct interface_lost *lost) {
135 #if !defined(REMOVE_LOG_DEBUG)
136   struct ipaddr_str buf;
137 #endif
138
139   OLSR_DEBUG(LOG_INTERFACE, "Remove %s from lost interface list\n",
140       olsr_ip_to_string(&buf, &lost->ip));
141   avl_delete(&interface_lost_tree, &lost->node);
142   olsr_cookie_free(interface_lost_mem_cookie, lost);
143 }
144
145 static void add_lost_interface_ip(union olsr_ip_addr *ip, uint32_t hello_timeout) {
146   struct interface_lost *lost;
147 #if !defined(REMOVE_LOG_DEBUG)
148   struct ipaddr_str buf;
149 #endif
150
151   lost = olsr_cookie_malloc(interface_lost_mem_cookie);
152   lost->node.key = &lost->ip;
153   lost->ip = *ip;
154   lost->valid_until = olsr_getTimestamp(hello_timeout * 2);
155   avl_insert(&interface_lost_tree, &lost->node);
156
157   OLSR_DEBUG(LOG_INTERFACE, "Added %s to lost interface list for %d ms\n",
158       olsr_ip_to_string(&buf, ip), hello_timeout*2);
159 }
160
161 static struct interface_lost *get_lost_interface_ip(union olsr_ip_addr *ip) {
162   struct interface_lost *lost;
163   assert(ip);
164   lost = avl_find_element(&interface_lost_tree, ip, lost, node);
165   return lost;
166 }
167
168 bool
169 is_lost_interface_ip(union olsr_ip_addr *ip) {
170   assert(ip);
171   return get_lost_interface_ip(ip) != NULL;
172 }
173
174 void destroy_interfaces(void) {
175   struct interface *iface;
176   struct interface_lost *lost;
177   struct list_iterator iterator;
178
179   OLSR_FOR_ALL_INTERFACES(iface, iterator) {
180     struct interface **ptr = &iface;
181     remove_interface(ptr);
182   }
183
184   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, iterator) {
185     remove_lost_interface_ip(lost);
186   }
187 }
188
189 /**
190  * Callback function for periodic check of interface parameters.
191  */
192 static void
193 check_interface_updates(void *foo __attribute__ ((unused)))
194 {
195   struct olsr_if_config *tmp_if;
196   struct interface_lost *lost;
197   struct list_iterator iterator;
198
199   OLSR_DEBUG(LOG_INTERFACE, "Checking for updates in the interface set\n");
200
201   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
202
203     if (!tmp_if->cnf->autodetect_chg) {
204       /* Don't check this interface */
205       OLSR_DEBUG(LOG_INTERFACE, "Not checking interface %s\n", tmp_if->name);
206       continue;
207     }
208
209     if (tmp_if->interf) {
210       chk_if_changed(tmp_if);
211     } else {
212       if (chk_if_up(tmp_if) == 1) {
213         lost = get_lost_interface_ip(&tmp_if->interf->ip_addr);
214         if (lost) {
215           remove_lost_interface_ip(lost);
216         }
217       }
218     }
219   }
220
221   /* clean up lost interface tree */
222   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, iterator) {
223     if (olsr_isTimedOut(lost->valid_until)) {
224       remove_lost_interface_ip(lost);
225     }
226   }
227 }
228
229 /**
230  * Remove and cleanup a physical interface.
231  */
232 void
233 remove_interface(struct interface **pinterf)
234 {
235   struct interface *ifp = *pinterf;
236
237   if (!ifp) {
238     return;
239   }
240
241   OLSR_INFO(LOG_INTERFACE, "Removing interface %s\n", ifp->int_name);
242
243   olsr_delete_link_entry_by_if(ifp);
244
245   /*
246    * Call possible ifchange functions registered by plugins
247    */
248   run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
249
250   /* Dequeue */
251   list_remove(&ifp->int_node);
252
253   /* Remove output buffer */
254   net_remove_buffer(ifp);
255
256   /*
257    * Deregister functions for periodic message generation
258    */
259   olsr_stop_timer(ifp->hello_gen_timer);
260   ifp->hello_gen_timer = NULL;
261
262   /*
263    * Stop interface pacing.
264    */
265   olsr_stop_timer(ifp->buffer_hold_timer);
266   ifp->buffer_hold_timer = NULL;
267
268   /*
269    * remember the IP for some time
270    */
271   add_lost_interface_ip(&ifp->ip_addr, ifp->hello_validity);
272
273   /*
274    * Unlink from config.
275    */
276   unlock_interface(*pinterf);
277   *pinterf = NULL;
278
279   /* Close olsr socket */
280   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
281   CLOSESOCKET(ifp->olsr_socket);
282   CLOSESOCKET(ifp->send_socket);
283   ifp->olsr_socket = -1;
284
285 //  free(ifp->int_name);
286   unlock_interface(ifp);
287
288   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
289     OLSR_ERROR(LOG_INTERFACE, "No more active interfaces - exiting.\n");
290     olsr_exit(EXIT_FAILURE);
291   }
292 }
293
294 void
295 run_ifchg_cbs(struct interface *ifp, int flag)
296 {
297   struct ifchgf *tmp;
298   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
299     tmp->function(ifp, flag);
300   }
301 }
302
303 /**
304  * Find the local interface with a given address.
305  *
306  * @param addr the address to check.
307  * @return the interface struct representing the interface
308  * that matched the address.
309  */
310 struct interface *
311 if_ifwithaddr(const union olsr_ip_addr *addr)
312 {
313   struct interface *ifp;
314   struct list_iterator iterator;
315   if (!addr) {
316     return NULL;
317   }
318
319   if (olsr_cnf->ip_version == AF_INET) {
320
321     /* IPv4 */
322     OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
323       if (ip4cmp(&ifp->int_addr.sin_addr, &addr->v4) == 0) {
324         return ifp;
325       }
326     }
327   } else {
328     /* IPv6 */
329     OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
330       if (ip6cmp(&ifp->int6_addr.sin6_addr, &addr->v6) == 0) {
331         return ifp;
332       }
333     }
334   }
335   return NULL;
336 }
337
338 /**
339  * Find the interface with a given number.
340  *
341  * @param nr the number of the interface to find.
342  * @return return the interface struct representing the interface
343  * that matched the number.
344  */
345 struct interface *
346 if_ifwithsock(int fd)
347 {
348   struct interface *ifp;
349   struct list_iterator iterator;
350
351   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
352     if (ifp->olsr_socket == fd) {
353       return ifp;
354     }
355   }
356
357   return NULL;
358 }
359
360
361 /**
362  * Find the interface with a given label.
363  *
364  * @param if_name the label of the interface to find.
365  * @return return the interface struct representing the interface
366  * that matched the label.
367  */
368 struct interface *
369 if_ifwithname(const char *if_name)
370 {
371   struct interface *ifp;
372   struct list_iterator iterator;
373
374   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
375     /* good ol' strcmp should be sufficient here */
376     if (strcmp(ifp->int_name, if_name) == 0) {
377       return ifp;
378     }
379   }
380
381   return NULL;
382 }
383
384 /**
385  * Find the interface with a given interface index.
386  *
387  * @param iif_index of the interface to find.
388  * @return return the interface struct representing the interface
389  * that matched the iif_index.
390  */
391 struct interface *
392 if_ifwithindex(const int if_index)
393 {
394   struct interface *ifp;
395   struct list_iterator iterator;
396   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
397     if (ifp->if_index == if_index) {
398       return ifp;
399     }
400   }
401
402   return NULL;
403 }
404
405 /**
406  * Get an interface name for a given interface index
407  *
408  * @param iif_index of the interface to find.
409  * @return "" or interface name.
410  */
411 const char *
412 if_ifwithindex_name(const int if_index)
413 {
414   const struct interface *const ifp = if_ifwithindex(if_index);
415   return ifp == NULL ? "void" : ifp->int_name;
416 }
417
418 /**
419  * Lock an interface.
420  */
421 void
422 lock_interface(struct interface *ifp)
423 {
424   assert(ifp);
425
426   ifp->refcount++;
427 }
428
429 /**
430  * Unlock an interface and free it if the refcount went down to zero.
431  */
432 void
433 unlock_interface(struct interface *ifp)
434 {
435   /* Node must have a positive refcount balance */
436   assert(ifp->refcount);
437
438   if (--ifp->refcount) {
439     return;
440   }
441
442   /* Node must be dequeued at this point */
443   assert(!list_node_added(&ifp->int_node));
444
445   /* Free memory */
446   free(ifp->int_name);
447   olsr_cookie_free(interface_mem_cookie, ifp);
448 }
449
450
451 /**
452  * Add an ifchange function. These functions are called on all (non-initial)
453  * changes in the interface set.
454  */
455 void
456 add_ifchgf(ifchg_cb_func f)
457 {
458   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
459
460   tmp->function = f;
461   tmp->next = ifchgf_list;
462   ifchgf_list = tmp;
463 }
464
465 #if 0
466
467 /*
468  * Remove an ifchange function
469  */
470 int
471 del_ifchgf(ifchg_cb_func f)
472 {
473   struct ifchgf *tmp, *prev;
474
475   for (tmp = ifchgf_list, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next) {
476     if (tmp->function == f) {
477       /* Remove entry */
478       if (prev == NULL) {
479         ifchgf_list = tmp->next;
480       } else {
481         prev->next = tmp->next;
482       }
483       free(tmp);
484       return 1;
485     }
486   }
487   return 0;
488 }
489 #endif
490
491 /*
492  * Local Variables:
493  * c-basic-offset: 2
494  * indent-tabs-mode: nil
495  * End:
496  */