sgw: add reportNewGateway function
[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 struct BestOverallLink {
87   bool valid;
88   bool isOlsr;
89   union {
90     struct sgw_egress_if * egress;
91     struct gateway_entry * olsr;
92   } link;
93   int olsrTunnelIfIndex;
94 };
95
96 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
97 static struct sgw_egress_if * bestEgressLink = NULL;
98
99 static struct BestOverallLink bestOverallLinkPrevious;
100 static struct BestOverallLink bestOverallLink;
101
102 /*
103  * Forward Declarations
104  */
105
106 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
107
108 /*
109  * Helper Functions
110  */
111
112 /**
113  * @return the gateway 'server' tunnel name to use
114  */
115 static inline const char * server_tunnel_name(void) {
116   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
117 }
118
119 /**
120  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
121  * pointer.
122  *
123  * @param mask the netmask of the HNA (in the form of an IP address)
124  * @param prefixlen the prefix length
125  * @return a pointer to the HNA
126  */
127 static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
128   return (((uint8_t *)mask) + ((prefixlen+7)/8));
129 }
130
131 /**
132  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
133  * to an uplink/downlink speed value
134  *
135  * @param value the encoded 1 byte transport value
136  * @return the uplink/downlink speed value (in kbit/s)
137  */
138 static uint32_t deserialize_gw_speed(uint8_t value) {
139   uint32_t speed;
140   uint32_t exp;
141
142   if (!value) {
143     /* 0 and 1 alias onto 0 during serialisation. We take 0 here to mean 0 and
144      * not 1 (since a bandwidth of 1 is no bandwidth at all really) */
145     return 0;
146   }
147
148   if (value == UINT8_MAX) {
149     /* maximum value: also return maximum value */
150     return 320000000;
151   }
152
153   speed = (value >> 3) + 1;
154   exp = value & 7;
155
156   while (exp-- > 0) {
157     speed *= 10;
158   }
159   return speed;
160 }
161
162 /**
163  * Convert an uplink/downlink speed value into an encoded 1 byte transport
164  * value (5 bits mantissa, 3 bits exponent)
165  *
166  * @param speed the uplink/downlink speed value (in kbit/s)
167  * @return value the encoded 1 byte transport value
168  */
169 static uint8_t serialize_gw_speed(uint32_t speed) {
170   uint8_t exp = 0;
171
172   if (speed == 0) {
173     return 0;
174   }
175
176   if (speed > 320000000) {
177     return UINT8_MAX;
178   }
179
180   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
181     speed /= 10;
182     exp++;
183   }
184   return ((speed - 1) << 3) | exp;
185 }
186
187 /**
188  * Find an interfaceName struct corresponding to a certain gateway
189  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
190  *
191  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
192  * @return a pointer to the struct, or NULL when not found
193  */
194 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
195   struct interfaceName * sgwTunnelInterfaceNames;
196   uint8_t i = 0;
197
198   if (!multi_gateway_mode()) {
199     return NULL;
200   }
201
202   assert(sgwTunnel4InterfaceNames);
203   assert(sgwTunnel6InterfaceNames);
204
205   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
206   while (i < olsr_cnf->smart_gw_use_count) {
207     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
208     if (ifn->gw == gw) {
209       return ifn;
210     }
211     i++;
212   }
213
214   return NULL;
215 }
216
217 /**
218  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
219  *
220  * @param gw pointer to the gateway
221  * @param name pointer to output buffer (length IFNAMSIZ)
222  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
223  */
224 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
225   static uint32_t counter = 0;
226
227   assert(gw);
228   assert(name);
229   assert(interfaceName);
230
231   memset(name, 0, IFNAMSIZ);
232
233   if (multi_gateway_mode()) {
234     struct interfaceName * ifn = find_interfaceName(NULL);
235
236     if (ifn) {
237       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
238       *interfaceName = ifn;
239       ifn->gw = gw;
240       return;
241     }
242
243     /* do not return, fall-through to classic naming as fallback */
244   }
245
246   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
247   *interfaceName = NULL;
248 }
249
250 /**
251  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
252  *
253  * @param gw pointer to the gateway
254  */
255 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
256   struct interfaceName * ifn;
257
258   if (!multi_gateway_mode()) {
259     return;
260   }
261
262   assert(gw);
263
264   ifn = find_interfaceName(gw);
265   if (ifn) {
266     ifn->gw = NULL;
267     return;
268   }
269 }
270
271 /**
272  * Run the multi-gateway script/
273  *
274  * @param mode the mode (see SCRIPT_MODE_* defines)
275  * @param addMode true to add policy routing, false to remove it
276  * @param ifname the interface name (optional)
277  * @param tableNr the routing table number (optional)
278  * @param ruleNr the IP rule number/priority (optional)
279  * @param bypassRuleNr the bypass IP rule number/priority (optional)
280  * @return true when successful
281  */
282 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
283   struct autobuf buf;
284   int r;
285
286   assert(!strcmp(mode, SCRIPT_MODE_GENERIC) //
287       || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
288       || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
289       || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
290       || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
291       );
292
293   assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
294       || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
295
296   assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
297       || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
298
299   assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
300       || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
301
302   assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
303       || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
304
305   assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
306       || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
307
308   abuf_init(&buf, 1024);
309
310   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
311
312   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
313
314   abuf_appendf(&buf, " \"%s\"", mode);
315
316   abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
317
318   if (ifName) {
319     abuf_appendf(&buf, " \"%s\"", ifName);
320   }
321
322   if (tableNr) {
323     abuf_appendf(&buf, " \"%u\"", tableNr);
324   }
325
326   if (ruleNr) {
327     abuf_appendf(&buf, " \"%u\"", ruleNr);
328   }
329
330   if (bypassRuleNr) {
331     abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
332   }
333
334   r = system(buf.buf);
335
336   abuf_free(&buf);
337
338   return (r == 0);
339 }
340
341 /**
342  * Setup generic multi-gateway iptables and ip rules
343  *
344  * @param add true to add policy routing, false to remove it
345  * @return true when successful
346  */
347 static bool multiGwRulesGeneric(bool add) {
348   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
349 }
350
351 /**
352  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
353  *
354  * @param add true to add policy routing, false to remove it
355  * @return true when successful
356  */
357 static bool multiGwRulesOlsrInterfaces(bool add) {
358   bool ok = true;
359   struct olsr_if * ifn;
360   unsigned int i = 0;
361
362   for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
363     if (!multiGwRunScript( //
364         SCRIPT_MODE_OLSRIF,//
365         add, //
366         ifn->name, //
367         0, //
368         0, //
369         olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
370             )) {
371       ok = false;
372       if (add) {
373         return ok;
374       }
375     }
376   }
377
378   return ok;
379 }
380
381 /**
382  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
383  *
384  * @param add true to add policy routing, false to remove it
385  * @return true when successful
386  */
387 static bool multiGwRulesSgwServerTunnel(bool add) {
388   return multiGwRunScript( //
389       SCRIPT_MODE_SGWSRVTUN,//
390       add, //
391       server_tunnel_name(), //
392       olsr_cnf->smart_gw_offset_tables, //
393       olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
394       0 //
395       );
396 }
397
398 /**
399  * Setup multi-gateway iptables and ip rules for all egress interfaces.
400  *
401  * @param add true to add policy routing, false to remove it
402  * @return true when successful
403  */
404 static bool multiGwRulesEgressInterfaces(bool add) {
405   bool ok = true;
406   unsigned int i = 0;
407
408   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
409   while (egress_if) {
410     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
411       ok = false;
412       if (add) {
413         return ok;
414       }
415     }
416
417     egress_if = egress_if->next;
418   }
419
420   return ok;
421 }
422
423 /**
424  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
425  *
426  * @param add true to add policy routing, false to remove it
427  * @return true when successful
428  */
429 static bool multiGwRulesSgwTunnels(bool add) {
430   bool ok = true;
431   unsigned int i = 0;
432
433   while (i < olsr_cnf->smart_gw_use_count) {
434     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
435     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
436       ok = false;
437       if (add) {
438         return ok;
439       }
440     }
441
442     i++;
443   }
444
445   return ok;
446 }
447
448 /**
449  * Process interface up/down events for non-olsr interfaces, which are egress
450  * interfaces
451  *
452  * @param if_index the index of the interface
453  * @param flag the up/down event
454  */
455 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
456   switch (flag) {
457     case IFCHG_IF_ADD: {
458       char ifname[IF_NAMESIZE];
459       struct sgw_egress_if * egress_if;
460
461       /*
462        * we need to get the name of the interface first because the interface
463        * might be hot-plugged _after_ olsrd has started
464        */
465       if (!if_indextoname(if_index, ifname)) {
466         /* not a known OS interface */
467         return;
468       }
469
470       egress_if = findEgressInterface(ifname);
471       if (!egress_if) {
472         /* not a known egress interface */
473         return;
474       }
475
476       egress_if->if_index = if_index;
477
478       if (egress_if->upCurrent) {
479         /* interface is already up: no change */
480         return;
481       }
482
483       egress_if->upPrevious = egress_if->upCurrent;
484       egress_if->upCurrent = true;
485       egress_if->upChanged = true;
486
487       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
488     }
489       break;
490
491     case IFCHG_IF_REMOVE: {
492       /*
493        * we need to find the egress interface by if_index because we might
494        * be too late; the kernel could already have removed the interface
495        * in which case we'd get a NULL ifname here if we'd try to call
496        * if_indextoname
497        */
498       struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
499       if (!egress_if) {
500         /* not a known egress interface */
501         return;
502       }
503
504       if (!egress_if->upCurrent) {
505         /* interface is already down: no change */
506         return;
507       }
508
509       egress_if->upPrevious = egress_if->upCurrent;
510       egress_if->upCurrent = false;
511       egress_if->upChanged = true;
512
513       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
514     }
515       break;
516
517     case IFCHG_IF_UPDATE:
518     default:
519       return;
520   }
521
522   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
523 }
524
525 /*
526  * Callback Functions
527  */
528
529 /**
530  * Callback for tunnel interface monitoring which will set the route into the tunnel
531  * when the interface comes up again.
532  *
533  * @param if_index the interface index
534  * @param ifh the interface (NULL when not an olsr interface)
535  * @param flag interface change flags
536  */
537 static void smartgw_tunnel_monitor(int if_index, struct interface *ifh, enum olsr_ifchg_flag flag) {
538   if (!ifh && multi_gateway_mode()) {
539     /* non-olsr interface in multi-sgw mode */
540     doEgressInterface(if_index, flag);
541   }
542
543   return;
544 }
545
546 /**
547  * Timer callback to remove and cleanup a gateway entry
548  *
549  * @param ptr
550  */
551 static void cleanup_gateway_handler(void *ptr) {
552   struct gateway_entry *gw = ptr;
553
554   if (gw->ipv4 || gw->ipv6) {
555     /* do not clean it up when it is in use */
556     return;
557   }
558
559   /* remove gateway entry */
560   avl_delete(&gateway_tree, &gw->node);
561   olsr_cookie_free(gateway_entry_mem_cookie, gw);
562 }
563
564 /**
565  * Remove a gateway from a gateway list.
566  *
567  * @param gw_list a pointer to the gateway list
568  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
569  * @param gw a pointer to the gateway to remove from the list
570  */
571 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
572   if (gw->tunnel) {
573     struct interfaceName * ifn = find_interfaceName(gw->gw);
574     if (ifn) {
575       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
576     }
577     olsr_os_del_ipip_tunnel(gw->tunnel);
578     set_unused_iptunnel_name(gw->gw);
579     gw->tunnel = NULL;
580   }
581   gw->gw = NULL;
582   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
583 }
584
585 /**
586  * Remove expensive gateways from the gateway list.
587  * It uses the smart_gw_takedown_percentage configuration parameter
588  *
589  * @param gw_list a pointer to the gateway list
590  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
591  * @param current_gw the current gateway
592  */
593 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
594   int64_t current_gw_cost_boundary;
595
596   /*
597    * exit immediately when takedown is disabled, there is no current gateway, or
598    * when there is only a single gateway
599    */
600   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || (current_gw == NULL ) || (gw_list->count <= 1)) {
601     return;
602   }
603
604   /* get the cost boundary */
605   current_gw_cost_boundary = current_gw->gw->path_cost;
606   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
607     if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
608       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
609     } else {
610       /* perform scaling because otherwise the percentage calculation can overflow */
611       current_gw_cost_boundary = (((current_gw_cost_boundary      ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
612     }
613   }
614
615   /* loop while we still have gateways */
616   while (gw_list->count > 1) {
617     /* get the worst gateway */
618     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
619
620     /* exit when it's the current gateway */
621     if (worst_gw == current_gw) {
622       return;
623     }
624
625     /*
626      * exit when it (and further ones; the list is sorted on costs) has lower
627      * costs than the boundary costs
628      */
629     if (worst_gw->gw->path_cost < current_gw_cost_boundary) {
630       return;
631     }
632
633     /* it's too expensive: take it down */
634     removeGatewayFromList(gw_list, ipv4, worst_gw);
635   }
636 }
637
638 /**
639  * Timer callback for proactive gateway takedown
640  *
641  * @param unused unused
642  */
643 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
644   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
645   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
646 }
647
648 /*
649  * Main Interface
650  */
651
652 /**
653  * Initialize gateway system
654  */
655 int olsr_init_gateways(void) {
656   int retries = 5;
657
658   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
659   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
660
661   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
662   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
663
664   avl_init(&gateway_tree, avl_comp_default);
665
666   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
667   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
668
669   sgwTunnel4InterfaceNames = NULL;
670   sgwTunnel6InterfaceNames = NULL;
671   memset(&bestOverallLinkPrevious, 0, sizeof(bestOverallLinkPrevious));
672   memset(&bestOverallLink, 0, sizeof(bestOverallLink));
673
674   if (multi_gateway_mode()) {
675     uint8_t i;
676     struct sgw_egress_if * egressif;
677     unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
678
679     /* setup the egress interface name/mark pairs */
680     i = 0;
681     egressif = olsr_cnf->smart_gw_egress_interfaces;
682     while (egressif) {
683       egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
684       egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
685       egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
686
687       egressif = egressif->next;
688       i++;
689     }
690     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
691
692     /* setup the SGW tunnel name/mark pairs */
693     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
694     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
695     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
696       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
697       uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
698       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;
699
700       ifn->gw = NULL;
701       ifn->tableNr = tableNr;
702       ifn->ruleNr = ruleNr;
703       ifn->bypassRuleNr = 0;
704       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
705
706       ifn = &sgwTunnel6InterfaceNames[i];
707       ifn->gw = NULL;
708       ifn->tableNr = tableNr;
709       ifn->ruleNr = ruleNr;
710       ifn->bypassRuleNr = 0;
711       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
712     }
713   }
714
715   current_ipv4_gw = NULL;
716   current_ipv6_gw = NULL;
717
718   gw_handler = NULL;
719
720   refresh_smartgw_netmask();
721
722   /* initialize default gateway handler */
723   gw_handler = &gw_def_handler;
724   gw_handler->init();
725
726
727   /*
728    * There appears to be a kernel bug in some kernels (at least in the 3.0
729    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
730    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
731    * a few times before giving up
732    */
733   while (retries-- > 0) {
734     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
735       retries = 5;
736       break;
737     }
738
739     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
740   }
741   if (retries <= 0) {
742     return 1;
743   }
744
745   return 0;
746 }
747
748 /**
749  * Startup gateway system
750  */
751 int olsr_startup_gateways(void) {
752   bool ok = true;
753
754   if (!multi_gateway_mode()) {
755     olsr_add_ifchange_handler(smartgw_tunnel_monitor);
756     return 0;
757   }
758
759   /* Initialise the egress interfaces */
760   {
761     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
762     while (egress_if) {
763       egress_if->if_index = if_nametoindex(egress_if->name);
764
765       egress_if->upPrevious = egress_if->upCurrent = olsr_if_isup(egress_if->name);
766       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
767
768       egressBwClear(&egress_if->bwPrevious, egress_if->upPrevious);
769       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
770       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
771       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
772       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
773       egress_if->bwChanged = egressBwChanged(egress_if);
774
775       egress_if->inEgressFile = false;
776
777       egress_if = egress_if->next;
778     }
779   }
780
781   ok = ok && multiGwRulesGeneric(true);
782   ok = ok && multiGwRulesSgwServerTunnel(true);
783   ok = ok && multiGwRulesOlsrInterfaces(true);
784   ok = ok && multiGwRulesEgressInterfaces(true);
785   ok = ok && multiGwRulesSgwTunnels(true);
786   if (!ok) {
787     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
788     olsr_shutdown_gateways();
789     return 1;
790   }
791
792   startEgressFile();
793   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
794
795   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
796
797   /* Check egress interfaces up status to compensate for a race: the interfaces
798    * can change status between initialising their data structures and
799    * registering the tunnel monitor */
800   {
801     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
802     while (egress_if) {
803       bool upCurrent = olsr_if_isup(egress_if->name);
804
805       if (upCurrent != egress_if->upCurrent) {
806         int index = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
807         enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
808         smartgw_tunnel_monitor(index, NULL, flag);
809       }
810
811       egress_if = egress_if->next;
812     }
813   }
814
815   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
816     /* start gateway takedown timer */
817     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
818   }
819
820   return 0;
821 }
822
823 /**
824  * Shutdown gateway tunnel system
825  */
826 void olsr_shutdown_gateways(void) {
827   if (!multi_gateway_mode()) {
828     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
829     return;
830   }
831
832   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
833     /* stop gateway takedown timer */
834     olsr_stop_timer(gw_takedown_timer);
835     gw_takedown_timer = NULL;
836   }
837
838   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
839
840   stopEgressFile();
841   {
842     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
843     while (egress_if) {
844       egress_if->upPrevious = egress_if->upCurrent;
845       egress_if->upCurrent = false;
846       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
847
848       egress_if->bwPrevious = egress_if->bwCurrent;
849       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
850       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
851       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
852       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
853       egress_if->bwChanged = egressBwChanged(egress_if);
854
855       egress_if->inEgressFile = false;
856
857       egress_if = egress_if->next;
858     }
859   }
860   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
861
862   (void)multiGwRulesSgwTunnels(false);
863   (void)multiGwRulesEgressInterfaces(false);
864   (void)multiGwRulesOlsrInterfaces(false);
865   (void)multiGwRulesSgwServerTunnel(false);
866   (void)multiGwRulesGeneric(false);
867 }
868
869 /**
870  * Cleanup gateway tunnel system
871  */
872 void olsr_cleanup_gateways(void) {
873   struct gateway_entry * tree_gw;
874   struct gw_container_entry * gw;
875
876   /* remove all gateways in the gateway tree that are not the active gateway */
877   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
878     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
879       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
880     }
881   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
882
883   /* remove all active IPv4 gateways (should be at most 1 now) */
884   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
885     if (gw && gw->gw) {
886       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
887     }
888   }
889   OLSR_FOR_ALL_GWS_END(gw);
890
891   /* remove all active IPv6 gateways (should be at most 1 now) */
892   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
893     if (gw && gw->gw) {
894       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
895     }
896   }
897   OLSR_FOR_ALL_GWS_END(gw);
898
899   /* there should be no more gateways */
900   assert(!avl_walk_first(&gateway_tree));
901   assert(!current_ipv4_gw);
902   assert(!current_ipv6_gw);
903
904   olsr_os_cleanup_iptunnel(server_tunnel_name());
905
906   assert(gw_handler);
907   gw_handler->cleanup();
908   gw_handler = NULL;
909
910   if (sgwTunnel4InterfaceNames) {
911     free(sgwTunnel4InterfaceNames);
912     sgwTunnel4InterfaceNames = NULL;
913   }
914   if (sgwTunnel6InterfaceNames) {
915     free(sgwTunnel6InterfaceNames);
916     sgwTunnel6InterfaceNames = NULL;
917   }
918
919   olsr_gw_list_cleanup(&gw_list_ipv6);
920   olsr_gw_list_cleanup(&gw_list_ipv4);
921   olsr_free_cookie(gw_container_entry_mem_cookie);
922   olsr_free_cookie(gateway_entry_mem_cookie);
923 }
924
925 /**
926  * Triggers the first lookup of a gateway.
927  */
928 void olsr_trigger_inetgw_startup(void) {
929   assert(gw_handler);
930   gw_handler->startup();
931 }
932
933 /**
934  * Print debug information about gateway entries
935  */
936 #ifndef NODEBUG
937 void olsr_print_gateway_entries(void) {
938   struct ipaddr_str buf;
939   struct gateway_entry *gw;
940   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
941
942   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
943   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
944       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
945
946   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
947     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
948         addrsize,
949         olsr_ip_to_string(&buf, &gw->originator),
950         gw->ipv4nat ? "" : "   ",
951         gw->ipv4 ? '4' : ' ',
952         gw->ipv4nat ? "(N)" : "",
953         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
954         gw->ipv6 ? '6' : ' ',
955         gw->uplink,
956         gw->downlink,
957         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
958   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
959 }
960 #endif /* NODEBUG */
961
962 /*
963  * Tx Path Interface
964  */
965
966 /**
967  * Apply the smart gateway modifications to an outgoing HNA
968  *
969  * @param mask pointer to netmask of the HNA
970  * @param prefixlen of the HNA
971  */
972 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
973   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
974
975   /* copy the current settings for uplink/downlink into the mask */
976   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
977   if (olsr_cnf->has_ipv4_gateway) {
978     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
979
980     if (olsr_cnf->smart_gw_uplink_nat) {
981       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
982     }
983   }
984   if (olsr_cnf->has_ipv6_gateway) {
985     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
986   }
987   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
988     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
989   }
990 }
991
992 /*
993  * SgwDynSpeed Plugin Interface
994  */
995
996 /**
997  * Setup the gateway netmask
998  */
999 void refresh_smartgw_netmask(void) {
1000   uint8_t *ip;
1001
1002   /* clear the mask */
1003   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1004
1005   if (olsr_cnf->smart_gw_active) {
1006     ip = (uint8_t *) &smart_gateway_netmask;
1007
1008     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1009     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1010     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1011
1012     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1013       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1014       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1015       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1016     }
1017   }
1018 }
1019
1020 /*
1021  * TC/SPF/HNA Interface
1022  */
1023
1024 /**
1025  * Checks if a HNA prefix/netmask combination is a smart gateway
1026  *
1027  * @param prefix
1028  * @param mask
1029  * @return true if is a valid smart gateway HNA, false otherwise
1030  */
1031 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1032   uint8_t *ptr;
1033
1034   if (!is_prefix_inetgw(prefix)) {
1035     return false;
1036   }
1037
1038   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1039   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1040 }
1041
1042 /**
1043  * Update a gateway_entry based on a HNA
1044  *
1045  * @param originator ip of the source of the HNA
1046  * @param mask netmask of the HNA
1047  * @param prefixlen of the HNA
1048  * @param seqno the sequence number of the HNA
1049  */
1050 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
1051   struct gw_container_entry * new_gw_in_list;
1052   uint8_t *ptr;
1053   int64_t prev_path_cost = 0;
1054   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1055
1056   if (!gw) {
1057     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1058     gw->originator = *originator;
1059     gw->node.key = &gw->originator;
1060
1061     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1062   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1063     /* ignore older HNAs */
1064     return;
1065   }
1066
1067   /* keep new HNA seqno */
1068   gw->seqno = seqno;
1069
1070   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1071   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1072     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1073     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1074   } else {
1075     gw->uplink = 0;
1076     gw->downlink = 0;
1077   }
1078
1079   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1080   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1081   gw->ipv6 = false;
1082
1083   if (olsr_cnf->ip_version == AF_INET6) {
1084     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1085
1086     /* do not reset prefixlength for ::ffff:0:0 HNAs */
1087     if (prefixlen == ipv6_internet_route.prefix_len) {
1088       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1089
1090       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1091           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1092         /* this is the right prefix (2000::/3), so we can copy the prefix */
1093         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1094         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1095       }
1096     }
1097   }
1098
1099   /* stop cleanup timer if necessary */
1100   if (gw->cleanup_timer) {
1101     olsr_stop_timer(gw->cleanup_timer);
1102     gw->cleanup_timer = NULL;
1103   }
1104
1105   assert(gw_handler);
1106   prev_path_cost = gw->path_cost;
1107   gw->path_cost = gw_handler->getcosts(gw);
1108
1109   if (prev_path_cost != gw->path_cost) {
1110     /* re-sort the gateway list when costs have changed and when it is an active gateway */
1111     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1112     if (new_gw_in_list) {
1113       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1114       assert(new_gw_in_list);
1115     }
1116
1117     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1118     if (new_gw_in_list) {
1119       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1120       assert(new_gw_in_list);
1121     }
1122
1123     if (multi_gateway_mode() && //
1124         ((!gw->ipv6 && current_ipv4_gw && current_ipv4_gw->gw == gw) || //
1125          (gw->ipv6 && current_ipv6_gw && current_ipv6_gw->gw == gw)) //
1126         ) {
1127       /* the active gw has changed its costs: re-evaluate egress routes */
1128       doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1129     }
1130   }
1131
1132   /* call update handler */
1133   assert(gw_handler);
1134   gw_handler->update(gw);
1135 }
1136
1137 /**
1138  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1139  * Should only be called if prefix is a smart_gw prefix or if node is removed
1140  * from TC set.
1141  *
1142  * @param originator
1143  * @param prefixlen
1144  * @param immediate when set to true then the gateway is removed from the
1145  * gateway tree immediately, else it is removed on a delayed schedule.
1146  */
1147 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1148   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1149 }
1150
1151 /**
1152  * Delete a gateway entry .
1153  *
1154  * @param gw a gateway entry from the gateway tree
1155  * @param prefixlen
1156  * @param immediate when set to true then the gateway is removed from the
1157  * gateway tree immediately, else it is removed on a delayed schedule.
1158  */
1159 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1160   bool change = false;
1161
1162   if (!gw) {
1163     return;
1164   }
1165
1166   if (immediate && gw->cleanup_timer) {
1167     /* stop timer if we have to remove immediately */
1168     olsr_stop_timer(gw->cleanup_timer);
1169     gw->cleanup_timer = NULL;
1170   }
1171
1172   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1173     /* the gw  is not scheduled for deletion */
1174
1175     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1176       change = gw->ipv4;
1177       gw->ipv4 = false;
1178       gw->ipv4nat = false;
1179     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1180       change = gw->ipv6;
1181       gw->ipv6 = false;
1182     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1183       change = gw->ipv4;
1184       gw->ipv4 = false;
1185       gw->ipv4nat = false;
1186     }
1187
1188     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1189       struct gw_container_entry * gw_in_list;
1190
1191       /* prevent this gateway from being chosen as the new gateway */
1192       gw->ipv4 = false;
1193       gw->ipv4nat = false;
1194       gw->ipv6 = false;
1195
1196       /* handle gateway loss */
1197       assert(gw_handler);
1198       gw_handler->delete(gw);
1199
1200       /* cleanup gateway if necessary */
1201       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1202       if (gw_in_list) {
1203         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1204           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1205           current_ipv4_gw = NULL;
1206         }
1207
1208         if (gw_in_list->tunnel) {
1209           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1210           if (ifn) {
1211             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1212           }
1213           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1214           set_unused_iptunnel_name(gw_in_list->gw);
1215           gw_in_list->tunnel = NULL;
1216         }
1217
1218         gw_in_list->gw = NULL;
1219         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1220         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1221       }
1222
1223       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1224       if (gw_in_list) {
1225         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1226           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1227           current_ipv6_gw = NULL;
1228         }
1229
1230         if (gw_in_list->tunnel) {
1231           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1232           if (ifn) {
1233             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1234           }
1235           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1236           set_unused_iptunnel_name(gw_in_list->gw);
1237           gw_in_list->tunnel = NULL;
1238         }
1239
1240         gw_in_list->gw = NULL;
1241         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1242         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1243       }
1244
1245       if (!immediate) {
1246         /* remove gateway entry on a delayed schedule */
1247         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1248       } else {
1249         cleanup_gateway_handler(gw);
1250       }
1251
1252       /* when the current gateway was deleted, then immediately choose a new gateway */
1253       if (!current_ipv4_gw || !current_ipv6_gw) {
1254         assert(gw_handler);
1255         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1256       }
1257
1258     } else if (change) {
1259       assert(gw_handler);
1260       gw_handler->update(gw);
1261     }
1262   }
1263 }
1264
1265 /**
1266  * Triggers a check if the one of the gateways have been lost or has an
1267  * ETX = infinity
1268  */
1269 void olsr_trigger_gatewayloss_check(void) {
1270   bool ipv4 = false;
1271   bool ipv6 = false;
1272
1273   if (current_ipv4_gw && current_ipv4_gw->gw) {
1274     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1275     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1276   }
1277   if (current_ipv6_gw && current_ipv6_gw->gw) {
1278     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1279     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
1280   }
1281
1282   if (ipv4 || ipv6) {
1283     assert(gw_handler);
1284     gw_handler->choose(ipv4, ipv6);
1285   }
1286 }
1287
1288 /*
1289  * Gateway Plugin Functions
1290  */
1291
1292 /**
1293  * Sets a new internet gateway.
1294  *
1295  * @param the chosen gateway
1296  * @param ipv4 set ipv4 gateway
1297  * @param ipv6 set ipv6 gateway
1298  * @return true if an error happened, false otherwise
1299  */
1300 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1301   struct gateway_entry *new_gw;
1302
1303   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1304   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1305   if (!ipv4 && !ipv6) {
1306     return true;
1307   }
1308
1309   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1310   if (!new_gw) {
1311     /* the originator is not in the gateway tree, we can't set it as gateway */
1312     return true;
1313   }
1314
1315   /* handle IPv4 */
1316   if (ipv4 &&
1317       new_gw->ipv4 &&
1318       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1319       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1320     /* new gw is different than the current gw */
1321
1322     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1323     if (new_gw_in_list) {
1324       /* new gw is already in the gw list */
1325       assert(new_gw_in_list->tunnel);
1326       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1327       current_ipv4_gw = new_gw_in_list;
1328
1329       if (multi_gateway_mode()) {
1330         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1331       }
1332     } else {
1333       /* new gw is not yet in the gw list */
1334       char name[IFNAMSIZ];
1335       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1336       struct interfaceName * interfaceName;
1337
1338       if (olsr_gw_list_full(&gw_list_ipv4)) {
1339         /* the list is full: remove the worst active gateway */
1340         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1341         assert(worst);
1342
1343         removeGatewayFromList(&gw_list_ipv4, true, worst);
1344       }
1345
1346       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1347       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1348       if (new_v4gw_tunnel) {
1349         if (interfaceName) {
1350           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1351         }
1352         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1353
1354         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1355         new_gw_in_list->gw = new_gw;
1356         new_gw_in_list->tunnel = new_v4gw_tunnel;
1357         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1358
1359         if (multi_gateway_mode()) {
1360           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1361         }
1362       } else {
1363         /* adding the tunnel failed, we try again in the next cycle */
1364         set_unused_iptunnel_name(new_gw);
1365         ipv4 = false;
1366       }
1367     }
1368   }
1369
1370   /* handle IPv6 */
1371   if (ipv6 &&
1372       new_gw->ipv6 &&
1373       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1374     /* new gw is different than the current gw */
1375
1376         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1377     if (new_gw_in_list) {
1378       /* new gw is already in the gw list */
1379       assert(new_gw_in_list->tunnel);
1380       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1381       current_ipv6_gw = new_gw_in_list;
1382
1383       if (multi_gateway_mode()) {
1384         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1385       }
1386     } else {
1387       /* new gw is not yet in the gw list */
1388       char name[IFNAMSIZ];
1389       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1390       struct interfaceName * interfaceName;
1391
1392       if (olsr_gw_list_full(&gw_list_ipv6)) {
1393         /* the list is full: remove the worst active gateway */
1394         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1395         assert(worst);
1396
1397         removeGatewayFromList(&gw_list_ipv6, false, worst);
1398       }
1399
1400       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1401       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1402       if (new_v6gw_tunnel) {
1403         if (interfaceName) {
1404           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1405         }
1406         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1407
1408         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1409         new_gw_in_list->gw = new_gw;
1410         new_gw_in_list->tunnel = new_v6gw_tunnel;
1411         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1412
1413         if (multi_gateway_mode()) {
1414           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1415         }
1416       } else {
1417         /* adding the tunnel failed, we try again in the next cycle */
1418         set_unused_iptunnel_name(new_gw);
1419         ipv6 = false;
1420       }
1421     }
1422   }
1423
1424   return !ipv4 && !ipv6;
1425 }
1426
1427 /**
1428  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1429  * gateway is returned
1430  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1431  * NULL if not set.
1432  */
1433 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1434         if (ipv6) {
1435                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1436         }
1437
1438         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1439 }
1440
1441 /*
1442  * Process Egress Changes
1443  */
1444
1445 #define MSGW_ROUTE_ADD_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1446 #define MSGW_ROUTE_ADD_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1447 #define MSGW_ROUTE_DEL_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1448 #define MSGW_ROUTE_DEL_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1449 #define MSGW_ROUTE_FORCED(phase)        ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1450
1451 /**
1452  * Determine best egress link.
1453  * The list of egress interface is ordered on priority (the declaration order),
1454  * so the function will - for multiple egress links with the same costs - set the
1455  * best egress interface to the first declared one of those.
1456  * When there is no best egress interface (that is up) then the function will
1457  * set the best egress interface to NULL.
1458  *
1459  * @param phase the phase of the change (startup/runtime/shutdown)
1460  * @return true when the best egress link changed or when any of its relevant
1461  * parameters has changed
1462  */
1463 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1464   struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1465
1466   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1467     bestEgress = NULL;
1468   } else {
1469     struct sgw_egress_if * egress_if = bestEgress;
1470     if (egress_if) {
1471       egress_if = egress_if->next;
1472     }
1473     while (egress_if) {
1474       if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs)) {
1475         bestEgress = egress_if;
1476       }
1477
1478       egress_if = egress_if->next;
1479     }
1480
1481     if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1482       bestEgress = NULL;
1483     }
1484   }
1485
1486   bestEgressLinkPrevious = bestEgressLink;
1487   bestEgressLink = bestEgress;
1488
1489   return ((bestEgressLinkPrevious != bestEgressLink) || //
1490       (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged)));
1491 }
1492
1493 /**
1494  * Determine best overall link (choose egress interface over olsrd).
1495  *
1496  * When there is no best overall link, the best overall link will be set to a
1497  * NULL egress interface.
1498  *
1499  * @param phase the phase of the change (startup/runtime/shutdown)
1500  * @return true when the best egress link changed or when any of its relevant
1501  * parameters has changed
1502  */
1503 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1504   struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1505   struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1506
1507   int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1508   int64_t olsrCosts = !olsrGw ? INT64_MAX : olsrGw->path_cost;
1509   int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1510
1511   bestOverallLinkPrevious = bestOverallLink;
1512   if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1513     bestOverallLink.valid = false;
1514     bestOverallLink.isOlsr = false;
1515     bestOverallLink.link.egress = NULL;
1516     bestOverallLink.olsrTunnelIfIndex = 0;
1517   } else if (egressCosts <= olsrCosts) {
1518     bestOverallLink.valid = bestEgressLink;
1519     bestOverallLink.isOlsr = false;
1520     bestOverallLink.link.egress = bestEgressLink;
1521     bestOverallLink.olsrTunnelIfIndex = 0;
1522   } else {
1523     struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1524
1525     bestOverallLink.valid = olsrGw;
1526     bestOverallLink.isOlsr = true;
1527     bestOverallLink.link.olsr = olsrGw;
1528     bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1529   }
1530
1531   return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1532 }
1533
1534 /*
1535  * Multi-Smart-Gateway Status Overview
1536  */
1537
1538 #define IPNONE    ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0"     : "::")
1539 #define MASKNONE  ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0"   : "::/0")
1540 #define IPLOCAL   ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1"   : "::1")
1541 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
1542
1543 /**
1544  * Print a timestamp to a file
1545  *
1546  * @param f the file
1547  */
1548 static void printDate(FILE * f) {
1549   time_t timer;
1550   struct tm* tm_info;
1551   char buffer[64];
1552
1553   time(&timer);
1554   tm_info = localtime(&timer);
1555
1556   strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
1557   fprintf(f, "%s", buffer);
1558 }
1559
1560 /**
1561  * Write multi-smart-gateway status file
1562  *
1563  * <pre>
1564  * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
1565  *
1566  * #Originator Prefix      Uplink Downlink PathCost   Type   Interface Gateway     Cost
1567  *  127.0.0.1  127.0.0.0/8 0      0        4294967295 egress ppp0      0.0.0.0     9223372036854775807
1568  *  127.0.0.1  127.0.0.0/8 0      0        4294967295 egress eth1      192.168.0.1 9223372036854775807
1569  * *0.0.0.0    0.0.0.0/0   290    1500     1024       olsr   tnl_4094  0.0.0.0     2182002287
1570  * </pre>
1571  *
1572  * @param phase the phase of the change (startup/runtime/shutdown)
1573  */
1574 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
1575              /*                     #  Orig Prefx Upl   Dwn PathC Type  Intfc Gw    Cost */
1576   static const char * fmt_header = "%s%-16s %-33s %-8s %-8s %-10s %-16s %-16s %-16s %s\n";
1577   static const char * fmt_values = "%s%-16s %-33s %-8u %-8u %-10u %-16s %-16s %-16s %llu\n";
1578
1579   char * fileName = olsr_cnf->smart_gw_status_file;
1580   FILE * fp = NULL;
1581
1582   if (!fileName || (fileName[0] == '\0')) {
1583     return;
1584   }
1585
1586   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1587     remove(fileName);
1588     return;
1589   }
1590
1591   fp = fopen(fileName, "w");
1592   if (!fp) {
1593     olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
1594     return;
1595   }
1596
1597   fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
1598   fprintf(fp, "# Generated on ");
1599   printDate(fp);
1600   fprintf(fp, "\n\n");
1601
1602   /* header */
1603   fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
1604
1605   /* egress interfaces */
1606   {
1607     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1608     while (egress_if) {
1609       struct ipaddr_str gwStr;
1610       const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
1611       bool selected = bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
1612
1613       fprintf(fp, fmt_values, //
1614           selected ? "*" : " ", //selected
1615           IPLOCAL, // Originator
1616           MASKLOCAL, // Prefix
1617           egress_if->bwCurrent.egressUk, // Uplink
1618           egress_if->bwCurrent.egressDk, // Downlink
1619           egress_if->bwCurrent.path_cost, // PathCost
1620           "egress", // Type
1621           egress_if->name, // Interface
1622           gw, // Gateway
1623           egress_if->bwCurrent.costs // Cost
1624           );
1625
1626       egress_if = egress_if->next;
1627     }
1628   }
1629
1630   /* olsr */
1631   {
1632     struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1633     struct gateway_entry * gw = !gwContainer ? NULL : gwContainer->gw;
1634     struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1635     struct tc_entry* tc = !gw ? NULL : olsr_lookup_tc_entry(&gw->originator);
1636
1637     struct ipaddr_str originatorStr;
1638     const char * originator = !gw ? IPNONE : olsr_ip_to_string(&originatorStr, &gw->originator);
1639     struct ipaddr_str prefixIpStr;
1640     const char * prefixIPStr = !gw ? IPNONE : olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
1641     uint8_t prefix_len = !gw ? 0 : gw->external_prefix.prefix_len;
1642     struct interfaceName * tunnelName = !gw ? NULL : find_interfaceName(gw);
1643     struct ipaddr_str tunnelGwStr;
1644     const char * tunnelGw = !tunnel ? IPNONE : olsr_ip_to_string(&tunnelGwStr, &tunnel->target);
1645     bool selected = bestOverallLink.valid && bestOverallLink.isOlsr;
1646
1647     char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
1648     snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
1649
1650     fprintf(fp, fmt_values, //
1651         selected ? "*" : " ", // selected
1652         originator, // Originator
1653         !gw ? MASKNONE : prefix, // Prefix IP
1654         !gw ? 0 : gw->uplink, // Uplink
1655         !gw ? 0 : gw->downlink, // Downlink
1656         (!gw || !tc) ? ROUTE_COST_BROKEN : tc->path_cost, // PathCost
1657         "olsr", // Type
1658         !tunnelName ? "none" : tunnelName->name, // Interface
1659         tunnelGw, // Gateway
1660         !gw ? INT64_MAX : gw->path_cost // Cost
1661       );
1662   }
1663
1664   fclose(fp);
1665 }
1666
1667 /**
1668  * Report a new gateway with its most relevant parameters in the syslog
1669  */
1670 static void reportNewGateway(void) {
1671   if (!bestOverallLink.valid) {
1672     /* best overall link is invalid (none) */
1673     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
1674     return;
1675   }
1676
1677   if (!bestOverallLink.isOlsr) {
1678     /* best overall link is an egress interface */
1679     struct ipaddr_str gwStr;
1680     const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
1681         NULL : //
1682         olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
1683
1684     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
1685         bestOverallLink.link.egress->name, //
1686         !gw ? "" : "via ", //
1687         !gw ? "" : gwStr.buf, //
1688         !gw ? "" : " ", //
1689         bestOverallLink.link.egress->bwCurrent.egressUk, //
1690         bestOverallLink.link.egress->bwCurrent.egressDk, //
1691         bestOverallLink.link.egress->bwCurrent.path_cost);
1692     return;
1693   }
1694
1695   /* best overall link is an olsr (tunnel) interface */
1696   {
1697     struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
1698
1699     char ifNameBuf[IFNAMSIZ];
1700     const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
1701
1702     struct ipaddr_str gwStr;
1703     const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
1704
1705     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%u", //
1706         !ifName ? "none" : ifName, //
1707         !gw ? "" : "via ", //
1708         !gw ? "" : gwStr.buf, //
1709         !gw ? "" : " ", //
1710         bestOverallLink.link.olsr->uplink, //
1711         bestOverallLink.link.olsr->downlink, //
1712         !tc ? ROUTE_COST_BROKEN : tc->path_cost);
1713   }
1714 }
1715
1716 /**
1717  * Process changes that are relevant to egress interface: changes to the
1718  * egress interfaces themselves and to the smart gateway that is chosen by olsrd
1719  *
1720  * @param egressChanged true when an egress interface changed
1721  * @param olsrChanged true when the smart gateway changed
1722  * @param phase the phase of the change (startup/runtime/shutdown)
1723  */
1724 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
1725   bool bestEgressChanged = false;
1726   bool bestOverallChanged = false;
1727   bool force = MSGW_ROUTE_FORCED(phase);
1728
1729   assert( //
1730       (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
1731       (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
1732       (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
1733
1734   if (!egressChanged && !olsrChanged && !force) {
1735     goto out;
1736   }
1737
1738   assert(multi_gateway_mode());
1739
1740   if (egressChanged || force) {
1741     bestEgressChanged = determineBestEgressLink(phase);
1742   }
1743
1744   if (olsrChanged || bestEgressChanged || force) {
1745     bestOverallChanged = determineBestOverallLink(phase);
1746   }
1747
1748   if (!bestEgressChanged && !bestOverallChanged && !force) {
1749     goto out;
1750   }
1751
1752   // FIXME program routes
1753
1754   if (bestOverallChanged || force) {
1755     reportNewGateway();
1756   }
1757
1758   writeProgramStatusFile(phase);
1759
1760   out: if (egressChanged) {
1761     /* clear the 'changed' flags of egress interfaces */
1762     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
1763     while (egress_if) {
1764       egress_if->upChanged = false;
1765
1766       egress_if->bwCostsChanged = false;
1767       egress_if->bwNetworkChanged = false;
1768       egress_if->bwGatewayChanged = false;
1769       egress_if->bwChanged = false;
1770
1771       egress_if = egress_if->next;
1772     }
1773   }
1774 }
1775
1776 #endif /* __linux__ */