sgw: track the up status of an egress interface
[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 #include "egressTypes.h"
26 #include "egressFile.h"
27
28 #include <assert.h>
29 #include <net/if.h>
30
31 /*
32  * Defines for the multi-gateway script
33  */
34
35 #define SCRIPT_MODE_GENERIC   "generic"
36 #define SCRIPT_MODE_OLSRIF    "olsrif"
37 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
38 #define SCRIPT_MODE_EGRESSIF  "egressif"
39 #define SCRIPT_MODE_SGWTUN    "sgwtun"
40
41 /** structure that holds an interface name, mark and a pointer to the gateway that uses it */
42 struct interfaceName {
43   char name[IFNAMSIZ]; /**< interface name */
44   uint8_t tableNr; /**< routing table number */
45   uint8_t ruleNr; /**< IP rule number */
46   uint8_t bypassRuleNr; /**< bypass IP rule number */
47   struct gateway_entry *gw; /**< gateway that uses this interface name */
48 };
49
50 /** the gateway tree */
51 struct avl_tree gateway_tree;
52
53 /** gateway cookie */
54 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
55
56 /** gateway container cookie */
57 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
58
59 /** the gateway netmask for the HNA */
60 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
61
62 /** the gateway handler/plugin */
63 static struct olsr_gw_handler *gw_handler;
64
65 /** the IPv4 gateway list */
66 struct gw_list gw_list_ipv4;
67
68 /** the IPv6 gateway list */
69 struct gw_list gw_list_ipv6;
70
71 /** the current IPv4 gateway */
72 static struct gw_container_entry *current_ipv4_gw;
73
74 /** the current IPv6 gateway */
75 static struct gw_container_entry *current_ipv6_gw;
76
77 /** interface names for smart gateway tunnel interfaces, IPv4 */
78 struct interfaceName * sgwTunnel4InterfaceNames;
79
80 /** interface names for smart gateway tunnel interfaces, IPv6 */
81 struct interfaceName * sgwTunnel6InterfaceNames;
82
83 /** the timer for proactive takedown */
84 static struct timer_entry *gw_takedown_timer;
85
86 /*
87  * Forward Declarations
88  */
89
90 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
91
92 /*
93  * Helper Functions
94  */
95
96 /**
97  * @return the gateway 'server' tunnel name to use
98  */
99 static inline const char * server_tunnel_name(void) {
100   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
101 }
102
103 /**
104  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
105  * pointer.
106  *
107  * @param mask the netmask of the HNA (in the form of an IP address)
108  * @param prefixlen the prefix length
109  * @return a pointer to the HNA
110  */
111 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
112   return (((uint8_t *)mask) + ((prefixlen+7)/8));
113 }
114
115 /**
116  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
117  * to an uplink/downlink speed value
118  *
119  * @param value the encoded 1 byte transport value
120  * @return the uplink/downlink speed value (in kbit/s)
121  */
122 static uint32_t deserialize_gw_speed(uint8_t value) {
123   uint32_t speed;
124   uint32_t exp;
125
126   if (!value) {
127     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
128      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
129     return 0;
130   }
131
132   if (value == UINT8_MAX) {
133     /* maximum value: also return maximum value */
134     return 320000000;
135   }
136
137   speed = (value >> 3) + 1;
138   exp = value & 7;
139
140   while (exp-- > 0) {
141     speed *= 10;
142   }
143   return speed;
144 }
145
146 /**
147  * Convert an uplink/downlink speed value into an encoded 1 byte transport
148  * value (5 bits mantissa, 3 bits exponent)
149  *
150  * @param speed the uplink/downlink speed value (in kbit/s)
151  * @return value the encoded 1 byte transport value
152  */
153 static uint8_t serialize_gw_speed(uint32_t speed) {
154   uint8_t exp = 0;
155
156   if (speed == 0) {
157     return 0;
158   }
159
160   if (speed > 320000000) {
161     return UINT8_MAX;
162   }
163
164   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
165     speed /= 10;
166     exp++;
167   }
168   return ((speed - 1) << 3) | exp;
169 }
170
171 /**
172  * Find an interfaceName struct corresponding to a certain gateway
173  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
174  *
175  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
176  * @return a pointer to the struct, or NULL when not found
177  */
178 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
179   struct interfaceName * sgwTunnelInterfaceNames;
180   uint8_t i = 0;
181
182   if (!multi_gateway_mode()) {
183     return NULL;
184   }
185
186   assert(sgwTunnel4InterfaceNames);
187   assert(sgwTunnel6InterfaceNames);
188
189   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
190   while (i < olsr_cnf->smart_gw_use_count) {
191     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
192     if (ifn->gw == gw) {
193       return ifn;
194     }
195     i++;
196   }
197
198   return NULL;
199 }
200
201 /**
202  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
203  *
204  * @param gw pointer to the gateway
205  * @param name pointer to output buffer (length IFNAMSIZ)
206  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
207  */
208 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
209   static uint32_t counter = 0;
210
211   assert(gw);
212   assert(name);
213   assert(interfaceName);
214
215   memset(name, 0, IFNAMSIZ);
216
217   if (multi_gateway_mode()) {
218     struct interfaceName * ifn = find_interfaceName(NULL);
219
220     if (ifn) {
221       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
222       *interfaceName = ifn;
223       ifn->gw = gw;
224       return;
225     }
226
227     /* do not return, fall-through to classic naming as fallback */
228   }
229
230   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
231   *interfaceName = NULL;
232 }
233
234 /**
235  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
236  *
237  * @param gw pointer to the gateway
238  */
239 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
240   struct interfaceName * ifn;
241
242   if (!multi_gateway_mode()) {
243     return;
244   }
245
246   assert(gw);
247
248   ifn = find_interfaceName(gw);
249   if (ifn) {
250     ifn->gw = NULL;
251     return;
252   }
253 }
254
255 /**
256  * Run the multi-gateway script/
257  *
258  * @param mode the mode (see SCRIPT_MODE_* defines)
259  * @param addMode true to add policy routing, false to remove it
260  * @param ifname the interface name (optional)
261  * @param tableNr the routing table number (optional)
262  * @param ruleNr the IP rule number/priority (optional)
263  * @param bypassRuleNr the bypass IP rule number/priority (optional)
264  * @return true when successful
265  */
266 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
267   struct autobuf buf;
268   int r;
269
270   assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
271       || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
272       || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
273       || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
274       || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
275       );
276
277   assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
278       || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
279
280   assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
281       || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
282
283   assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
284       || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
285
286   assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
287       || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
288
289   assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
290       || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
291
292   abuf_init(&buf, 1024);
293
294   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
295
296   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
297
298   abuf_appendf(&buf, " \"%s\"", mode);
299
300   abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
301
302   if (ifName) {
303     abuf_appendf(&buf, " \"%s\"", ifName);
304   }
305
306   if (tableNr) {
307     abuf_appendf(&buf, " \"%u\"", tableNr);
308   }
309
310   if (ruleNr) {
311     abuf_appendf(&buf, " \"%u\"", ruleNr);
312   }
313
314   if (bypassRuleNr) {
315     abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
316   }
317
318   r = system(buf.buf);
319
320   abuf_free(&buf);
321
322   return (r == 0);
323 }
324
325 /**
326  * Setup generic multi-gateway iptables and ip rules
327  *
328  * @param add true to add policy routing, false to remove it
329  * @return true when successful
330  */
331 static bool multiGwRulesGeneric(bool add) {
332   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
333 }
334
335 /**
336  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
337  *
338  * @param add true to add policy routing, false to remove it
339  * @return true when successful
340  */
341 static bool multiGwRulesOlsrInterfaces(bool add) {
342   bool ok = true;
343   struct olsr_if * ifn;
344   unsigned int i = 0;
345
346   for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
347     if (!multiGwRunScript( //
348         SCRIPT_MODE_OLSRIF,//
349         add, //
350         ifn->name, //
351         0, //
352         0, //
353         olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
354             )) {
355       ok = false;
356       if (add) {
357         return ok;
358       }
359     }
360   }
361
362   return ok;
363 }
364
365 /**
366  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
367  *
368  * @param add true to add policy routing, false to remove it
369  * @return true when successful
370  */
371 static bool multiGwRulesSgwServerTunnel(bool add) {
372   return multiGwRunScript( //
373       SCRIPT_MODE_SGWSRVTUN,//
374       add, //
375       server_tunnel_name(), //
376       olsr_cnf->smart_gw_offset_tables, //
377       olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
378       0 //
379       );
380 }
381
382 /**
383  * Setup multi-gateway iptables and ip rules for all egress interfaces.
384  *
385  * @param add true to add policy routing, false to remove it
386  * @return true when successful
387  */
388 static bool multiGwRulesEgressInterfaces(bool add) {
389   bool ok = true;
390   unsigned int i = 0;
391
392   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
393   while (egress_if) {
394     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
395       ok = false;
396       if (add) {
397         return ok;
398       }
399     }
400
401     egress_if = egress_if->next;
402   }
403
404   return ok;
405 }
406
407 /**
408  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
409  *
410  * @param add true to add policy routing, false to remove it
411  * @return true when successful
412  */
413 static bool multiGwRulesSgwTunnels(bool add) {
414   bool ok = true;
415   unsigned int i = 0;
416
417   while (i < olsr_cnf->smart_gw_use_count) {
418     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
419     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
420       ok = false;
421       if (add) {
422         return ok;
423       }
424     }
425
426     i++;
427   }
428
429   return ok;
430 }
431
432 /*
433  * Callback Functions
434  */
435
436 /**
437  * Callback for tunnel interface monitoring which will set the route into the tunnel
438  * when the interface comes up again.
439  *
440  * @param if_index the interface index
441  * @param ifh the interface
442  * @param flag interface change flags
443  */
444 static void smartgw_tunnel_monitor(int if_index __attribute__ ((unused)),
445     struct interface *ifh __attribute__ ((unused)), enum olsr_ifchg_flag flag __attribute__ ((unused))) {
446   return;
447 }
448
449 /**
450  * Timer callback to remove and cleanup a gateway entry
451  *
452  * @param ptr
453  */
454 static void cleanup_gateway_handler(void *ptr) {
455   struct gateway_entry *gw = ptr;
456
457   if (gw->ipv4 || gw->ipv6) {
458     /* do not clean it up when it is in use */
459     return;
460   }
461
462   /* remove gateway entry */
463   avl_delete(&gateway_tree, &gw->node);
464   olsr_cookie_free(gateway_entry_mem_cookie, gw);
465 }
466
467 /**
468  * Remove a gateway from a gateway list.
469  *
470  * @param gw_list a pointer to the gateway list
471  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
472  * @param gw a pointer to the gateway to remove from the list
473  */
474 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
475   if (gw->tunnel) {
476     struct interfaceName * ifn = find_interfaceName(gw->gw);
477     if (ifn) {
478       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
479     }
480     olsr_os_del_ipip_tunnel(gw->tunnel);
481     set_unused_iptunnel_name(gw->gw);
482     gw->tunnel = NULL;
483   }
484   gw->gw = NULL;
485   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
486 }
487
488 /**
489  * Remove expensive gateways from the gateway list.
490  * It uses the smart_gw_takedown_percentage configuration parameter
491  *
492  * @param gw_list a pointer to the gateway list
493  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
494  * @param current_gw the current gateway
495  */
496 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
497   int64_t current_gw_cost_boundary;
498
499   /*
500    * exit immediately when takedown is disabled, there is no current gateway, or
501    * when there is only a single gateway
502    */
503   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
504     return;
505   }
506
507   /* get the cost boundary */
508   current_gw_cost_boundary = current_gw->gw->path_cost;
509   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
510     if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
511       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
512     } else {
513       /* perform scaling because otherwise the percentage calculation can overflow */
514       current_gw_cost_boundary = (((current_gw_cost_boundary      ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
515     }
516   }
517
518   /* loop while we still have gateways */
519   while (gw_list->count > 1) {
520     /* get the worst gateway */
521     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
522
523     /* exit when it's the current gateway */
524     if (worst_gw == current_gw) {
525       return;
526     }
527
528     /*
529      * exit when it (and further ones; the list is sorted on costs) has lower
530      * costs than the boundary costs
531      */
532     if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
533       return;
534     }
535
536     /* it's too expensive: take it down */
537     removeGatewayFromList(gw_list, ipv4, worst_gw);
538   }
539 }
540
541 /**
542  * Timer callback for proactive gateway takedown
543  *
544  * @param unused unused
545  */
546 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
547   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
548   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
549 }
550
551 /*
552  * Main Interface
553  */
554
555 /**
556  * Initialize gateway system
557  */
558 int olsr_init_gateways(void) {
559   int retries = 5;
560
561   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
562   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
563
564   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
565   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
566
567   avl_init(&gateway_tree, avl_comp_default);
568
569   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
570   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
571
572   if (!multi_gateway_mode()) {
573     sgwTunnel4InterfaceNames = NULL;
574     sgwTunnel6InterfaceNames = NULL;
575   } else {
576     uint8_t i;
577     struct sgw_egress_if * egressif;
578     unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
579
580     /* setup the egress interface name/mark pairs */
581     i = 0;
582     egressif = olsr_cnf->smart_gw_egress_interfaces;
583     while (egressif) {
584       egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
585       egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
586       egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
587
588       egressif = egressif->next;
589       i++;
590     }
591     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
592
593     /* setup the SGW tunnel name/mark pairs */
594     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
595     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
596     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
597       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
598       uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
599       uint32_t ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
600
601       ifn->gw = NULL;
602       ifn->tableNr = tableNr;
603       ifn->ruleNr = ruleNr;
604       ifn->bypassRuleNr = 0;
605       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
606
607       ifn = &sgwTunnel6InterfaceNames[i];
608       ifn->gw = NULL;
609       ifn->tableNr = tableNr;
610       ifn->ruleNr = ruleNr;
611       ifn->bypassRuleNr = 0;
612       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
613     }
614   }
615
616   current_ipv4_gw = NULL;
617   current_ipv6_gw = NULL;
618
619   gw_handler = NULL;
620
621   refresh_smartgw_netmask();
622
623   /* initialize default gateway handler */
624   gw_handler = &gw_def_handler;
625   gw_handler->init();
626
627
628   /*
629    * There appears to be a kernel bug in some kernels (at least in the 3.0
630    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
631    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
632    * a few times before giving up
633    */
634   while (retries-- > 0) {
635     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
636       retries = 5;
637       break;
638     }
639
640     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
641   }
642   if (retries <= 0) {
643     return 1;
644   }
645
646   return 0;
647 }
648
649 /**
650  * Startup gateway system
651  */
652 int olsr_startup_gateways(void) {
653   bool ok = true;
654
655   if (!multi_gateway_mode()) {
656     olsr_add_ifchange_handler(smartgw_tunnel_monitor);
657     return 0;
658   }
659
660   /* Initialise the egress interfaces */
661   {
662     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
663     while (egress_if) {
664       egress_if->if_index = if_nametoindex(egress_if->name);
665
666       egress_if->upPrevious = egress_if->upCurrent = olsr_if_isup(egress_if->name);
667       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
668
669       egressBwClear(&egress_if->bwPrevious, egress_if->upPrevious);
670       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
671       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
672       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
673       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
674       egress_if->bwChanged = egressBwChanged(egress_if);
675
676       egress_if->inEgressFile = false;
677
678       egress_if = egress_if->next;
679     }
680   }
681
682   ok = ok && multiGwRulesGeneric(true);
683   ok = ok && multiGwRulesSgwServerTunnel(true);
684   ok = ok && multiGwRulesOlsrInterfaces(true);
685   ok = ok && multiGwRulesEgressInterfaces(true);
686   ok = ok && multiGwRulesSgwTunnels(true);
687   if (!ok) {
688     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
689     olsr_shutdown_gateways();
690     return 1;
691   }
692
693   startEgressFile();
694   // FIXME process changes (always: initial setup)
695
696   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
697
698   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
699     /* start gateway takedown timer */
700     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
701   }
702
703   return 0;
704 }
705
706 /**
707  * Shutdown gateway tunnel system
708  */
709 void olsr_shutdown_gateways(void) {
710   if (!multi_gateway_mode()) {
711     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
712     return;
713   }
714
715   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
716     /* stop gateway takedown timer */
717     olsr_stop_timer(gw_takedown_timer);
718     gw_takedown_timer = NULL;
719   }
720
721   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
722
723   stopEgressFile();
724   {
725     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
726     while (egress_if) {
727       egress_if->upPrevious = egress_if->upCurrent;
728       egress_if->upCurrent = false;
729       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
730
731       egress_if->bwPrevious = egress_if->bwCurrent;
732       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
733       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
734       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
735       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
736       egress_if->bwChanged = egressBwChanged(egress_if);
737
738       egress_if->inEgressFile = false;
739
740       egress_if = egress_if->next;
741     }
742   }
743   // FIXME process changes (always: shutdown)
744
745   (void)multiGwRulesSgwTunnels(false);
746   (void)multiGwRulesEgressInterfaces(false);
747   (void)multiGwRulesOlsrInterfaces(false);
748   (void)multiGwRulesSgwServerTunnel(false);
749   (void)multiGwRulesGeneric(false);
750 }
751
752 /**
753  * Cleanup gateway tunnel system
754  */
755 void olsr_cleanup_gateways(void) {
756   struct gateway_entry * tree_gw;
757   struct gw_container_entry * gw;
758
759   /* remove all gateways in the gateway tree that are not the active gateway */
760   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
761     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
762       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
763     }
764   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
765
766   /* remove all active IPv4 gateways (should be at most 1 now) */
767   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
768     if (gw && gw->gw) {
769       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
770     }
771   }
772   OLSR_FOR_ALL_GWS_END(gw);
773
774   /* remove all active IPv6 gateways (should be at most 1 now) */
775   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
776     if (gw && gw->gw) {
777       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
778     }
779   }
780   OLSR_FOR_ALL_GWS_END(gw);
781
782   /* there should be no more gateways */
783   assert(!avl_walk_first(&gateway_tree));
784   assert(!current_ipv4_gw);
785   assert(!current_ipv6_gw);
786
787   olsr_os_cleanup_iptunnel(server_tunnel_name());
788
789   assert(gw_handler);
790   gw_handler->cleanup();
791   gw_handler = NULL;
792
793   if (sgwTunnel4InterfaceNames) {
794     free(sgwTunnel4InterfaceNames);
795     sgwTunnel4InterfaceNames = NULL;
796   }
797   if (sgwTunnel6InterfaceNames) {
798     free(sgwTunnel6InterfaceNames);
799     sgwTunnel6InterfaceNames = NULL;
800   }
801
802   olsr_gw_list_cleanup(&gw_list_ipv6);
803   olsr_gw_list_cleanup(&gw_list_ipv4);
804   olsr_free_cookie(gw_container_entry_mem_cookie);
805   olsr_free_cookie(gateway_entry_mem_cookie);
806 }
807
808 /**
809  * Triggers the first lookup of a gateway.
810  */
811 void olsr_trigger_inetgw_startup(void) {
812   assert(gw_handler);
813   gw_handler->startup();
814 }
815
816 /**
817  * Print debug information about gateway entries
818  */
819 #ifndef NODEBUG
820 void olsr_print_gateway_entries(void) {
821   struct ipaddr_str buf;
822   struct gateway_entry *gw;
823   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
824
825   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
826   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
827       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
828
829   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
830     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
831         addrsize,
832         olsr_ip_to_string(&buf, &gw->originator),
833         gw->ipv4nat ? "" : "   ",
834         gw->ipv4 ? '4' : ' ',
835         gw->ipv4nat ? "(N)" : "",
836         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
837         gw->ipv6 ? '6' : ' ',
838         gw->uplink,
839         gw->downlink,
840         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
841   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
842 }
843 #endif /* NODEBUG */
844
845 /*
846  * Tx Path Interface
847  */
848
849 /**
850  * Apply the smart gateway modifications to an outgoing HNA
851  *
852  * @param mask pointer to netmask of the HNA
853  * @param prefixlen of the HNA
854  */
855 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
856   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
857
858   /* copy the current settings for uplink/downlink into the mask */
859   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
860   if (olsr_cnf->has_ipv4_gateway) {
861     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
862
863     if (olsr_cnf->smart_gw_uplink_nat) {
864       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
865     }
866   }
867   if (olsr_cnf->has_ipv6_gateway) {
868     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
869   }
870   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
871     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
872   }
873 }
874
875 /*
876  * SgwDynSpeed Plugin Interface
877  */
878
879 /**
880  * Setup the gateway netmask
881  */
882 void refresh_smartgw_netmask(void) {
883   uint8_t *ip;
884
885   /* clear the mask */
886   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
887
888   if (olsr_cnf->smart_gw_active) {
889     ip = (uint8_t *) &smart_gateway_netmask;
890
891     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
892     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
893     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
894
895     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
896       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
897       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
898       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
899     }
900   }
901 }
902
903 /*
904  * TC/SPF/HNA Interface
905  */
906
907 /**
908  * Checks if a HNA prefix/netmask combination is a smart gateway
909  *
910  * @param prefix
911  * @param mask
912  * @return true if is a valid smart gateway HNA, false otherwise
913  */
914 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
915   uint8_t *ptr;
916
917   if (!is_prefix_inetgw(prefix)) {
918     return false;
919   }
920
921   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
922   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
923 }
924
925 /**
926  * Update a gateway_entry based on a HNA
927  *
928  * @param originator ip of the source of the HNA
929  * @param mask netmask of the HNA
930  * @param prefixlen of the HNA
931  * @param seqno the sequence number of the HNA
932  */
933 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
934   struct gw_container_entry * new_gw_in_list;
935   uint8_t *ptr;
936   int64_t prev_path_cost = 0;
937   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
938
939   if (!gw) {
940     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
941     gw->originator = *originator;
942     gw->node.key = &gw->originator;
943
944     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
945   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
946     /* ignore older HNAs */
947     return;
948   }
949
950   /* keep new HNA seqno */
951   gw->seqno = seqno;
952
953   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
954   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
955     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
956     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
957   } else {
958     gw->uplink = 0;
959     gw->downlink = 0;
960   }
961
962   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
963   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
964   gw->ipv6 = false;
965
966   if (olsr_cnf->ip_version == AF_INET6) {
967     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
968
969     /* do not reset prefixlength for ::ffff:0:0 HNAs */
970     if (prefixlen == ipv6_internet_route.prefix_len) {
971       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
972
973       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
974           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
975         /* this is the right prefix (2000::/3), so we can copy the prefix */
976         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
977         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
978       }
979     }
980   }
981
982   /* stop cleanup timer if necessary */
983   if (gw->cleanup_timer) {
984     olsr_stop_timer(gw->cleanup_timer);
985     gw->cleanup_timer = NULL;
986   }
987
988   assert(gw_handler);
989   prev_path_cost = gw->path_cost;
990   gw->path_cost = gw_handler->getcosts(gw);
991
992   if (prev_path_cost != gw->path_cost) {
993     /* re-sort the gateway list when costs have changed and when it is an active gateway */
994     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
995     if (new_gw_in_list) {
996       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
997       assert(new_gw_in_list);
998     }
999
1000     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1001     if (new_gw_in_list) {
1002       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1003       assert(new_gw_in_list);
1004     }
1005   }
1006
1007   /* call update handler */
1008   assert(gw_handler);
1009   gw_handler->update(gw);
1010 }
1011
1012 /**
1013  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1014  * Should only be called if prefix is a smart_gw prefix or if node is removed
1015  * from TC set.
1016  *
1017  * @param originator
1018  * @param prefixlen
1019  * @param immediate when set to true then the gateway is removed from the
1020  * gateway tree immediately, else it is removed on a delayed schedule.
1021  */
1022 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1023   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1024 }
1025
1026 /**
1027  * Delete a gateway entry .
1028  *
1029  * @param gw a gateway entry from the gateway tree
1030  * @param prefixlen
1031  * @param immediate when set to true then the gateway is removed from the
1032  * gateway tree immediately, else it is removed on a delayed schedule.
1033  */
1034 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1035   bool change = false;
1036
1037   if (!gw) {
1038     return;
1039   }
1040
1041   if (immediate && gw->cleanup_timer) {
1042     /* stop timer if we have to remove immediately */
1043     olsr_stop_timer(gw->cleanup_timer);
1044     gw->cleanup_timer = NULL;
1045   }
1046
1047   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1048     /* the gw  is not scheduled for deletion */
1049
1050     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1051       change = gw->ipv4;
1052       gw->ipv4 = false;
1053       gw->ipv4nat = false;
1054     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1055       change = gw->ipv6;
1056       gw->ipv6 = false;
1057     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1058       change = gw->ipv4;
1059       gw->ipv4 = false;
1060       gw->ipv4nat = false;
1061     }
1062
1063     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1064       struct gw_container_entry * gw_in_list;
1065
1066       /* prevent this gateway from being chosen as the new gateway */
1067       gw->ipv4 = false;
1068       gw->ipv4nat = false;
1069       gw->ipv6 = false;
1070
1071       /* handle gateway loss */
1072       assert(gw_handler);
1073       gw_handler->delete(gw);
1074
1075       /* cleanup gateway if necessary */
1076       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1077       if (gw_in_list) {
1078         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1079           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1080           current_ipv4_gw = NULL;
1081         }
1082
1083         if (gw_in_list->tunnel) {
1084           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1085           if (ifn) {
1086             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1087           }
1088           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1089           set_unused_iptunnel_name(gw_in_list->gw);
1090           gw_in_list->tunnel = NULL;
1091         }
1092
1093         gw_in_list->gw = NULL;
1094         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1095         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1096       }
1097
1098       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1099       if (gw_in_list) {
1100         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1101           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1102           current_ipv6_gw = NULL;
1103         }
1104
1105         if (gw_in_list->tunnel) {
1106           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1107           if (ifn) {
1108             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1109           }
1110           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1111           set_unused_iptunnel_name(gw_in_list->gw);
1112           gw_in_list->tunnel = NULL;
1113         }
1114
1115         gw_in_list->gw = NULL;
1116         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1117         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1118       }
1119
1120       if (!immediate) {
1121         /* remove gateway entry on a delayed schedule */
1122         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1123       } else {
1124         cleanup_gateway_handler(gw);
1125       }
1126
1127       /* when the current gateway was deleted, then immediately choose a new gateway */
1128       if (!current_ipv4_gw || !current_ipv6_gw) {
1129         assert(gw_handler);
1130         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1131       }
1132
1133     } else if (change) {
1134       assert(gw_handler);
1135       gw_handler->update(gw);
1136     }
1137   }
1138 }
1139
1140 /**
1141  * Triggers a check if the one of the gateways have been lost or has an
1142  * ETX = infinity
1143  */
1144 void olsr_trigger_gatewayloss_check(void) {
1145   bool ipv4 = false;
1146   bool ipv6 = false;
1147
1148   if (current_ipv4_gw && current_ipv4_gw->gw) {
1149     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1150     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1151   }
1152   if (current_ipv6_gw && current_ipv6_gw->gw) {
1153     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1154     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1155   }
1156
1157   if (ipv4 || ipv6) {
1158     assert(gw_handler);
1159     gw_handler->choose(ipv4, ipv6);
1160   }
1161 }
1162
1163 /*
1164  * Gateway Plugin Functions
1165  */
1166
1167 /**
1168  * Sets a new internet gateway.
1169  *
1170  * @param the chosen gateway
1171  * @param ipv4 set ipv4 gateway
1172  * @param ipv6 set ipv6 gateway
1173  * @return true if an error happened, false otherwise
1174  */
1175 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1176   struct gateway_entry *new_gw;
1177
1178   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1179   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1180   if (!ipv4 && !ipv6) {
1181     return true;
1182   }
1183
1184   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1185   if (!new_gw) {
1186     /* the originator is not in the gateway tree, we can't set it as gateway */
1187     return true;
1188   }
1189
1190   /* handle IPv4 */
1191   if (ipv4 &&
1192       new_gw->ipv4 &&
1193       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1194       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1195     /* new gw is different than the current gw */
1196
1197     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1198     if (new_gw_in_list) {
1199       /* new gw is already in the gw list */
1200       assert(new_gw_in_list->tunnel);
1201       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1202       current_ipv4_gw = new_gw_in_list;
1203     } else {
1204       /* new gw is not yet in the gw list */
1205       char name[IFNAMSIZ];
1206       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1207       struct interfaceName * interfaceName;
1208
1209       if (olsr_gw_list_full(&gw_list_ipv4)) {
1210         /* the list is full: remove the worst active gateway */
1211         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1212         assert(worst);
1213
1214         removeGatewayFromList(&gw_list_ipv4, true, worst);
1215       }
1216
1217       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1218       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1219       if (new_v4gw_tunnel) {
1220         if (interfaceName) {
1221           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1222         }
1223         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1224
1225         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1226         new_gw_in_list->gw = new_gw;
1227         new_gw_in_list->tunnel = new_v4gw_tunnel;
1228         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1229       } else {
1230         /* adding the tunnel failed, we try again in the next cycle */
1231         set_unused_iptunnel_name(new_gw);
1232         ipv4 = false;
1233       }
1234     }
1235   }
1236
1237   /* handle IPv6 */
1238   if (ipv6 &&
1239       new_gw->ipv6 &&
1240       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1241     /* new gw is different than the current gw */
1242
1243         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1244     if (new_gw_in_list) {
1245       /* new gw is already in the gw list */
1246       assert(new_gw_in_list->tunnel);
1247       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1248       current_ipv6_gw = new_gw_in_list;
1249     } else {
1250       /* new gw is not yet in the gw list */
1251       char name[IFNAMSIZ];
1252       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1253       struct interfaceName * interfaceName;
1254
1255       if (olsr_gw_list_full(&gw_list_ipv6)) {
1256         /* the list is full: remove the worst active gateway */
1257         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1258         assert(worst);
1259
1260         removeGatewayFromList(&gw_list_ipv6, false, worst);
1261       }
1262
1263       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1264       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1265       if (new_v6gw_tunnel) {
1266         if (interfaceName) {
1267           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1268         }
1269         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1270
1271         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1272         new_gw_in_list->gw = new_gw;
1273         new_gw_in_list->tunnel = new_v6gw_tunnel;
1274         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1275       } else {
1276         /* adding the tunnel failed, we try again in the next cycle */
1277         set_unused_iptunnel_name(new_gw);
1278         ipv6 = false;
1279       }
1280     }
1281   }
1282
1283   return !ipv4 && !ipv6;
1284 }
1285
1286 /**
1287  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1288  * gateway is returned
1289  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1290  * NULL if not set.
1291  */
1292 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1293         if (ipv6) {
1294                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1295         }
1296
1297         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1298 }
1299
1300 #endif /* __linux__ */