gateway: initialise the egress interface names in/for multi-gateway mode
[olsrd.git] / src / gateway.c
1 /*
2  * gateway.c
3  *
4  *  Created on: 05.01.2010
5  *      Author: henning
6  */
7
8 #ifdef __linux__
9
10 #include "common/avl.h"
11 #include "defs.h"
12 #include "ipcalc.h"
13 #include "olsr.h"
14 #include "olsr_cfg.h"
15 #include "olsr_cookie.h"
16 #include "scheduler.h"
17 #include "kernel_routes.h"
18 #include "kernel_tunnel.h"
19 #include "net_os.h"
20 #include "duplicate_set.h"
21 #include "log.h"
22 #include "gateway_default_handler.h"
23 #include "gateway_list.h"
24 #include "gateway.h"
25
26 #include <assert.h>
27 #include <net/if.h>
28
29 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
30 struct interfaceName {
31   char name[IFNAMSIZ]; /**< interface name */
32   uint8_t mark; /**< marking */
33   struct gateway_entry *gw; /**< gateway that uses this interface name */
34 };
35
36 /** the gateway tree */
37 struct avl_tree gateway_tree;
38
39 /** gateway cookie */
40 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
41
42 /** gateway container cookie */
43 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
44
45 /** the gateway netmask for the HNA */
46 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
47
48 /** the gateway handler/plugin */
49 static struct olsr_gw_handler *gw_handler;
50
51 /** the IPv4 gateway list */
52 static struct gw_list gw_list_ipv4;
53
54 /** the IPv6 gateway list */
55 static struct gw_list gw_list_ipv6;
56
57 /** the current IPv4 gateway */
58 static struct gw_container_entry *current_ipv4_gw;
59
60 /** the current IPv6 gateway */
61 static struct gw_container_entry *current_ipv6_gw;
62
63 /** interface names for smart gateway egress interfaces */
64 struct interfaceName * sgwEgressInterfaceNames;
65
66 /** interface names for smart gateway tunnel interfaces, IPv4 */
67 struct interfaceName * sgwTunnel4InterfaceNames;
68
69 /** interface names for smart gateway tunnel interfaces, IPv6 */
70 struct interfaceName * sgwTunnel6InterfaceNames;
71
72 /*
73  * Forward Declarations
74  */
75
76 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
77
78 /*
79  * Helper Functions
80  */
81
82 #define TUNNEL_NAME (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6)
83
84 #define OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen) (((uint8_t *)mask) + ((prefixlen+7)/8))
85
86 /**
87  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
88  * to an uplink/downlink speed value
89  *
90  * @param value the encoded 1 byte transport value
91  * @return the uplink/downlink speed value (in kbit/s)
92  */
93 static uint32_t deserialize_gw_speed(uint8_t value) {
94   uint32_t speed;
95   uint32_t exp;
96
97   if (!value) {
98     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
99      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
100     return 0;
101   }
102
103   speed = (value >> 3) + 1;
104   exp = value & 7;
105
106   while (exp-- > 0) {
107     speed *= 10;
108   }
109   return speed;
110 }
111
112 /**
113  * Convert an uplink/downlink speed value into an encoded 1 byte transport
114  * value (5 bits mantissa, 3 bits exponent)
115  *
116  * @param speed the uplink/downlink speed value (in kbit/s)
117  * @return value the encoded 1 byte transport value
118  */
119 static uint8_t serialize_gw_speed(uint32_t speed) {
120   uint8_t exp = 0;
121
122   if (speed == 0) {
123     return 0;
124   }
125
126   if (speed > 320000000) {
127     return 0xff;
128   }
129
130   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
131     speed /= 10;
132     exp++;
133   }
134   return ((speed - 1) << 3) | exp;
135 }
136
137 /**
138  * Dummy for generating an interface name for an olsr ipip tunnel
139  * @param target IP destination of the tunnel
140  * @param name pointer to output buffer (length IFNAMSIZ)
141  */
142 static void generate_iptunnel_name(union olsr_ip_addr *target, char * name) {
143   static uint32_t counter = 0;
144
145   memset(name, 0, IFNAMSIZ);
146   snprintf(name, IFNAMSIZ, "tnl_%08x", olsr_cnf->ip_version == AF_INET ? target->v4.s_addr : ++counter);
147 }
148
149 /*
150  * Callback Functions
151  */
152
153 /**
154  * Callback for tunnel interface monitoring which will set the route into the tunnel
155  * when the interface comes up again.
156  *
157  * @param if_index the interface index
158  * @param ifh the interface
159  * @param flag interface change flags
160  */
161 static void smartgw_tunnel_monitor(int if_index __attribute__ ((unused)),
162     struct interface *ifh __attribute__ ((unused)), enum olsr_ifchg_flag flag __attribute__ ((unused))) {
163   return;
164 }
165
166 /**
167  * Timer callback to remove and cleanup a gateway entry
168  *
169  * @param ptr
170  */
171 static void cleanup_gateway_handler(void *ptr) {
172   struct gateway_entry *gw = ptr;
173
174   if (gw->ipv4 || gw->ipv6) {
175     /* do not clean it up when it is in use */
176     return;
177   }
178
179   /* remove gateway entry */
180   avl_delete(&gateway_tree, &gw->node);
181   olsr_cookie_free(gateway_entry_mem_cookie, gw);
182 }
183
184 /*
185  * Main Interface
186  */
187
188 /**
189  * Initialize gateway system
190  */
191 int olsr_init_gateways(void) {
192   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
193   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
194
195   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
196   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
197
198   avl_init(&gateway_tree, avl_comp_default);
199
200   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
201   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
202
203   if (olsr_cnf->smart_gw_use_count <= 1) {
204     sgwEgressInterfaceNames = NULL;
205     sgwTunnel4InterfaceNames = NULL;
206     sgwTunnel6InterfaceNames = NULL;
207   } else {
208     uint8_t i;
209
210     /* setup the egress interface name/mark pairs */
211     sgwEgressInterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_egress_interfaces_count, "sgwEgressInterfaceNames");
212     for (i = 0; i < olsr_cnf->smart_gw_egress_interfaces_count; i++) {
213       struct interfaceName * ifn = &sgwEgressInterfaceNames[i];
214       ifn->gw = NULL;
215       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_egress;
216       snprintf(&ifn->name[0], sizeof(ifn->name), "egress_%03u", ifn->mark);
217     }
218
219     /* setup the SGW tunnel name/mark pairs */
220     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
221     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
222     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
223       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
224       ifn->gw = NULL;
225       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
226       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl4_%03u", ifn->mark);
227
228       ifn = &sgwTunnel6InterfaceNames[i];
229       ifn->gw = NULL;
230       ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
231       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl6_%03u", ifn->mark);
232     }
233   }
234
235   current_ipv4_gw = NULL;
236   current_ipv6_gw = NULL;
237
238   gw_handler = NULL;
239
240   refresh_smartgw_netmask();
241
242   /* initialize default gateway handler */
243   gw_handler = &gw_def_handler;
244   gw_handler->init();
245
246   if (olsr_os_init_iptunnel(TUNNEL_NAME)) {
247     return 1;
248   }
249
250   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
251
252   return 0;
253 }
254
255 /**
256  * Cleanup gateway tunnel system
257  */
258 void olsr_cleanup_gateways(void) {
259   struct avl_node * avlnode = NULL;
260   struct gw_container_entry * gw;
261
262   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
263
264   olsr_os_cleanup_iptunnel(TUNNEL_NAME);
265
266   /* remove all gateways in the gateway tree that are not the active gateway */
267   while ((avlnode = avl_walk_first(&gateway_tree))) {
268     struct gateway_entry* tree_gw = node2gateway(avlnode);
269     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
270       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
271     }
272   }
273
274   /* remove all active IPv4 gateways (should be at most 1 now) */
275   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
276     if (gw && gw->gw) {
277       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
278     }
279   }
280   OLSR_FOR_ALL_GWS_END(gw);
281
282   /* remove all active IPv6 gateways (should be at most 1 now) */
283   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
284     if (gw && gw->gw) {
285       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
286     }
287   }
288   OLSR_FOR_ALL_GWS_END(gw);
289
290   /* there should be no more gateways */
291   assert(!avl_walk_first(&gateway_tree));
292   assert(!current_ipv4_gw);
293   assert(!current_ipv6_gw);
294
295   assert(gw_handler);
296   gw_handler->cleanup();
297   gw_handler = NULL;
298
299   if (sgwEgressInterfaceNames) {
300     free(sgwEgressInterfaceNames);
301     sgwEgressInterfaceNames = NULL;
302   }
303   if (sgwTunnel4InterfaceNames) {
304     free(sgwTunnel4InterfaceNames);
305     sgwTunnel4InterfaceNames = NULL;
306   }
307   if (sgwTunnel6InterfaceNames) {
308     free(sgwTunnel6InterfaceNames);
309     sgwTunnel6InterfaceNames = NULL;
310   }
311
312   olsr_gw_list_cleanup(&gw_list_ipv6);
313   olsr_gw_list_cleanup(&gw_list_ipv4);
314   olsr_free_cookie(gw_container_entry_mem_cookie);
315   olsr_free_cookie(gateway_entry_mem_cookie);
316 }
317
318 /**
319  * Triggers the first lookup of a gateway.
320  */
321 void olsr_trigger_inetgw_startup(void) {
322   assert(gw_handler);
323   gw_handler->startup();
324 }
325
326 /**
327  * Print debug information about gateway entries
328  */
329 #ifndef NODEBUG
330 void olsr_print_gateway_entries(void) {
331   struct ipaddr_str buf;
332   struct gateway_entry *gw;
333   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
334
335   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
336   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
337       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
338
339   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
340     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
341         addrsize,
342         olsr_ip_to_string(&buf, &gw->originator),
343         gw->ipv4nat ? "" : "   ",
344         gw->ipv4 ? '4' : ' ',
345         gw->ipv4nat ? "(N)" : "",
346         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
347         gw->ipv6 ? '6' : ' ',
348         gw->uplink,
349         gw->downlink,
350         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
351   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
352 }
353 #endif /* NODEBUG */
354
355 /*
356  * Tx Path Interface
357  */
358
359 /**
360  * Apply the smart gateway modifications to an outgoing HNA
361  *
362  * @param mask pointer to netmask of the HNA
363  * @param prefixlen of the HNA
364  */
365 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
366   uint8_t *ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
367
368   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
369   if (olsr_cnf->has_ipv4_gateway) {
370     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
371
372     if (olsr_cnf->smart_gw_uplink_nat) {
373       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
374     }
375   }
376   if (olsr_cnf->has_ipv6_gateway) {
377     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
378   }
379   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
380     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
381   }
382 }
383
384 /*
385  * SgwDynSpeed Plugin Interface
386  */
387
388 /**
389  * Setup the gateway netmask
390  */
391 void refresh_smartgw_netmask(void) {
392   uint8_t *ip;
393   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
394
395   if (olsr_cnf->smart_gw_active) {
396     ip = (uint8_t *) &smart_gateway_netmask;
397
398     if (olsr_cnf->smart_gw_uplink > 0 && olsr_cnf->smart_gw_downlink > 0) {
399       /* the link is bi-directional with a non-zero bandwidth */
400       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
401       ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
402       ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
403     }
404     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
405       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
406       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
407       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
408     }
409   }
410 }
411
412 /*
413  * TC/SPF/HNA Interface
414  */
415
416 /**
417  * Checks if a HNA prefix/netmask combination is a smart gateway
418  *
419  * @param prefix
420  * @param mask
421  * @return true if is a valid smart gateway HNA, false otherwise
422  */
423 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
424   uint8_t *ptr;
425
426   if (!is_prefix_inetgw(prefix)) {
427     return false;
428   }
429
430   ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefix->prefix_len);
431   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
432 }
433
434 /**
435  * Update a gateway_entry based on a HNA
436  *
437  * @param originator ip of the source of the HNA
438  * @param mask netmask of the HNA
439  * @param prefixlen of the HNA
440  * @param seqno the sequence number of the HNA
441  */
442 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
443   struct gw_container_entry * new_gw_in_list;
444   uint8_t *ptr;
445   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
446
447   if (!gw) {
448     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
449     gw->originator = *originator;
450     gw->node.key = &gw->originator;
451
452     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
453   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
454     /* ignore older HNAs */
455     return;
456   }
457
458   /* keep new HNA seqno */
459   gw->seqno = seqno;
460
461   ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
462   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
463     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
464     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
465   } else {
466     gw->uplink = 0;
467     gw->downlink = 0;
468   }
469
470   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
471   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
472
473   if (olsr_cnf->ip_version == AF_INET6) {
474     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
475
476     /* do not reset prefixlength for ::ffff:0:0 HNAs */
477     if (prefixlen == ipv6_internet_route.prefix_len) {
478       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
479
480       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
481           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
482         /* this is the right prefix (2000::/3), so we can copy the prefix */
483         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
484         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
485       }
486     }
487   }
488
489   /* stop cleanup timer if necessary */
490   if (gw->cleanup_timer) {
491     olsr_stop_timer(gw->cleanup_timer);
492     gw->cleanup_timer = NULL;
493   }
494
495   /* update the costs of the gateway when it is an active gateway */
496   new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
497   if (new_gw_in_list) {
498     assert(gw_handler);
499     new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
500   }
501
502   /* call update handler */
503   assert(gw_handler);
504   gw_handler->update(gw);
505 }
506
507 /**
508  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
509  * Should only be called if prefix is a smart_gw prefix or if node is removed
510  * from TC set.
511  *
512  * @param originator
513  * @param prefixlen
514  * @param immediate when set to true then the gateway is removed from the
515  * gateway tree immediately, else it is removed on a delayed schedule.
516  */
517 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
518   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
519 }
520
521 /**
522  * Delete a gateway entry .
523  *
524  * @param gw a gateway entry from the gateway tree
525  * @param prefixlen
526  * @param immediate when set to true then the gateway is removed from the
527  * gateway tree immediately, else it is removed on a delayed schedule.
528  */
529 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
530   bool change = false;
531
532   if (!gw) {
533     return;
534   }
535
536   if (immediate && gw->cleanup_timer) {
537     /* stop timer if we have to remove immediately */
538     olsr_stop_timer(gw->cleanup_timer);
539     gw->cleanup_timer = NULL;
540   }
541
542   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
543     /* the gw  is not scheduled for deletion */
544
545     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
546       change = gw->ipv4;
547       gw->ipv4 = false;
548       gw->ipv4nat = false;
549     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
550       change = gw->ipv6;
551       gw->ipv6 = false;
552     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
553       change = gw->ipv4;
554       gw->ipv4 = false;
555       gw->ipv4nat = false;
556     }
557
558     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
559       struct gw_container_entry * gw_in_list;
560
561       /* prevent this gateway from being chosen as the new gateway */
562       gw->ipv4 = false;
563       gw->ipv4nat = false;
564       gw->ipv6 = false;
565
566       /* handle gateway loss */
567       assert(gw_handler);
568       gw_handler->delete(gw);
569
570       /* cleanup gateway if necessary */
571       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
572       if (gw_in_list) {
573         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
574           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, NULL);
575           current_ipv4_gw = NULL;
576         }
577
578         if (gw_in_list->tunnel) {
579           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
580           gw_in_list->tunnel = NULL;
581         }
582
583         gw_in_list->gw = NULL;
584         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
585         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
586       }
587
588       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
589       if (gw_in_list) {
590         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
591           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, NULL);
592           current_ipv6_gw = NULL;
593         }
594
595         if (gw_in_list->tunnel) {
596           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
597           gw_in_list->tunnel = NULL;
598         }
599
600         gw_in_list->gw = NULL;
601         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
602         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
603       }
604
605       if (!immediate) {
606         /* remove gateway entry on a delayed schedule */
607         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
608       } else {
609         cleanup_gateway_handler(gw);
610       }
611
612       /* when the current gateway was deleted, then immediately choose a new gateway */
613       if (!current_ipv4_gw || !current_ipv6_gw) {
614         assert(gw_handler);
615         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
616       }
617
618     } else if (change) {
619       assert(gw_handler);
620       gw_handler->update(gw);
621     }
622   }
623 }
624
625 /**
626  * Triggers a check if the one of the gateways have been lost or has an
627  * ETX = infinity
628  */
629 void olsr_trigger_gatewayloss_check(void) {
630   bool ipv4 = false;
631   bool ipv6 = false;
632
633   if (current_ipv4_gw && current_ipv4_gw->gw) {
634     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
635     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
636   }
637   if (current_ipv6_gw && current_ipv6_gw->gw) {
638     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
639     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
640   }
641
642   if (ipv4 || ipv6) {
643     assert(gw_handler);
644     gw_handler->choose(ipv4, ipv6);
645   }
646 }
647
648 /*
649  * Gateway Plugin Functions
650  */
651
652 /**
653  * Sets a new internet gateway.
654  *
655  * @param originator ip address of the node with the new gateway
656  * @param path_cost the path cost
657  * @param ipv4 set ipv4 gateway
658  * @param ipv6 set ipv6 gateway
659  * @return true if an error happened, false otherwise
660  */
661 bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6) {
662   struct gateway_entry *new_gw;
663
664   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
665   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
666   if (!ipv4 && !ipv6) {
667     return true;
668   }
669
670   new_gw = node2gateway(avl_find(&gateway_tree, originator));
671   if (!new_gw) {
672     /* the originator is not in the gateway tree, we can't set it as gateway */
673     return true;
674   }
675
676   /* handle IPv4 */
677   if (ipv4 && new_gw->ipv4 && (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) && (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
678     /* new gw is different than the current gw */
679
680     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
681     if (new_gw_in_list) {
682       /* new gw is already in the gw list */
683       assert(new_gw_in_list->tunnel);
684       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, NULL);
685       current_ipv4_gw = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, path_cost);
686     } else {
687       /* new gw is not yet in the gw list */
688       char name[IFNAMSIZ];
689       struct olsr_iptunnel_entry *new_v4gw_tunnel;
690
691       if (olsr_gw_list_full(&gw_list_ipv4)) {
692         /* the list is full: remove the worst active gateway */
693         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
694         assert(worst);
695
696         if (worst->tunnel) {
697           olsr_os_del_ipip_tunnel(worst->tunnel);
698           worst->tunnel = NULL;
699         }
700         worst->gw = NULL;
701         olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(&gw_list_ipv4, worst));
702       }
703
704       generate_iptunnel_name(&new_gw->originator, name);
705       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
706       if (new_v4gw_tunnel) {
707         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, NULL);
708
709         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
710         new_gw_in_list->gw = new_gw;
711         new_gw_in_list->tunnel = new_v4gw_tunnel;
712         new_gw_in_list->path_cost = path_cost;
713         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
714       } else {
715         /* adding the tunnel failed, we try again in the next cycle */
716         ipv4 = false;
717       }
718     }
719   }
720
721   /* handle IPv6 */
722   if (ipv6 && new_gw->ipv6 && (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
723     /* new gw is different than the current gw */
724
725         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
726     if (new_gw_in_list) {
727       /* new gw is already in the gw list */
728       assert(new_gw_in_list->tunnel);
729       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, NULL);
730       current_ipv6_gw = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, path_cost);
731     } else {
732       /* new gw is not yet in the gw list */
733       char name[IFNAMSIZ];
734       struct olsr_iptunnel_entry *new_v6gw_tunnel;
735
736       if (olsr_gw_list_full(&gw_list_ipv6)) {
737         /* the list is full: remove the worst active gateway */
738         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
739         assert(worst);
740
741         if (worst->tunnel) {
742           olsr_os_del_ipip_tunnel(worst->tunnel);
743           worst->tunnel = NULL;
744         }
745         worst->gw = NULL;
746         olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(&gw_list_ipv6, worst));
747       }
748
749       generate_iptunnel_name(&new_gw->originator, name);
750       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
751       if (new_v6gw_tunnel) {
752         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, NULL);
753
754         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
755         new_gw_in_list->gw = new_gw;
756         new_gw_in_list->tunnel = new_v6gw_tunnel;
757         new_gw_in_list->path_cost = path_cost;
758         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
759       } else {
760         /* adding the tunnel failed, we try again in the next cycle */
761         ipv6 = false;
762       }
763     }
764   }
765
766   return !ipv4 && !ipv6;
767 }
768
769 /**
770  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
771  * gateway is returned
772  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
773  * NULL if not set.
774  */
775 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
776         if (ipv6) {
777                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
778         }
779
780         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
781 }
782
783 #endif /* __linux__ */