add tc fragmentation support again
[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_node 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 ifinit(void)
96 {
97   struct olsr_if_config *tmp_if;
98
99   /* Initial values */
100   list_head_init(&interface_head);
101   avl_init(&interface_lost_tree, avl_comp_default);
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, AVL_DUP_NO);
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 avl_node *node;
163   assert(ip);
164   node = avl_find(&interface_lost_tree, ip);
165   if (node) {
166     return node_tree2lostif(node);
167   }
168   return NULL;
169 }
170
171 bool
172 is_lost_interface_ip(union olsr_ip_addr *ip) {
173   assert(ip);
174   return get_lost_interface_ip(ip) != NULL;
175 }
176
177 /**
178  * Callback function for periodic check of interface parameters.
179  */
180 static void
181 check_interface_updates(void *foo __attribute__ ((unused)))
182 {
183   struct olsr_if_config *tmp_if;
184   struct interface_lost *lost;
185
186   OLSR_DEBUG(LOG_INTERFACE, "Checking for updates in the interface set\n");
187
188   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
189
190     if (!tmp_if->cnf->autodetect_chg) {
191       /* Don't check this interface */
192       OLSR_DEBUG(LOG_INTERFACE, "Not checking interface %s\n", tmp_if->name);
193       continue;
194     }
195
196     if (tmp_if->interf) {
197       chk_if_changed(tmp_if);
198     } else {
199       if (chk_if_up(tmp_if) == 1) {
200         lost = get_lost_interface_ip(&tmp_if->interf->ip_addr);
201         if (lost) {
202           remove_lost_interface_ip(lost);
203         }
204       }
205     }
206   }
207
208   /* clean up lost interface tree */
209   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost) {
210     if (olsr_isTimedOut(lost->valid_until)) {
211       remove_lost_interface_ip(lost);
212     }
213   } OLSR_FOR_ALL_LOSTIF_ENTRIES_END(lost)
214 }
215
216 /**
217  * Remove and cleanup a physical interface.
218  */
219 void
220 remove_interface(struct interface **pinterf)
221 {
222   struct interface *ifp = *pinterf;
223   struct ipaddr_str buf;
224
225   if (!ifp) {
226     return;
227   }
228
229   OLSR_INFO(LOG_INTERFACE, "Removing interface %s\n", ifp->int_name);
230
231   olsr_delete_link_entry_by_if(ifp);
232
233   /*
234    * Call possible ifchange functions registered by plugins
235    */
236   run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
237
238   /* Dequeue */
239   list_remove(&ifp->int_node);
240
241   /* Remove output buffer */
242   net_remove_buffer(ifp);
243
244   /* Check main addr */
245   if (!olsr_cnf->fixed_origaddr && olsr_ipcmp(&olsr_cnf->router_id, &ifp->ip_addr) == 0) {
246     if (list_is_empty(&interface_head)) {
247       /* No more interfaces */
248       memset(&olsr_cnf->router_id, 0, olsr_cnf->ipsize);
249       OLSR_INFO(LOG_INTERFACE, "Removed last interface. Cleared main address.\n");
250     } else {
251
252       /* Grab the first interface in the list. */
253       olsr_cnf->router_id = list2interface(interface_head.next)->ip_addr;
254       olsr_ip_to_string(&buf, &olsr_cnf->router_id);
255       OLSR_INFO(LOG_INTERFACE, "New main address: %s\n", buf.buf);
256     }
257   }
258
259   /*
260    * Deregister functions for periodic message generation
261    */
262   olsr_stop_timer(ifp->hello_gen_timer);
263   ifp->hello_gen_timer = NULL;
264
265   /*
266    * Stop interface pacing.
267    */
268   olsr_stop_timer(ifp->buffer_hold_timer);
269   ifp->buffer_hold_timer = NULL;
270
271   /*
272    * remember the IP for some time
273    */
274   add_lost_interface_ip(&ifp->ip_addr, ifp->hello_validity);
275
276   /*
277    * Unlink from config.
278    */
279   unlock_interface(*pinterf);
280   *pinterf = NULL;
281
282   /* Close olsr socket */
283   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
284   CLOSESOCKET(ifp->olsr_socket);
285   ifp->olsr_socket = -1;
286
287 //  free(ifp->int_name);
288   unlock_interface(ifp);
289
290   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
291     OLSR_ERROR(LOG_INTERFACE, "No more active interfaces - exiting.\n");
292     olsr_exit(EXIT_FAILURE);
293   }
294 }
295
296 void
297 run_ifchg_cbs(struct interface *ifp, int flag)
298 {
299   struct ifchgf *tmp;
300   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
301     tmp->function(ifp, flag);
302   }
303 }
304
305 /**
306  * Find the local interface with a given address.
307  *
308  * @param addr the address to check.
309  * @return the interface struct representing the interface
310  * that matched the address.
311  */
312 struct interface *
313 if_ifwithaddr(const union olsr_ip_addr *addr)
314 {
315   struct interface *ifp;
316   if (!addr) {
317     return NULL;
318   }
319
320   if (olsr_cnf->ip_version == AF_INET) {
321
322     /* IPv4 */
323     OLSR_FOR_ALL_INTERFACES(ifp) {
324       if (ip4cmp(&ifp->int_addr.sin_addr, &addr->v4) == 0) {
325         return ifp;
326       }
327     }
328     OLSR_FOR_ALL_INTERFACES_END(ifp);
329
330   } else {
331
332     /* IPv6 */
333     OLSR_FOR_ALL_INTERFACES(ifp) {
334       if (ip6cmp(&ifp->int6_addr.sin6_addr, &addr->v6) == 0) {
335         return ifp;
336       }
337     }
338     OLSR_FOR_ALL_INTERFACES_END(ifp);
339   }
340   return NULL;
341 }
342
343 /**
344  * Find the interface with a given number.
345  *
346  * @param nr the number of the interface to find.
347  * @return return the interface struct representing the interface
348  * that matched the number.
349  */
350 struct interface *
351 if_ifwithsock(int fd)
352 {
353   struct interface *ifp;
354
355   OLSR_FOR_ALL_INTERFACES(ifp) {
356     if (ifp->olsr_socket == fd) {
357       return ifp;
358     }
359   }
360   OLSR_FOR_ALL_INTERFACES_END(ifp);
361
362   return NULL;
363 }
364
365
366 /**
367  * Find the interface with a given label.
368  *
369  * @param if_name the label of the interface to find.
370  * @return return the interface struct representing the interface
371  * that matched the label.
372  */
373 struct interface *
374 if_ifwithname(const char *if_name)
375 {
376   struct interface *ifp;
377   OLSR_FOR_ALL_INTERFACES(ifp) {
378
379     /* good ol' strcmp should be sufficient here */
380     if (strcmp(ifp->int_name, if_name) == 0) {
381       return ifp;
382     }
383   }
384   OLSR_FOR_ALL_INTERFACES_END(ifp);
385
386   return NULL;
387 }
388
389 #if 0
390
391 /**
392  * Find the interface with a given interface index.
393  *
394  * @param iif_index of the interface to find.
395  * @return return the interface struct representing the interface
396  * that matched the iif_index.
397  */
398 struct interface *
399 if_ifwithindex(const int if_index)
400 {
401   struct interface *ifp;
402   OLSR_FOR_ALL_INTERFACES(ifp) {
403     if (ifp->if_index == if_index) {
404       return ifp;
405     }
406   }
407   OLSR_FOR_ALL_INTERFACES_END(ifp);
408
409   return NULL;
410 }
411 #endif
412
413 #if 0
414
415 /**
416  * Get an interface name for a given interface index
417  *
418  * @param iif_index of the interface to find.
419  * @return "" or interface name.
420  */
421 const char *
422 if_ifwithindex_name(const int if_index)
423 {
424   const struct interface *const ifp = if_ifwithindex(if_index);
425   return ifp == NULL ? "void" : ifp->int_name;
426 }
427 #endif
428
429 /**
430  * Lock an interface.
431  */
432 void
433 lock_interface(struct interface *ifp)
434 {
435   assert(ifp);
436
437   ifp->refcount++;
438 }
439
440 /**
441  * Unlock an interface and free it if the refcount went down to zero.
442  */
443 void
444 unlock_interface(struct interface *ifp)
445 {
446   /* Node must have a positive refcount balance */
447   assert(ifp->refcount);
448
449   if (--ifp->refcount) {
450     return;
451   }
452
453   /* Node must be dequeued at this point */
454   assert(!list_node_on_list(&ifp->int_node));
455
456   /* Free memory */
457   free(ifp->int_name);
458   olsr_cookie_free(interface_mem_cookie, ifp);
459 }
460
461
462 /**
463  * Add an ifchange function. These functions are called on all (non-initial)
464  * changes in the interface set.
465  */
466 void
467 add_ifchgf(ifchg_cb_func f)
468 {
469   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
470
471   tmp->function = f;
472   tmp->next = ifchgf_list;
473   ifchgf_list = tmp;
474 }
475
476 #if 0
477
478 /*
479  * Remove an ifchange function
480  */
481 int
482 del_ifchgf(ifchg_cb_func f)
483 {
484   struct ifchgf *tmp, *prev;
485
486   for (tmp = ifchgf_list, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next) {
487     if (tmp->function == f) {
488       /* Remove entry */
489       if (prev == NULL) {
490         ifchgf_list = tmp->next;
491       } else {
492         prev->next = tmp->next;
493       }
494       free(tmp);
495       return 1;
496     }
497   }
498   return 0;
499 }
500 #endif
501
502 /*
503  * Local Variables:
504  * c-basic-offset: 2
505  * indent-tabs-mode: nil
506  * End:
507  */