sgw: add egress file reader
[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       egressBwClear(&egress_if->bwPrevious, false);
665       egressBwClear(&egress_if->bwCurrent, false);
666       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
667       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
668       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
669       egress_if->bwChanged = egressBwChanged(egress_if);
670
671       egress_if->inEgressFile = false;
672
673       egress_if = egress_if->next;
674     }
675   }
676
677   ok = ok && multiGwRulesGeneric(true);
678   ok = ok && multiGwRulesSgwServerTunnel(true);
679   ok = ok && multiGwRulesOlsrInterfaces(true);
680   ok = ok && multiGwRulesEgressInterfaces(true);
681   ok = ok && multiGwRulesSgwTunnels(true);
682   if (!ok) {
683     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
684     olsr_shutdown_gateways();
685     return 1;
686   }
687
688   startEgressFile();
689   // FIXME process changes (always: initial setup)
690
691   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
692
693   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
694     /* start gateway takedown timer */
695     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
696   }
697
698   return 0;
699 }
700
701 /**
702  * Shutdown gateway tunnel system
703  */
704 void olsr_shutdown_gateways(void) {
705   if (!multi_gateway_mode()) {
706     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
707     return;
708   }
709
710   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
711     /* stop gateway takedown timer */
712     olsr_stop_timer(gw_takedown_timer);
713     gw_takedown_timer = NULL;
714   }
715
716   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
717
718   stopEgressFile();
719   {
720     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
721     while (egress_if) {
722       egress_if->bwPrevious = egress_if->bwCurrent;
723       egressBwClear(&egress_if->bwCurrent, false);
724       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
725       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
726       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
727       egress_if->bwChanged = egressBwChanged(egress_if);
728
729       egress_if->inEgressFile = false;
730
731       egress_if = egress_if->next;
732     }
733   }
734   // FIXME process changes (always: shutdown)
735
736   (void)multiGwRulesSgwTunnels(false);
737   (void)multiGwRulesEgressInterfaces(false);
738   (void)multiGwRulesOlsrInterfaces(false);
739   (void)multiGwRulesSgwServerTunnel(false);
740   (void)multiGwRulesGeneric(false);
741 }
742
743 /**
744  * Cleanup gateway tunnel system
745  */
746 void olsr_cleanup_gateways(void) {
747   struct gateway_entry * tree_gw;
748   struct gw_container_entry * gw;
749
750   /* remove all gateways in the gateway tree that are not the active gateway */
751   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
752     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
753       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
754     }
755   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
756
757   /* remove all active IPv4 gateways (should be at most 1 now) */
758   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
759     if (gw && gw->gw) {
760       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
761     }
762   }
763   OLSR_FOR_ALL_GWS_END(gw);
764
765   /* remove all active IPv6 gateways (should be at most 1 now) */
766   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
767     if (gw && gw->gw) {
768       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
769     }
770   }
771   OLSR_FOR_ALL_GWS_END(gw);
772
773   /* there should be no more gateways */
774   assert(!avl_walk_first(&gateway_tree));
775   assert(!current_ipv4_gw);
776   assert(!current_ipv6_gw);
777
778   olsr_os_cleanup_iptunnel(server_tunnel_name());
779
780   assert(gw_handler);
781   gw_handler->cleanup();
782   gw_handler = NULL;
783
784   if (sgwTunnel4InterfaceNames) {
785     free(sgwTunnel4InterfaceNames);
786     sgwTunnel4InterfaceNames = NULL;
787   }
788   if (sgwTunnel6InterfaceNames) {
789     free(sgwTunnel6InterfaceNames);
790     sgwTunnel6InterfaceNames = NULL;
791   }
792
793   olsr_gw_list_cleanup(&gw_list_ipv6);
794   olsr_gw_list_cleanup(&gw_list_ipv4);
795   olsr_free_cookie(gw_container_entry_mem_cookie);
796   olsr_free_cookie(gateway_entry_mem_cookie);
797 }
798
799 /**
800  * Triggers the first lookup of a gateway.
801  */
802 void olsr_trigger_inetgw_startup(void) {
803   assert(gw_handler);
804   gw_handler->startup();
805 }
806
807 /**
808  * Print debug information about gateway entries
809  */
810 #ifndef NODEBUG
811 void olsr_print_gateway_entries(void) {
812   struct ipaddr_str buf;
813   struct gateway_entry *gw;
814   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
815
816   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
817   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
818       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
819
820   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
821     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
822         addrsize,
823         olsr_ip_to_string(&buf, &gw->originator),
824         gw->ipv4nat ? "" : "   ",
825         gw->ipv4 ? '4' : ' ',
826         gw->ipv4nat ? "(N)" : "",
827         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
828         gw->ipv6 ? '6' : ' ',
829         gw->uplink,
830         gw->downlink,
831         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
832   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
833 }
834 #endif /* NODEBUG */
835
836 /*
837  * Tx Path Interface
838  */
839
840 /**
841  * Apply the smart gateway modifications to an outgoing HNA
842  *
843  * @param mask pointer to netmask of the HNA
844  * @param prefixlen of the HNA
845  */
846 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
847   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
848
849   /* copy the current settings for uplink/downlink into the mask */
850   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
851   if (olsr_cnf->has_ipv4_gateway) {
852     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
853
854     if (olsr_cnf->smart_gw_uplink_nat) {
855       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
856     }
857   }
858   if (olsr_cnf->has_ipv6_gateway) {
859     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
860   }
861   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
862     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
863   }
864 }
865
866 /*
867  * SgwDynSpeed Plugin Interface
868  */
869
870 /**
871  * Setup the gateway netmask
872  */
873 void refresh_smartgw_netmask(void) {
874   uint8_t *ip;
875
876   /* clear the mask */
877   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
878
879   if (olsr_cnf->smart_gw_active) {
880     ip = (uint8_t *) &smart_gateway_netmask;
881
882     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
883     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
884     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
885
886     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
887       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
888       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
889       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
890     }
891   }
892 }
893
894 /*
895  * TC/SPF/HNA Interface
896  */
897
898 /**
899  * Checks if a HNA prefix/netmask combination is a smart gateway
900  *
901  * @param prefix
902  * @param mask
903  * @return true if is a valid smart gateway HNA, false otherwise
904  */
905 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
906   uint8_t *ptr;
907
908   if (!is_prefix_inetgw(prefix)) {
909     return false;
910   }
911
912   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
913   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
914 }
915
916 /**
917  * Update a gateway_entry based on a HNA
918  *
919  * @param originator ip of the source of the HNA
920  * @param mask netmask of the HNA
921  * @param prefixlen of the HNA
922  * @param seqno the sequence number of the HNA
923  */
924 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
925   struct gw_container_entry * new_gw_in_list;
926   uint8_t *ptr;
927   int64_t prev_path_cost = 0;
928   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
929
930   if (!gw) {
931     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
932     gw->originator = *originator;
933     gw->node.key = &gw->originator;
934
935     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
936   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
937     /* ignore older HNAs */
938     return;
939   }
940
941   /* keep new HNA seqno */
942   gw->seqno = seqno;
943
944   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
945   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
946     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
947     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
948   } else {
949     gw->uplink = 0;
950     gw->downlink = 0;
951   }
952
953   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
954   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
955   gw->ipv6 = false;
956
957   if (olsr_cnf->ip_version == AF_INET6) {
958     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
959
960     /* do not reset prefixlength for ::ffff:0:0 HNAs */
961     if (prefixlen == ipv6_internet_route.prefix_len) {
962       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
963
964       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
965           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
966         /* this is the right prefix (2000::/3), so we can copy the prefix */
967         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
968         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
969       }
970     }
971   }
972
973   /* stop cleanup timer if necessary */
974   if (gw->cleanup_timer) {
975     olsr_stop_timer(gw->cleanup_timer);
976     gw->cleanup_timer = NULL;
977   }
978
979   assert(gw_handler);
980   prev_path_cost = gw->path_cost;
981   gw->path_cost = gw_handler->getcosts(gw);
982
983   if (prev_path_cost != gw->path_cost) {
984     /* re-sort the gateway list when costs have changed and when it is an active gateway */
985     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
986     if (new_gw_in_list) {
987       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
988       assert(new_gw_in_list);
989     }
990
991     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
992     if (new_gw_in_list) {
993       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
994       assert(new_gw_in_list);
995     }
996   }
997
998   /* call update handler */
999   assert(gw_handler);
1000   gw_handler->update(gw);
1001 }
1002
1003 /**
1004  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1005  * Should only be called if prefix is a smart_gw prefix or if node is removed
1006  * from TC set.
1007  *
1008  * @param originator
1009  * @param prefixlen
1010  * @param immediate when set to true then the gateway is removed from the
1011  * gateway tree immediately, else it is removed on a delayed schedule.
1012  */
1013 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1014   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1015 }
1016
1017 /**
1018  * Delete a gateway entry .
1019  *
1020  * @param gw a gateway entry from the gateway tree
1021  * @param prefixlen
1022  * @param immediate when set to true then the gateway is removed from the
1023  * gateway tree immediately, else it is removed on a delayed schedule.
1024  */
1025 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1026   bool change = false;
1027
1028   if (!gw) {
1029     return;
1030   }
1031
1032   if (immediate && gw->cleanup_timer) {
1033     /* stop timer if we have to remove immediately */
1034     olsr_stop_timer(gw->cleanup_timer);
1035     gw->cleanup_timer = NULL;
1036   }
1037
1038   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1039     /* the gw  is not scheduled for deletion */
1040
1041     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1042       change = gw->ipv4;
1043       gw->ipv4 = false;
1044       gw->ipv4nat = false;
1045     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1046       change = gw->ipv6;
1047       gw->ipv6 = false;
1048     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1049       change = gw->ipv4;
1050       gw->ipv4 = false;
1051       gw->ipv4nat = false;
1052     }
1053
1054     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1055       struct gw_container_entry * gw_in_list;
1056
1057       /* prevent this gateway from being chosen as the new gateway */
1058       gw->ipv4 = false;
1059       gw->ipv4nat = false;
1060       gw->ipv6 = false;
1061
1062       /* handle gateway loss */
1063       assert(gw_handler);
1064       gw_handler->delete(gw);
1065
1066       /* cleanup gateway if necessary */
1067       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1068       if (gw_in_list) {
1069         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1070           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1071           current_ipv4_gw = NULL;
1072         }
1073
1074         if (gw_in_list->tunnel) {
1075           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1076           if (ifn) {
1077             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1078           }
1079           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1080           set_unused_iptunnel_name(gw_in_list->gw);
1081           gw_in_list->tunnel = NULL;
1082         }
1083
1084         gw_in_list->gw = NULL;
1085         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1086         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1087       }
1088
1089       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1090       if (gw_in_list) {
1091         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1092           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1093           current_ipv6_gw = NULL;
1094         }
1095
1096         if (gw_in_list->tunnel) {
1097           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1098           if (ifn) {
1099             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1100           }
1101           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1102           set_unused_iptunnel_name(gw_in_list->gw);
1103           gw_in_list->tunnel = NULL;
1104         }
1105
1106         gw_in_list->gw = NULL;
1107         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1108         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1109       }
1110
1111       if (!immediate) {
1112         /* remove gateway entry on a delayed schedule */
1113         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1114       } else {
1115         cleanup_gateway_handler(gw);
1116       }
1117
1118       /* when the current gateway was deleted, then immediately choose a new gateway */
1119       if (!current_ipv4_gw || !current_ipv6_gw) {
1120         assert(gw_handler);
1121         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1122       }
1123
1124     } else if (change) {
1125       assert(gw_handler);
1126       gw_handler->update(gw);
1127     }
1128   }
1129 }
1130
1131 /**
1132  * Triggers a check if the one of the gateways have been lost or has an
1133  * ETX = infinity
1134  */
1135 void olsr_trigger_gatewayloss_check(void) {
1136   bool ipv4 = false;
1137   bool ipv6 = false;
1138
1139   if (current_ipv4_gw && current_ipv4_gw->gw) {
1140     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1141     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1142   }
1143   if (current_ipv6_gw && current_ipv6_gw->gw) {
1144     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1145     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1146   }
1147
1148   if (ipv4 || ipv6) {
1149     assert(gw_handler);
1150     gw_handler->choose(ipv4, ipv6);
1151   }
1152 }
1153
1154 /*
1155  * Gateway Plugin Functions
1156  */
1157
1158 /**
1159  * Sets a new internet gateway.
1160  *
1161  * @param the chosen gateway
1162  * @param ipv4 set ipv4 gateway
1163  * @param ipv6 set ipv6 gateway
1164  * @return true if an error happened, false otherwise
1165  */
1166 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1167   struct gateway_entry *new_gw;
1168
1169   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1170   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1171   if (!ipv4 && !ipv6) {
1172     return true;
1173   }
1174
1175   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1176   if (!new_gw) {
1177     /* the originator is not in the gateway tree, we can't set it as gateway */
1178     return true;
1179   }
1180
1181   /* handle IPv4 */
1182   if (ipv4 &&
1183       new_gw->ipv4 &&
1184       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1185       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1186     /* new gw is different than the current gw */
1187
1188     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1189     if (new_gw_in_list) {
1190       /* new gw is already in the gw list */
1191       assert(new_gw_in_list->tunnel);
1192       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1193       current_ipv4_gw = new_gw_in_list;
1194     } else {
1195       /* new gw is not yet in the gw list */
1196       char name[IFNAMSIZ];
1197       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1198       struct interfaceName * interfaceName;
1199
1200       if (olsr_gw_list_full(&gw_list_ipv4)) {
1201         /* the list is full: remove the worst active gateway */
1202         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1203         assert(worst);
1204
1205         removeGatewayFromList(&gw_list_ipv4, true, worst);
1206       }
1207
1208       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1209       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1210       if (new_v4gw_tunnel) {
1211         if (interfaceName) {
1212           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1213         }
1214         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1215
1216         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1217         new_gw_in_list->gw = new_gw;
1218         new_gw_in_list->tunnel = new_v4gw_tunnel;
1219         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1220       } else {
1221         /* adding the tunnel failed, we try again in the next cycle */
1222         set_unused_iptunnel_name(new_gw);
1223         ipv4 = false;
1224       }
1225     }
1226   }
1227
1228   /* handle IPv6 */
1229   if (ipv6 &&
1230       new_gw->ipv6 &&
1231       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1232     /* new gw is different than the current gw */
1233
1234         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1235     if (new_gw_in_list) {
1236       /* new gw is already in the gw list */
1237       assert(new_gw_in_list->tunnel);
1238       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1239       current_ipv6_gw = new_gw_in_list;
1240     } else {
1241       /* new gw is not yet in the gw list */
1242       char name[IFNAMSIZ];
1243       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1244       struct interfaceName * interfaceName;
1245
1246       if (olsr_gw_list_full(&gw_list_ipv6)) {
1247         /* the list is full: remove the worst active gateway */
1248         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1249         assert(worst);
1250
1251         removeGatewayFromList(&gw_list_ipv6, false, worst);
1252       }
1253
1254       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1255       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1256       if (new_v6gw_tunnel) {
1257         if (interfaceName) {
1258           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1259         }
1260         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1261
1262         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1263         new_gw_in_list->gw = new_gw;
1264         new_gw_in_list->tunnel = new_v6gw_tunnel;
1265         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1266       } else {
1267         /* adding the tunnel failed, we try again in the next cycle */
1268         set_unused_iptunnel_name(new_gw);
1269         ipv6 = false;
1270       }
1271     }
1272   }
1273
1274   return !ipv4 && !ipv6;
1275 }
1276
1277 /**
1278  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1279  * gateway is returned
1280  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1281  * NULL if not set.
1282  */
1283 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1284         if (ipv6) {
1285                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1286         }
1287
1288         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1289 }
1290
1291 #endif /* __linux__ */