Merge pull request #78 from ffontaine/master
[olsrd.git] / src / interfaces.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include <signal.h>
47 #include <unistd.h>
48
49 #include "defs.h"
50 #include "interfaces.h"
51 #include "ifnet.h"
52 #include "scheduler.h"
53 #include "olsr.h"
54 #include "net_olsr.h"
55 #include "ipcalc.h"
56 #include "log.h"
57 #include "parser.h"
58
59 #ifdef _WIN32
60 #include <winbase.h>
61 #define close(x) closesocket(x)
62 #endif /* _WIN32 */
63
64 /* The interface linked-list */
65 struct interface_olsr *ifnet;
66
67 /* Ifchange functions */
68 struct ifchgf {
69   void (*function) (int if_index, struct interface_olsr *, enum olsr_ifchg_flag);
70   struct ifchgf *next;
71 };
72
73 static struct ifchgf *ifchgf_list;
74
75 /* Some cookies for stats keeping */
76 struct olsr_cookie_info *interface_poll_timer_cookie = NULL;
77 struct olsr_cookie_info *hello_gen_timer_cookie = NULL;
78 struct olsr_cookie_info *tc_gen_timer_cookie = NULL;
79 struct olsr_cookie_info *mid_gen_timer_cookie = NULL;
80 struct olsr_cookie_info *hna_gen_timer_cookie = NULL;
81
82 /**
83  *Do initialization of various data needed for
84  *network interface management.
85  *This function also tries to set up the given interfaces.
86  *
87  *@return the number of interfaces configured
88  */
89 int
90 olsr_init_interfacedb(void)
91 {
92   struct olsr_if *tmp_if;
93
94   /* Initial values */
95   ifnet = NULL;
96
97   /*
98    * Get some cookies for getting stats to ease troubleshooting.
99    */
100   interface_poll_timer_cookie = olsr_alloc_cookie("Interface Polling", OLSR_COOKIE_TYPE_TIMER);
101
102   hello_gen_timer_cookie = olsr_alloc_cookie("Hello Generation", OLSR_COOKIE_TYPE_TIMER);
103   tc_gen_timer_cookie = olsr_alloc_cookie("TC Generation", OLSR_COOKIE_TYPE_TIMER);
104   mid_gen_timer_cookie = olsr_alloc_cookie("MID Generation", OLSR_COOKIE_TYPE_TIMER);
105   hna_gen_timer_cookie = olsr_alloc_cookie("HNA Generation", OLSR_COOKIE_TYPE_TIMER);
106
107   OLSR_PRINTF(1, "\n ---- Interface configuration ---- \n\n");
108   /* Run trough all interfaces immedeatly */
109   for (tmp_if = olsr_cnf->interfaces; tmp_if != NULL; tmp_if = tmp_if->next) {
110     if (!tmp_if->host_emul) {
111       if (!olsr_cnf->host_emul) /* XXX: TEMPORARY! */
112         chk_if_up(tmp_if, 1);
113     } else {
114       add_hemu_if(tmp_if);
115     }
116   }
117
118   /* Kick a periodic timer for the network interface update function */
119   olsr_start_timer((unsigned int)olsr_cnf->nic_chgs_pollrate * MSEC_PER_SEC, 5, OLSR_TIMER_PERIODIC, &check_interface_updates, NULL,
120                    interface_poll_timer_cookie);
121
122   return (ifnet == NULL) ? 0 : 1;
123 }
124
125 void
126 olsr_trigger_ifchange(int if_index, struct interface_olsr *ifp, enum olsr_ifchg_flag flag)
127 {
128   struct ifchgf *tmp_ifchgf_list = ifchgf_list;
129
130   while (tmp_ifchgf_list != NULL) {
131     tmp_ifchgf_list->function(if_index, ifp, flag);
132     tmp_ifchgf_list = tmp_ifchgf_list->next;
133   }
134 }
135
136 /**
137  *Find the local interface with a given address.
138  *
139  *@param addr the address to check.
140  *
141  *@return the interface struct representing the interface
142  *that matched the address.
143  */
144
145 struct interface_olsr *
146 if_ifwithaddr(const union olsr_ip_addr *addr)
147 {
148   struct interface_olsr *ifp;
149
150   if (!addr)
151     return NULL;
152
153   for (ifp = ifnet; ifp; ifp = ifp->int_next) {
154     if (olsr_cnf->ip_version == AF_INET) {
155       /* IPv4 */
156       //printf("Checking: %s == ", inet_ntoa(((struct sockaddr_in *)&ifp->int_addr)->sin_addr));
157       //printf("%s\n", olsr_ip_to_string(addr));
158
159       if (((struct sockaddr_in *)&ifp->int_addr)->sin_addr.s_addr == addr->v4.s_addr)
160         return ifp;
161     } else {
162       /* IPv6 */
163       //printf("Checking %s ", olsr_ip_to_string((union olsr_ip_addr *)&ifp->int6_addr.sin6_addr));
164       //printf("== %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in6 *)addr)->sin6_addr));
165       if (ip6equal(&ifp->int6_addr.sin6_addr, &addr->v6))
166         return ifp;
167     }
168   }
169   return NULL;
170 }
171
172 /**
173  *Find the interface with a given file descriptor/socket.
174  *
175  *@param fd file descriptor/socket of the interface to find.
176  *
177  *@return return the interface struct representing the interface
178  *that matched the number.
179  */
180 struct interface_olsr *
181 if_ifwithsock(int fd)
182 {
183   struct interface_olsr *ifp;
184   ifp = ifnet;
185
186   while (ifp) {
187     if (ifp->olsr_socket == fd || ifp->send_socket == fd)
188       return ifp;
189     ifp = ifp->int_next;
190   }
191
192   return NULL;
193 }
194
195 /**
196  *Find the interface with a given label.
197  *
198  *@param if_name the label of the interface to find.
199  *
200  *@return return the interface struct representing the interface
201  *that matched the label.
202  */
203 struct interface_olsr *
204 if_ifwithname(const char *if_name)
205 {
206   struct interface_olsr *ifp = ifnet;
207   while (ifp) {
208     /* good ol' strcmp should be sufficcient here */
209     if (strcmp(ifp->int_name, if_name) == 0) {
210       return ifp;
211     }
212     ifp = ifp->int_next;
213   }
214   return NULL;
215 }
216
217 /**
218  *Find the olsr_if with a given label.
219  *
220  *@param if_name the label of the interface to find.
221  *
222  *@return return the interface struct representing the interface
223  *that matched the label.
224  */
225 struct olsr_if *
226 olsrif_ifwithname(const char *if_name)
227 {
228   struct olsr_if *oifp = olsr_cnf->interfaces;
229   while (oifp) {
230     /* good ol' strcmp should be sufficcient here */
231     if (strcmp(oifp->name, if_name) == 0) {
232       return oifp;
233     }
234     oifp = oifp->next;
235   }
236   return NULL;
237 }
238
239 /**
240  *Find the interface with a given interface index.
241  *
242  *@param if_index index of the interface to find.
243  *
244  *@return return the interface struct representing the interface
245  *that matched the iif_index.
246  */
247 struct interface_olsr *
248 if_ifwithindex(const int if_index)
249 {
250   struct interface_olsr *ifp = ifnet;
251   while (ifp != NULL) {
252     if (ifp->if_index == if_index) {
253       return ifp;
254     }
255     ifp = ifp->int_next;
256   }
257   return NULL;
258 }
259
260 /**
261  *Get an interface name for a given interface index
262  *
263  *@param if_index index of the interface to find.
264  *
265  *@return "" or interface name.
266  */
267 const char *
268 if_ifwithindex_name(const int if_index)
269 {
270   const struct interface_olsr *const ifp = if_ifwithindex(if_index);
271   return ifp == NULL ? "void" : ifp->int_name;
272 }
273
274 /**
275  *Create a new interf_name struct using a given
276  *name and insert it into the interface list.
277  *
278  *@param name the name of the interface.
279  *@param hemu non-zero to indicate host emulation mode
280  *
281  *@return the new interf_name struct
282  */
283 struct olsr_if *
284 olsr_create_olsrif(const char *name, int hemu)
285 {
286   struct olsr_if *interf_n = olsr_cnf->interfaces;
287   size_t name_size;
288
289   //printf("Adding interface %s\n", name);
290
291   /* check if the inerfaces already exists */
292   while (interf_n != NULL) {
293     if (strcmp(interf_n->name, name) == 0) {
294       fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
295       return NULL;
296     }
297     interf_n = interf_n->next;
298   }
299
300   interf_n = olsr_malloc(sizeof(struct olsr_if), "queue interface");
301
302   name_size = strlen(name) + 1;
303   interf_n->name = olsr_malloc(name_size, "queue interface name");
304   strscpy(interf_n->name, name, name_size);
305
306   interf_n->cnf = olsr_malloc(sizeof(*interf_n->cnf), "queue cnf");
307
308   interf_n->cnfi = olsr_malloc(sizeof(*interf_n->cnfi), "queue cnfi");
309   memset(interf_n->cnfi, 0xFF, sizeof(*interf_n->cnfi));
310   interf_n->cnfi->orig_lq_mult_cnt=0;
311
312   interf_n->host_emul = hemu ? true : false;
313
314   interf_n->next = olsr_cnf->interfaces;
315   olsr_cnf->interfaces = interf_n;
316
317   return interf_n;
318 }
319
320 /**
321  *Add an ifchange function. These functions are called on all (non-initial)
322  *changes in the interface set.
323  *
324  *@param f a callback function
325  *
326  *@return always 1
327  */
328 int
329 olsr_add_ifchange_handler(void (*f) (int if_index, struct interface_olsr *, enum olsr_ifchg_flag))
330 {
331
332   struct ifchgf *new_ifchgf;
333
334   new_ifchgf = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
335
336   new_ifchgf->next = ifchgf_list;
337   new_ifchgf->function = f;
338
339   ifchgf_list = new_ifchgf;
340
341   return 1;
342 }
343
344 /*
345  * Remove an ifchange function
346  */
347 int
348 olsr_remove_ifchange_handler(void (*f) (int if_index, struct interface_olsr *, enum olsr_ifchg_flag))
349 {
350   struct ifchgf *tmp_ifchgf, *prev;
351
352   if (!f) {
353     return 0;
354   }
355
356   tmp_ifchgf = ifchgf_list;
357   prev = NULL;
358
359   while (tmp_ifchgf) {
360     if (tmp_ifchgf->function == f) {
361       /* Remove entry */
362       if (prev == NULL) {
363         ifchgf_list = tmp_ifchgf->next;
364         free(tmp_ifchgf);
365       } else {
366         prev->next = tmp_ifchgf->next;
367         free(tmp_ifchgf);
368       }
369       return 1;
370     }
371     prev = tmp_ifchgf;
372     tmp_ifchgf = tmp_ifchgf->next;
373   }
374
375   return 0;
376 }
377
378 void
379 olsr_remove_interface(struct olsr_if * iface)
380 {
381   struct interface_olsr *ifp, *tmp_ifp;
382   ifp = iface->interf;
383
384   OLSR_PRINTF(1, "Removing interface %s (%d)\n", iface->name, ifp->if_index);
385   olsr_syslog(OLSR_LOG_INFO, "Removing interface %s\n", iface->name);
386
387   olsr_delete_link_entry_by_ip(&ifp->ip_addr);
388
389   /*
390    *Call possible ifchange functions registered by plugins
391    */
392   olsr_trigger_ifchange(ifp->if_index, ifp, IFCHG_IF_REMOVE);
393
394   /* cleanup routes over this interface */
395   olsr_delete_interface_routes(ifp->if_index);
396
397   /* Dequeue */
398   if (ifp == ifnet) {
399     ifnet = ifp->int_next;
400   } else {
401     tmp_ifp = ifnet;
402     while (tmp_ifp->int_next != ifp) {
403       tmp_ifp = tmp_ifp->int_next;
404     }
405     tmp_ifp->int_next = ifp->int_next;
406   }
407
408   /* Remove output buffer */
409   net_remove_buffer(ifp);
410
411   /*
412    * Deregister functions for periodic message generation
413    */
414   olsr_stop_timer(ifp->hello_gen_timer);
415   olsr_stop_timer(ifp->tc_gen_timer);
416   olsr_stop_timer(ifp->mid_gen_timer);
417   olsr_stop_timer(ifp->hna_gen_timer);
418   ifp->hello_gen_timer = NULL;
419   ifp->tc_gen_timer = NULL;
420   ifp->mid_gen_timer = NULL;
421   ifp->hna_gen_timer = NULL;
422
423   iface->configured = 0;
424   iface->interf = NULL;
425
426   /* Close olsr socket */
427   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
428   close(ifp->olsr_socket);
429
430   remove_olsr_socket(ifp->send_socket, &olsr_input, NULL);
431   close(ifp->send_socket);
432
433   /* Free memory */
434   free(ifp->int_name);
435   free(ifp);
436
437   if ((ifnet == NULL) && (!olsr_cnf->allow_no_interfaces)) {
438     olsr_exit("No more active interfaces", EXIT_FAILURE);
439   }
440 }
441
442 /*
443  * Local Variables:
444  * c-basic-offset: 2
445  * indent-tabs-mode: nil
446  * End:
447  */