FIX: floatingpoint-text to uint32 conversion
[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   olsr_stop_timer(ifp->tc_gen_timer);
265   ifp->tc_gen_timer = NULL;
266   olsr_stop_timer(ifp->mid_gen_timer);
267   ifp->mid_gen_timer = NULL;
268   olsr_stop_timer(ifp->hna_gen_timer);
269   ifp->hna_gen_timer = NULL;
270
271   /*
272    * Stop interface pacing.
273    */
274   olsr_stop_timer(ifp->buffer_hold_timer);
275   ifp->buffer_hold_timer = NULL;
276
277   /*
278    * remember the IP for some time
279    */
280   add_lost_interface_ip(&ifp->ip_addr, me_to_reltime(ifp->valtimes.hello));
281
282   /*
283    * Unlink from config.
284    */
285   unlock_interface(*pinterf);
286   *pinterf = NULL;
287
288   /* Close olsr socket */
289   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
290   CLOSESOCKET(ifp->olsr_socket);
291   ifp->olsr_socket = -1;
292
293   unlock_interface(ifp);
294
295   free(ifp->int_name);
296   olsr_cookie_free(interface_mem_cookie, ifp);
297
298   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
299     OLSR_ERROR(LOG_INTERFACE, "No more active interfaces - exiting.\n");
300     olsr_exit(EXIT_FAILURE);
301   }
302 }
303
304 void
305 run_ifchg_cbs(struct interface *ifp, int flag)
306 {
307   struct ifchgf *tmp;
308   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
309     tmp->function(ifp, flag);
310   }
311 }
312
313 /**
314  * Find the local interface with a given address.
315  *
316  * @param addr the address to check.
317  * @return the interface struct representing the interface
318  * that matched the address.
319  */
320 struct interface *
321 if_ifwithaddr(const union olsr_ip_addr *addr)
322 {
323   struct interface *ifp;
324   if (!addr) {
325     return NULL;
326   }
327
328   if (olsr_cnf->ip_version == AF_INET) {
329
330     /* IPv4 */
331     OLSR_FOR_ALL_INTERFACES(ifp) {
332       if (ip4cmp(&ifp->int_addr.sin_addr, &addr->v4) == 0) {
333         return ifp;
334       }
335     }
336     OLSR_FOR_ALL_INTERFACES_END(ifp);
337
338   } else {
339
340     /* IPv6 */
341     OLSR_FOR_ALL_INTERFACES(ifp) {
342       if (ip6cmp(&ifp->int6_addr.sin6_addr, &addr->v6) == 0) {
343         return ifp;
344       }
345     }
346     OLSR_FOR_ALL_INTERFACES_END(ifp);
347   }
348   return NULL;
349 }
350
351 /**
352  * Find the interface with a given number.
353  *
354  * @param nr the number of the interface to find.
355  * @return return the interface struct representing the interface
356  * that matched the number.
357  */
358 struct interface *
359 if_ifwithsock(int fd)
360 {
361   struct interface *ifp;
362
363   OLSR_FOR_ALL_INTERFACES(ifp) {
364     if (ifp->olsr_socket == fd) {
365       return ifp;
366     }
367   }
368   OLSR_FOR_ALL_INTERFACES_END(ifp);
369
370   return NULL;
371 }
372
373
374 /**
375  * Find the interface with a given label.
376  *
377  * @param if_name the label of the interface to find.
378  * @return return the interface struct representing the interface
379  * that matched the label.
380  */
381 struct interface *
382 if_ifwithname(const char *if_name)
383 {
384   struct interface *ifp;
385   OLSR_FOR_ALL_INTERFACES(ifp) {
386
387     /* good ol' strcmp should be sufficient here */
388     if (strcmp(ifp->int_name, if_name) == 0) {
389       return ifp;
390     }
391   }
392   OLSR_FOR_ALL_INTERFACES_END(ifp);
393
394   return NULL;
395 }
396
397 #if 0
398
399 /**
400  * Find the interface with a given interface index.
401  *
402  * @param iif_index of the interface to find.
403  * @return return the interface struct representing the interface
404  * that matched the iif_index.
405  */
406 struct interface *
407 if_ifwithindex(const int if_index)
408 {
409   struct interface *ifp;
410   OLSR_FOR_ALL_INTERFACES(ifp) {
411     if (ifp->if_index == if_index) {
412       return ifp;
413     }
414   }
415   OLSR_FOR_ALL_INTERFACES_END(ifp);
416
417   return NULL;
418 }
419 #endif
420
421 #if 0
422
423 /**
424  * Get an interface name for a given interface index
425  *
426  * @param iif_index of the interface to find.
427  * @return "" or interface name.
428  */
429 const char *
430 if_ifwithindex_name(const int if_index)
431 {
432   const struct interface *const ifp = if_ifwithindex(if_index);
433   return ifp == NULL ? "void" : ifp->int_name;
434 }
435 #endif
436
437 /**
438  * Lock an interface.
439  */
440 void
441 lock_interface(struct interface *ifp)
442 {
443   assert(ifp);
444
445   ifp->refcount++;
446 }
447
448 /**
449  * Unlock an interface and free it if the refcount went down to zero.
450  */
451 void
452 unlock_interface(struct interface *ifp)
453 {
454   /* Node must have a positive refcount balance */
455   assert(ifp->refcount);
456
457   if (--ifp->refcount) {
458     return;
459   }
460
461   /* Node must be dequeued at this point */
462   assert(!list_node_on_list(&ifp->int_node));
463
464   /* Free memory */
465   free(ifp->int_name);
466   olsr_cookie_free(interface_mem_cookie, ifp);
467 }
468
469
470 /**
471  * Add an ifchange function. These functions are called on all (non-initial)
472  * changes in the interface set.
473  */
474 void
475 add_ifchgf(ifchg_cb_func f)
476 {
477   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
478
479   tmp->function = f;
480   tmp->next = ifchgf_list;
481   ifchgf_list = tmp;
482 }
483
484 #if 0
485
486 /*
487  * Remove an ifchange function
488  */
489 int
490 del_ifchgf(ifchg_cb_func f)
491 {
492   struct ifchgf *tmp, *prev;
493
494   for (tmp = ifchgf_list, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next) {
495     if (tmp->function == f) {
496       /* Remove entry */
497       if (prev == NULL) {
498         ifchgf_list = tmp->next;
499       } else {
500         prev->next = tmp->next;
501       }
502       free(tmp);
503       return 1;
504     }
505   }
506   return 0;
507 }
508 #endif
509
510 /*
511  * Local Variables:
512  * c-basic-offset: 2
513  * indent-tabs-mode: nil
514  * End:
515  */