sgw: fix memory leaks on the shutdown path
[olsrd.git] / src / gateway.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #ifdef __linux__
47
48 #include "common/avl.h"
49 #include "defs.h"
50 #include "ipcalc.h"
51 #include "olsr.h"
52 #include "olsr_cfg.h"
53 #include "olsr_cookie.h"
54 #include "scheduler.h"
55 #include "kernel_routes.h"
56 #include "kernel_tunnel.h"
57 #include "net_os.h"
58 #include "duplicate_set.h"
59 #include "log.h"
60 #include "gateway_default_handler.h"
61 #include "gateway_list.h"
62 #include "gateway.h"
63 #include "gateway_costs.h"
64 #include "egressTypes.h"
65 #include "egressFile.h"
66 #include "ifnet.h"
67
68 #include <assert.h>
69 #include <linux/rtnetlink.h>
70 #include <net/if.h>
71 #include <sys/ioctl.h>
72
73 /*
74  * Defines for the multi-gateway script
75  */
76
77 #define SCRIPT_MODE_CLEANUP   "cleanup"
78 #define SCRIPT_MODE_GENERIC   "generic"
79 #define SCRIPT_MODE_OLSRIF    "olsrif"
80 #define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
81 #define SCRIPT_MODE_EGRESSIF  "egressif"
82 #define SCRIPT_MODE_SGWTUN    "sgwtun"
83
84 /* ipv4 prefix 0.0.0.0/0 */
85 static struct olsr_ip_prefix ipv4_slash_0_route;
86
87 /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
88 static struct olsr_ip_prefix ipv4_slash_1_routes[2];
89
90 /** the gateway tree */
91 struct avl_tree gateway_tree;
92
93 /** gateway cookie */
94 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
95
96 /** gateway container cookie */
97 static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
98
99 /** the gateway netmask for the HNA with zero bandwidth */
100 static uint8_t smart_gateway_netmask_zero[sizeof(union olsr_ip_addr)];
101
102 /** the gateway netmask for the HNA */
103 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
104
105 /** the gateway handler/plugin */
106 static struct olsr_gw_handler *gw_handler;
107
108 /** the IPv4 gateway list */
109 struct gw_list gw_list_ipv4;
110
111 /** the IPv6 gateway list */
112 struct gw_list gw_list_ipv6;
113
114 /** the current IPv4 gateway */
115 static struct gw_container_entry *current_ipv4_gw;
116
117 /** the current IPv6 gateway */
118 static struct gw_container_entry *current_ipv6_gw;
119
120 /** interface names for smart gateway tunnel interfaces, IPv4 */
121 struct interfaceName * sgwTunnel4InterfaceNames;
122
123 /** interface names for smart gateway tunnel interfaces, IPv6 */
124 struct interfaceName * sgwTunnel6InterfaceNames;
125
126 /** the timer for proactive takedown */
127 static struct timer_entry *gw_takedown_timer;
128
129 struct BestOverallLink {
130   bool valid;
131   bool isOlsr;
132   union {
133     struct sgw_egress_if * egress;
134     struct gateway_entry * olsr;
135   } link;
136   int olsrTunnelIfIndex;
137 };
138
139 static struct sgw_egress_if * bestEgressLinkPrevious = NULL;
140 static struct sgw_egress_if * bestEgressLink = NULL;
141
142 struct sgw_route_info bestEgressLinkPreviousRoute;
143 struct sgw_route_info bestEgressLinkRoute;
144
145 struct sgw_route_info bestOverallLinkPreviousRoutes[2];
146 struct sgw_route_info bestOverallLinkRoutes[2];
147
148 static struct BestOverallLink bestOverallLinkPrevious;
149 static struct BestOverallLink bestOverallLink;
150
151 static bool olsrInterfacesAllDown = false;
152
153 /*
154  * Forward Declarations
155  */
156
157 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate);
158 static void writeProgramStatusFile(enum sgw_multi_change_phase phase);
159 static bool isInterfaceUp(int if_index);
160
161 /*
162  * Helper Functions
163  */
164
165 /**
166  * @return true when all olsr interfaces are down
167  */
168 static bool allOlsrInterfacesDown(struct olsrd_config * cfg) {
169   struct olsr_if * ifn;
170
171   for (ifn = cfg->interfaces; ifn; ifn = ifn->next) {
172     if (!ifn->interf) {
173       continue;
174     }
175
176     if (isInterfaceUp(ifn->interf->if_index)) {
177       return false;
178     }
179   }
180
181   return true;
182 }
183
184 /**
185  * @return the gateway 'server' tunnel name to use
186  */
187 static INLINE const char * server_tunnel_name(void) {
188   return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
189 }
190
191 /**
192  * Convert the netmask of the HNA (in the form of an IP address) to a HNA
193  * pointer.
194  *
195  * @param mask the netmask of the HNA (in the form of an IP address)
196  * @param prefixlen the prefix length
197  * @return a pointer to the HNA
198  */
199 static INLINE uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
200   return (((uint8_t *)mask) + ((prefixlen+7)/8));
201 }
202
203 /**
204  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
205  * to an uplink/downlink speed value
206  *
207  * @param value the encoded 1 byte transport value
208  * @return the uplink/downlink speed value (in kbit/s)
209  */
210 static uint32_t deserialize_gw_speed(uint8_t value) {
211   uint32_t speed;
212   uint32_t exp;
213
214   if (!value) {
215     return 0;
216   }
217
218   if (value == UINT8_MAX) {
219     /* maximum value: also return maximum value */
220     return MAX_SMARTGW_SPEED;
221   }
222
223   speed = (value >> 3) + 1;
224   exp = value & 7;
225
226   while (exp-- > 0) {
227     speed *= 10;
228   }
229   return speed;
230 }
231
232 /**
233  * Convert an uplink/downlink speed value into an encoded 1 byte transport
234  * value (5 bits mantissa, 3 bits exponent)
235  *
236  * A bandwidth of 1 will alias onto a bandwidth of 2.
237  *
238  * @param speed the uplink/downlink speed value (in kbit/s)
239  * @return value the encoded 1 byte transport value
240  */
241 static uint8_t serialize_gw_speed(uint32_t speed) {
242   uint8_t exp = 0;
243
244   if (speed == 0) {
245     return 0;
246   }
247
248   if (speed == 1) {
249     speed++;
250   }
251
252   if (speed >= MAX_SMARTGW_SPEED) {
253     return UINT8_MAX;
254   }
255
256   while ((speed > 32 || (speed % 10) == 0) && exp < 7) {
257     speed /= 10;
258     exp++;
259   }
260   return ((speed - 1) << 3) | exp;
261 }
262
263 /**
264  * Find an interfaceName struct corresponding to a certain gateway
265  * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
266  *
267  * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
268  * @return a pointer to the struct, or NULL when not found
269  */
270 static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
271   struct interfaceName * sgwTunnelInterfaceNames;
272   uint8_t i = 0;
273
274   if (!multi_gateway_mode()) {
275     return NULL;
276   }
277
278   assert(sgwTunnel4InterfaceNames);
279   assert(sgwTunnel6InterfaceNames);
280
281   sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
282   while (i < olsr_cnf->smart_gw_use_count) {
283     struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
284     if (ifn->gw == gw) {
285       return ifn;
286     }
287     i++;
288   }
289
290   return NULL;
291 }
292
293 /**
294  * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
295  *
296  * @param gw pointer to the gateway
297  * @param name pointer to output buffer (length IFNAMSIZ)
298  * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
299  */
300 static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
301   static uint32_t counter = 0;
302
303   assert(gw);
304   assert(name);
305   assert(interfaceName);
306
307   memset(name, 0, IFNAMSIZ);
308
309   if (multi_gateway_mode()) {
310     struct interfaceName * ifn = find_interfaceName(NULL);
311
312     if (ifn) {
313       strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
314       *interfaceName = ifn;
315       ifn->gw = gw;
316       return;
317     }
318
319     /* do not return, fall-through to classic naming as fallback */
320   }
321
322   snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
323   *interfaceName = NULL;
324 }
325
326 /**
327  * Set an olsr ipip tunnel name that is used by a certain gateway as unused
328  *
329  * @param gw pointer to the gateway
330  */
331 static void set_unused_iptunnel_name(struct gateway_entry *gw) {
332   struct interfaceName * ifn;
333
334   if (!multi_gateway_mode()) {
335     return;
336   }
337
338   assert(gw);
339
340   ifn = find_interfaceName(gw);
341   if (ifn) {
342     ifn->gw = NULL;
343     return;
344   }
345 }
346
347 /**
348  * Run the multi-gateway script/
349  *
350  * @param mode the mode (see SCRIPT_MODE_* defines)
351  * @param addMode true to add policy routing, false to remove it
352  * @param ifname the interface name (optional)
353  * @param tableNr the routing table number (optional)
354  * @param ruleNr the IP rule number/priority (optional)
355  * @param bypassRuleNr the bypass IP rule number/priority (optional)
356  * @return true when successful
357  */
358 static bool multiGwRunScript(const char * mode, bool addMode, const char * ifName, uint32_t tableNr, uint32_t ruleNr, uint32_t bypassRuleNr) {
359   struct autobuf buf;
360   int r;
361
362   assert(!strcmp(mode, SCRIPT_MODE_CLEANUP) //
363       || !strcmp(mode, SCRIPT_MODE_GENERIC) //
364       || !strcmp(mode, SCRIPT_MODE_OLSRIF)//
365       || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN)//
366       || !strcmp(mode, SCRIPT_MODE_EGRESSIF)//
367       || !strcmp(mode, SCRIPT_MODE_SGWTUN)//
368       );
369
370   assert(strcmp(mode, SCRIPT_MODE_CLEANUP) //
371       || (!strcmp(mode, SCRIPT_MODE_CLEANUP) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
372
373   assert(strcmp(mode, SCRIPT_MODE_GENERIC) //
374       || (!strcmp(mode, SCRIPT_MODE_GENERIC) && !ifName && !tableNr && !ruleNr && !bypassRuleNr));
375
376   assert(strcmp(mode, SCRIPT_MODE_OLSRIF) //
377       || (!strcmp(mode, SCRIPT_MODE_OLSRIF) && ifName && !tableNr && !ruleNr && bypassRuleNr));
378
379   assert(strcmp(mode, SCRIPT_MODE_SGWSRVTUN) //
380       || (!strcmp(mode, SCRIPT_MODE_SGWSRVTUN) && ifName && tableNr&& ruleNr && !bypassRuleNr));
381
382   assert(strcmp(mode, SCRIPT_MODE_EGRESSIF) //
383       || (!strcmp(mode, SCRIPT_MODE_EGRESSIF) && ifName && tableNr && ruleNr && bypassRuleNr));
384
385   assert(strcmp(mode, SCRIPT_MODE_SGWTUN) //
386       || (!strcmp(mode, SCRIPT_MODE_SGWTUN) && ifName && tableNr && ruleNr && !bypassRuleNr));
387
388   abuf_init(&buf, AUTOBUFCHUNK);
389
390   abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
391
392   abuf_appendf(&buf, " \"%s\"", olsr_cnf->smart_gw_instance_id);
393
394   abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
395
396   abuf_appendf(&buf, " \"%s\"", mode);
397
398   abuf_appendf(&buf, " \"%s\"", addMode ? "add" : "del");
399
400   if (ifName) {
401     abuf_appendf(&buf, " \"%s\"", ifName);
402   }
403
404   if (tableNr) {
405     abuf_appendf(&buf, " \"%u\"", tableNr);
406   }
407
408   if (ruleNr) {
409     abuf_appendf(&buf, " \"%u\"", ruleNr);
410   }
411
412   if (bypassRuleNr) {
413     abuf_appendf(&buf, " \"%u\"", bypassRuleNr);
414   }
415
416   r = system(buf.buf);
417
418   abuf_free(&buf);
419
420   return (r == 0);
421 }
422
423 /**
424  * Cleanup multi-gateway iptables and ip rules
425  *
426  * @param add true to add policy routing, false to remove it
427  * @return true when successful
428  */
429 static bool multiGwRulesCleanup(bool add) {
430   return multiGwRunScript(SCRIPT_MODE_CLEANUP, add, NULL, 0, 0, 0);
431 }
432
433 /**
434  * Setup generic multi-gateway iptables and ip rules
435  *
436  * @param add true to add policy routing, false to remove it
437  * @return true when successful
438  */
439 static bool multiGwRulesGeneric(bool add) {
440   return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, 0, 0, 0);
441 }
442
443 /**
444  * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
445  *
446  * @param add true to add policy routing, false to remove it
447  * @return true when successful
448  */
449 static bool multiGwRulesOlsrInterfaces(bool add) {
450   bool ok = true;
451   struct olsr_if * ifn;
452   unsigned int i = 0;
453
454   for (ifn = olsr_cnf->interfaces; ifn; ifn = ifn->next, i++) {
455     if (!multiGwRunScript( //
456         SCRIPT_MODE_OLSRIF,//
457         add, //
458         ifn->name, //
459         0, //
460         0, //
461         olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + i //
462             )) {
463       ok = false;
464       if (add) {
465         return ok;
466       }
467     }
468   }
469
470   return ok;
471 }
472
473 /**
474  * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
475  *
476  * @param add true to add policy routing, false to remove it
477  * @return true when successful
478  */
479 static bool multiGwRulesSgwServerTunnel(bool add) {
480   return multiGwRunScript( //
481       SCRIPT_MODE_SGWSRVTUN,//
482       add, //
483       server_tunnel_name(), //
484       olsr_cnf->smart_gw_offset_tables, //
485       olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + getNrOfOlsrInterfaces(olsr_cnf), //
486       0 //
487       );
488 }
489
490 /**
491  * Setup multi-gateway iptables and ip rules for all egress interfaces.
492  *
493  * @param add true to add policy routing, false to remove it
494  * @return true when successful
495  */
496 static bool multiGwRulesEgressInterfaces(bool add) {
497   bool ok = true;
498
499   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
500   while (egress_if) {
501     if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, egress_if->name, egress_if->tableNr, egress_if->ruleNr, egress_if->bypassRuleNr)) {
502       ok = false;
503       if (add) {
504         return ok;
505       }
506     }
507
508     egress_if = egress_if->next;
509   }
510
511   return ok;
512 }
513
514 /**
515  * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
516  *
517  * @param add true to add policy routing, false to remove it
518  * @return true when successful
519  */
520 static bool multiGwRulesSgwTunnels(bool add) {
521   bool ok = true;
522   unsigned int i = 0;
523
524   while (i < olsr_cnf->smart_gw_use_count) {
525     struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
526     if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, ifn->tableNr, ifn->ruleNr, ifn->bypassRuleNr)) {
527       ok = false;
528       if (add) {
529         return ok;
530       }
531     }
532
533     i++;
534   }
535
536   return ok;
537 }
538
539 /**
540  * Process interface up/down events for non-olsr interfaces, which are egress
541  * interfaces
542  *
543  * @param if_index the index of the interface
544  * @param flag the up/down event
545  */
546 static void doEgressInterface(int if_index, enum olsr_ifchg_flag flag) {
547   switch (flag) {
548     case IFCHG_IF_ADD: {
549       char ifname[IF_NAMESIZE];
550       struct sgw_egress_if * egress_if;
551
552       /*
553        * we need to get the name of the interface first because the interface
554        * might be hot-plugged _after_ olsrd has started
555        */
556       if (!if_indextoname(if_index, ifname)) {
557         /* not a known OS interface */
558         return;
559       }
560
561       egress_if = findEgressInterface(ifname);
562       if (!egress_if) {
563         /* not a known egress interface */
564         return;
565       }
566
567       egress_if->if_index = if_index;
568
569       if (egress_if->upCurrent) {
570         /* interface is already up: no change */
571         return;
572       }
573
574       egress_if->upPrevious = egress_if->upCurrent;
575       egress_if->upCurrent = true;
576       egress_if->upChanged = true;
577
578       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
579     }
580       break;
581
582     case IFCHG_IF_REMOVE: {
583       /*
584        * we need to find the egress interface by if_index because we might
585        * be too late; the kernel could already have removed the interface
586        * in which case we'd get a NULL ifname here if we'd try to call
587        * if_indextoname
588        */
589       struct sgw_egress_if * egress_if = findEgressInterfaceByIndex(if_index);
590       if (!egress_if) {
591         /* not a known egress interface */
592         return;
593       }
594
595       if (!egress_if->upCurrent) {
596         /* interface is already down: no change */
597         return;
598       }
599
600       egress_if->upPrevious = egress_if->upCurrent;
601       egress_if->upCurrent = false;
602       egress_if->upChanged = true;
603
604       egress_if->bwCostsChanged = egressBwCalculateCosts(&egress_if->bwCurrent, egress_if->upCurrent);
605     }
606       break;
607
608     case IFCHG_IF_UPDATE:
609     default:
610       return;
611   }
612
613   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_RUNTIME);
614 }
615
616 /*
617  * Callback Functions
618  */
619
620 /**
621  * Callback for tunnel interface monitoring which will set the route into the tunnel
622  * when the interface comes up again.
623  *
624  * @param if_index the interface index
625  * @param ifh the interface (NULL when not an olsr interface)
626  * @param flag interface change flags
627  */
628 static void smartgw_tunnel_monitor(int if_index, struct interface_olsr *ifh, enum olsr_ifchg_flag flag) {
629   if (!ifh && multi_gateway_mode()) {
630     /* non-olsr interface in multi-sgw mode */
631     doEgressInterface(if_index, flag);
632   }
633
634   /*
635    * The best gateway must always be re-evaluated since olsr and/or egress interfaces might have
636    * changed their UP/DOWN status
637    */
638   doRoutesMultiGw(true, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
639
640   return;
641 }
642
643 /**
644  * Timer callback to expire a gateway entry
645  *
646  * @param ptr a pointer to the smart gateway HNA to expire (struct gateway_entry*)
647  */
648 static void expire_gateway_handler(void *ptr) {
649   struct gateway_entry *gw = ptr;
650
651   assert(gw);
652
653   /* remove gateway entry */
654   olsr_delete_gateway_entry(&gw->originator, gw->external_prefix.prefix_len, false);
655 }
656
657 /**
658  * Timer callback to remove and cleanup a gateway entry
659  *
660  * @param ptr
661  */
662 static void cleanup_gateway_handler(void *ptr) {
663   struct gateway_entry *gw = ptr;
664
665   if (gw->ipv4 || gw->ipv6) {
666     /* do not clean it up when it is in use */
667     return;
668   }
669
670   /* remove gateway entry */
671   avl_delete(&gateway_tree, &gw->node);
672   olsr_cookie_free(gateway_entry_mem_cookie, gw);
673 }
674
675 /**
676  * Remove a gateway from a gateway list.
677  *
678  * @param gw_list a pointer to the gateway list
679  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
680  * @param gw a pointer to the gateway to remove from the list
681  */
682 static void removeGatewayFromList(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * gw) {
683   if (gw->tunnel) {
684     struct interfaceName * ifn = find_interfaceName(gw->gw);
685     if (ifn) {
686       olsr_os_inetgw_tunnel_route(gw->tunnel->if_index, ipv4, false, ifn->tableNr);
687     }
688     olsr_os_del_ipip_tunnel(gw->tunnel);
689     set_unused_iptunnel_name(gw->gw);
690     gw->tunnel = NULL;
691   }
692   gw->gw = NULL;
693   olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(gw_list, gw));
694 }
695
696 /**
697  * Remove expensive gateways from the gateway list.
698  * It uses the smart_gw_takedown_percentage configuration parameter
699  *
700  * @param gw_list a pointer to the gateway list
701  * @param ipv4 true when dealing with an IPv4 gateway / gateway list
702  * @param current_gw the current gateway
703  */
704 static void takeDownExpensiveGateways(struct gw_list * gw_list, bool ipv4, struct gw_container_entry * current_gw) {
705   int64_t current_gw_cost_boundary;
706
707   /*
708    * exit immediately when takedown is disabled, there is no current gateway, or
709    * when there is only a single gateway
710    */
711   if ((olsr_cnf->smart_gw_takedown_percentage == 0) || !current_gw || (gw_list->count <= 1)) {
712     return;
713   }
714
715   /* get the cost boundary */
716   current_gw_cost_boundary = current_gw->gw->path_cost;
717   if (olsr_cnf->smart_gw_takedown_percentage < 100) {
718     if (current_gw_cost_boundary <= (INT64_MAX / 100)) {
719       current_gw_cost_boundary =  ((current_gw_cost_boundary * 100) / olsr_cnf->smart_gw_takedown_percentage);
720     } else {
721       /* perform scaling because otherwise the percentage calculation can overflow */
722       current_gw_cost_boundary = (((current_gw_cost_boundary      ) / olsr_cnf->smart_gw_takedown_percentage) * 100) + 99;
723     }
724   }
725
726   /* loop while we still have gateways */
727   while (gw_list->count > 1) {
728     /* get the worst gateway */
729     struct gw_container_entry * worst_gw = olsr_gw_list_get_worst_entry(gw_list);
730     assert(worst_gw);
731
732     if (!worst_gw) {
733       return;
734     }
735
736     /* exit when it's the current gateway */
737     if (worst_gw == current_gw) {
738       return;
739     }
740
741     /*
742      * exit when it (and further ones; the list is sorted on costs) has lower
743      * costs than the boundary costs
744      */
745     if (worst_gw->gw && (worst_gw->gw->path_cost < current_gw_cost_boundary)) {
746       return;
747     }
748
749     /* it's too expensive: take it down */
750     removeGatewayFromList(gw_list, ipv4, worst_gw);
751   }
752 }
753
754 /**
755  * Timer callback for proactive gateway takedown
756  *
757  * @param unused unused
758  */
759 static void gw_takedown_timer_callback(void *unused __attribute__ ((unused))) {
760   takeDownExpensiveGateways(&gw_list_ipv4, true, current_ipv4_gw);
761   takeDownExpensiveGateways(&gw_list_ipv6, false, current_ipv6_gw);
762 }
763
764 /*
765  * Main Interface
766  */
767
768 /**
769  * Initialize gateway system
770  */
771 int olsr_init_gateways(void) {
772   int retries = 5;
773
774   memset(&bestEgressLinkPreviousRoute, 0, sizeof(bestEgressLinkPreviousRoute));
775   memset(&bestEgressLinkRoute, 0, sizeof(bestEgressLinkRoute));
776   memset(bestOverallLinkPreviousRoutes, 0, sizeof(bestOverallLinkPreviousRoutes));
777   memset(bestOverallLinkRoutes, 0, sizeof(bestOverallLinkRoutes));
778
779   /* ipv4 prefix 0.0.0.0/0 */
780   memset(&ipv4_slash_0_route, 0, sizeof(ipv4_slash_0_route));
781
782   /* ipv4 prefixes 0.0.0.0/1 and 128.0.0.0/1 */
783   memset(&ipv4_slash_1_routes, 0, sizeof(ipv4_slash_1_routes));
784   ipv4_slash_1_routes[0].prefix.v4.s_addr = htonl(0x00000000);
785   ipv4_slash_1_routes[0].prefix_len = 1;
786   ipv4_slash_1_routes[1].prefix.v4.s_addr = htonl(0x80000000);
787   ipv4_slash_1_routes[1].prefix_len = 1;
788
789   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
790   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
791
792   gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
793   olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
794
795   avl_init(&gateway_tree, avl_comp_default);
796
797   olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
798   olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
799
800   sgwTunnel4InterfaceNames = NULL;
801   sgwTunnel6InterfaceNames = NULL;
802   memset(&bestOverallLinkPrevious, 0, sizeof(bestOverallLinkPrevious));
803   memset(&bestOverallLink, 0, sizeof(bestOverallLink));
804
805   if (multi_gateway_mode()) {
806     uint8_t i;
807     struct sgw_egress_if * egressif;
808     unsigned int nrOlsrIfs = getNrOfOlsrInterfaces(olsr_cnf);
809
810     /* Initialise the egress interfaces */
811     /* setup the egress interface name/mark pairs */
812     i = 0;
813     egressif = olsr_cnf->smart_gw_egress_interfaces;
814     while (egressif) {
815       egressif->if_index = if_nametoindex(egressif->name);
816
817       egressif->tableNr = olsr_cnf->smart_gw_offset_tables + 1 + i;
818       egressif->ruleNr = olsr_cnf->smart_gw_offset_rules + olsr_cnf->smart_gw_egress_interfaces_count + nrOlsrIfs + 1 + i;
819       egressif->bypassRuleNr = olsr_cnf->smart_gw_offset_rules + i;
820
821       egressif->upPrevious = egressif->upCurrent = olsr_if_isup(egressif->name);
822       egressif->upChanged = (egressif->upPrevious != egressif->upCurrent);
823
824       egressBwClear(&egressif->bwPrevious, egressif->upPrevious);
825       egressBwClear(&egressif->bwCurrent, egressif->upCurrent);
826       egressif->bwCostsChanged = egressBwCostsChanged(egressif);
827       egressif->bwNetworkChanged = egressBwNetworkChanged(egressif);
828       egressif->bwGatewayChanged = egressBwGatewayChanged(egressif);
829       egressif->bwChanged = egressBwChanged(egressif);
830
831       egressif->inEgressFile = false;
832
833       egressif = egressif->next;
834       i++;
835     }
836     assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
837
838     /* setup the SGW tunnel name/mark pairs */
839     sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
840     sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
841     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
842       struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
843       uint32_t tableNr = olsr_cnf->smart_gw_offset_tables + 1 + olsr_cnf->smart_gw_egress_interfaces_count + i;
844       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;
845
846       ifn->gw = NULL;
847       ifn->tableNr = tableNr;
848       ifn->ruleNr = ruleNr;
849       ifn->bypassRuleNr = 0;
850       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->tableNr);
851
852       ifn = &sgwTunnel6InterfaceNames[i];
853       ifn->gw = NULL;
854       ifn->tableNr = tableNr;
855       ifn->ruleNr = ruleNr;
856       ifn->bypassRuleNr = 0;
857       snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->tableNr);
858     }
859   }
860
861   current_ipv4_gw = NULL;
862   current_ipv6_gw = NULL;
863
864   gw_handler = NULL;
865
866   refresh_smartgw_netmask();
867
868   /* initialize default gateway handler */
869   gw_handler = &gw_def_handler;
870   gw_handler->init();
871
872
873   /*
874    * There appears to be a kernel bug in some kernels (at least in the 3.0
875    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
876    * initialising the IPIP server tunnel (loading the IPIP module), so we retry
877    * a few times before giving up
878    */
879   while (retries-- > 0) {
880     if (!olsr_os_init_iptunnel(server_tunnel_name())) {
881       retries = 5;
882       break;
883     }
884
885     olsr_printf(0, "Could not initialise the IPIP server tunnel, retrying %d more times\n", retries);
886   }
887   if (retries <= 0) {
888     return 1;
889   }
890
891   return 0;
892 }
893
894 /**
895  * Startup gateway system
896  */
897 int olsr_startup_gateways(void) {
898   bool ok = true;
899
900   if (!multi_gateway_mode()) {
901     olsr_add_ifchange_handler(smartgw_tunnel_monitor);
902     return 0;
903   }
904
905   ok = ok && multiGwRulesCleanup(true);
906   ok = ok && multiGwRulesGeneric(true);
907   ok = ok && multiGwRulesSgwServerTunnel(true);
908   ok = ok && multiGwRulesOlsrInterfaces(true);
909   ok = ok && multiGwRulesEgressInterfaces(true);
910   ok = ok && multiGwRulesSgwTunnels(true);
911   if (!ok) {
912     olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
913     olsr_shutdown_gateways();
914     return 1;
915   }
916
917   startEgressFile();
918   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_STARTUP);
919
920   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
921
922   /* Check egress interfaces up status to compensate for a race: the interfaces
923    * can change status between initialising their data structures and
924    * registering the tunnel monitor */
925   {
926     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
927     while (egress_if) {
928       bool upCurrent = olsr_if_isup(egress_if->name);
929
930       if (upCurrent != egress_if->upCurrent) {
931         int idx = upCurrent ? (int) if_nametoindex(egress_if->name) : egress_if->if_index;
932         enum olsr_ifchg_flag flag = upCurrent ? IFCHG_IF_ADD : IFCHG_IF_REMOVE;
933         smartgw_tunnel_monitor(idx, NULL, flag);
934       }
935
936       egress_if = egress_if->next;
937     }
938   }
939
940   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
941     /* start gateway takedown timer */
942     olsr_set_timer(&gw_takedown_timer, olsr_cnf->smart_gw_period, 0, true, &gw_takedown_timer_callback, NULL, 0);
943   }
944
945   return 0;
946 }
947
948 /**
949  * Shutdown gateway tunnel system
950  */
951 void olsr_shutdown_gateways(void) {
952   if (!multi_gateway_mode()) {
953     olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
954     return;
955   }
956
957   if (olsr_cnf->smart_gw_takedown_percentage > 0) {
958     /* stop gateway takedown timer */
959     olsr_stop_timer(gw_takedown_timer);
960     gw_takedown_timer = NULL;
961   }
962
963   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
964
965   stopEgressFile();
966   {
967     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
968     while (egress_if) {
969       egress_if->upPrevious = egress_if->upCurrent;
970       egress_if->upCurrent = false;
971       egress_if->upChanged = (egress_if->upPrevious != egress_if->upCurrent);
972
973       egress_if->bwPrevious = egress_if->bwCurrent;
974       egressBwClear(&egress_if->bwCurrent, egress_if->upCurrent);
975       egress_if->bwCostsChanged = egressBwCostsChanged(egress_if);
976       egress_if->bwNetworkChanged = egressBwNetworkChanged(egress_if);
977       egress_if->bwGatewayChanged = egressBwGatewayChanged(egress_if);
978       egress_if->bwChanged = egressBwChanged(egress_if);
979
980       egress_if->inEgressFile = false;
981
982       egress_if = egress_if->next;
983     }
984   }
985   doRoutesMultiGw(true, false, GW_MULTI_CHANGE_PHASE_SHUTDOWN);
986
987   (void)multiGwRulesSgwTunnels(false);
988   (void)multiGwRulesEgressInterfaces(false);
989   (void)multiGwRulesOlsrInterfaces(false);
990   (void)multiGwRulesSgwServerTunnel(false);
991   (void)multiGwRulesGeneric(false);
992   (void)multiGwRulesCleanup(false);
993 }
994
995 /**
996  * Cleanup gateway tunnel system
997  */
998 void olsr_cleanup_gateways(void) {
999   struct gateway_entry * tree_gw;
1000   struct gw_container_entry * gw;
1001
1002   while (olsr_cnf->smart_gw_egress_interfaces) {
1003     struct sgw_egress_if * next = olsr_cnf->smart_gw_egress_interfaces->next;
1004     free(olsr_cnf->smart_gw_egress_interfaces->name);
1005     free(olsr_cnf->smart_gw_egress_interfaces);
1006     olsr_cnf->smart_gw_egress_interfaces = next;
1007   }
1008
1009   /* remove all gateways in the gateway tree that are not the active gateway */
1010   OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
1011     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
1012       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
1013     }
1014   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(tree_gw)
1015
1016   /* remove all active IPv4 gateways (should be at most 1 now) */
1017   OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
1018     if (gw && gw->gw) {
1019       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
1020     }
1021   }
1022   OLSR_FOR_ALL_GWS_END(gw);
1023
1024   /* remove all active IPv6 gateways (should be at most 1 now) */
1025   OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
1026     if (gw && gw->gw) {
1027       olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
1028     }
1029   }
1030   OLSR_FOR_ALL_GWS_END(gw);
1031
1032   /* there should be no more gateways */
1033   assert(!avl_walk_first(&gateway_tree));
1034   assert(!current_ipv4_gw);
1035   assert(!current_ipv6_gw);
1036
1037   olsr_os_cleanup_iptunnel(server_tunnel_name());
1038
1039   assert(gw_handler);
1040   gw_handler->cleanup();
1041   gw_handler = NULL;
1042
1043   if (sgwTunnel4InterfaceNames) {
1044     free(sgwTunnel4InterfaceNames);
1045     sgwTunnel4InterfaceNames = NULL;
1046   }
1047   if (sgwTunnel6InterfaceNames) {
1048     free(sgwTunnel6InterfaceNames);
1049     sgwTunnel6InterfaceNames = NULL;
1050   }
1051
1052   olsr_gw_list_cleanup(&gw_list_ipv6);
1053   olsr_gw_list_cleanup(&gw_list_ipv4);
1054   olsr_free_cookie(gw_container_entry_mem_cookie);
1055   olsr_free_cookie(gateway_entry_mem_cookie);
1056 }
1057
1058 /**
1059  * Triggers the first lookup of a gateway.
1060  */
1061 void olsr_trigger_inetgw_startup(void) {
1062   assert(gw_handler);
1063   gw_handler->startup();
1064 }
1065
1066 /**
1067  * Print debug information about gateway entries
1068  */
1069 #ifndef NODEBUG
1070 void olsr_print_gateway_entries(void) {
1071   struct ipaddr_str buf;
1072   struct gateway_entry *gw;
1073   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
1074
1075   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n", olsr_wallclock_string());
1076   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n",
1077       addrsize, "IP address", "Type", "Uplink", "Downlink", olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
1078
1079   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
1080     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n",
1081         addrsize,
1082         olsr_ip_to_string(&buf, &gw->originator),
1083         gw->ipv4nat ? "" : "   ",
1084         gw->ipv4 ? '4' : ' ',
1085         gw->ipv4nat ? "(N)" : "",
1086         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
1087         gw->ipv6 ? '6' : ' ',
1088         gw->uplink,
1089         gw->downlink,
1090         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
1091   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
1092 }
1093 #endif /* NODEBUG */
1094
1095 /*
1096  * Tx Path Interface
1097  */
1098
1099 /**
1100  * Apply the smart gateway modifications to an outgoing HNA
1101  *
1102  * @param mask pointer to netmask of the HNA
1103  * @param prefixlen of the HNA
1104  * @param zero true to use zero bandwidth
1105  */
1106 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen, bool zero) {
1107   uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1108
1109   /* copy the current settings for uplink/downlink into the mask */
1110   memcpy( //
1111       ptr, //
1112       zero ? &smart_gateway_netmask_zero : &smart_gateway_netmask, //
1113       (zero ? sizeof(smart_gateway_netmask_zero) : sizeof(smart_gateway_netmask)) - prefixlen / 8);
1114   if (olsr_cnf->has_ipv4_gateway) {
1115     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
1116
1117     if (olsr_cnf->smart_gw_uplink_nat) {
1118       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
1119     }
1120   }
1121   if (olsr_cnf->has_ipv6_gateway) {
1122     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
1123   }
1124   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len) {
1125     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
1126   }
1127 }
1128
1129 /*
1130  * SgwDynSpeed Plugin Interface
1131  */
1132
1133 /**
1134  * Setup the gateway netmask
1135  */
1136 void refresh_smartgw_netmask(void) {
1137   uint8_t *ip;
1138
1139   /* clear the mask */
1140   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
1141
1142   if (olsr_cnf->smart_gw_active) {
1143     ip = (uint8_t *) &smart_gateway_netmask;
1144
1145     ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
1146     ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
1147     ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
1148
1149     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
1150       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
1151       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
1152       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
1153     }
1154
1155     {
1156       uint8_t *ipz = (uint8_t *) &smart_gateway_netmask_zero;
1157       memcpy(ipz, ip, sizeof(smart_gateway_netmask_zero));
1158       ipz[GW_HNA_DOWNLINK] = serialize_gw_speed(0);
1159       ipz[GW_HNA_UPLINK] = serialize_gw_speed(0);
1160     }
1161   }
1162 }
1163
1164 /*
1165  * TC/SPF/HNA Interface
1166  */
1167
1168 /**
1169  * Checks if a HNA prefix/netmask combination is a smart gateway
1170  *
1171  * @param prefix
1172  * @param mask
1173  * @return true if is a valid smart gateway HNA, false otherwise
1174  */
1175 bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
1176   uint8_t *ptr;
1177
1178   if (!is_prefix_inetgw(prefix)) {
1179     return false;
1180   }
1181
1182   ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
1183   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
1184 }
1185
1186 /**
1187  * Update a gateway_entry based on a HNA
1188  *
1189  * @param originator ip of the source of the HNA
1190  * @param mask netmask of the HNA
1191  * @param prefixlen of the HNA
1192  * @param seqno the sequence number of the HNA
1193  * @param vtime the validity time of the HNA
1194  */
1195 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno, olsr_reltime vtime) {
1196   struct gw_container_entry * new_gw_in_list;
1197   uint8_t *ptr;
1198   int64_t prev_path_cost = 0;
1199   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
1200
1201   if (!gw) {
1202     gw = olsr_cookie_malloc(gateway_entry_mem_cookie);
1203     gw->originator = *originator;
1204     gw->node.key = &gw->originator;
1205
1206     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
1207   } else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
1208     /* ignore older HNAs */
1209     return;
1210   }
1211
1212   /* keep new HNA seqno */
1213   gw->seqno = seqno;
1214   gw->uplink = 0;
1215   gw->downlink = 0;
1216   gw->path_cost = INT64_MAX;
1217
1218   ptr = hna_mask_to_hna_pointer(mask, prefixlen);
1219   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
1220     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
1221     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
1222   }
1223
1224   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
1225   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
1226   gw->ipv6 = false;
1227
1228   if (olsr_cnf->ip_version == AF_INET6) {
1229     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
1230
1231     /* do not reset prefixlength for ::ffff:0:0 HNAs */
1232     if (prefixlen == ipv6_internet_route.prefix_len) {
1233       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
1234
1235       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
1236           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
1237         /* this is the right prefix (2000::/3), so we can copy the prefix */
1238         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
1239         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
1240       }
1241     }
1242   }
1243
1244   if (!gw->uplink || !gw->downlink) {
1245     olsr_delete_gateway_tree_entry(gw, FORCE_DELETE_GW_ENTRY, true);
1246     return;
1247   }
1248
1249   if (!gw->expire_timer) {
1250     /* start expire timer */
1251     olsr_set_timer(&gw->expire_timer, vtime, 0, false, expire_gateway_handler, gw, NULL);
1252   } else {
1253     /* restart expire timer */
1254     olsr_change_timer(gw->expire_timer, vtime, 0, false);
1255   }
1256
1257   /* stop cleanup timer if necessary */
1258   if (gw->cleanup_timer) {
1259     olsr_stop_timer(gw->cleanup_timer);
1260     gw->cleanup_timer = NULL;
1261   }
1262
1263   assert(gw_handler);
1264   prev_path_cost = gw->path_cost;
1265   gw->path_cost = gw_handler->getcosts(gw);
1266
1267   if (prev_path_cost != gw->path_cost) {
1268     /* re-sort the gateway list when costs have changed and when it is an active gateway */
1269     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1270     if (new_gw_in_list) {
1271       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list);
1272       assert(new_gw_in_list);
1273
1274       if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1275         /* the active gateway has changed its costs: re-evaluate egress routes */
1276         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1277       }
1278     }
1279
1280     new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1281     if (new_gw_in_list) {
1282       new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list);
1283       assert(new_gw_in_list);
1284
1285       if (multi_gateway_mode() && new_gw_in_list->tunnel) {
1286         /* the active gateway has changed its costs: re-evaluate egress routes */
1287         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1288       }
1289     }
1290   }
1291
1292   /* call update handler */
1293   assert(gw_handler);
1294   gw_handler->update(gw);
1295 }
1296
1297 /**
1298  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
1299  * Should only be called if prefix is a smart_gw prefix or if node is removed
1300  * from TC set.
1301  *
1302  * @param originator
1303  * @param prefixlen
1304  * @param immediate when set to true then the gateway is removed from the
1305  * gateway tree immediately, else it is removed on a delayed schedule.
1306  */
1307 void olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen, bool immediate) {
1308   olsr_delete_gateway_tree_entry(node2gateway(avl_find(&gateway_tree, originator)), prefixlen, immediate);
1309 }
1310
1311 /**
1312  * Delete a gateway entry .
1313  *
1314  * @param gw a gateway entry from the gateway tree
1315  * @param prefixlen
1316  * @param immediate when set to true then the gateway is removed from the
1317  * gateway tree immediately, else it is removed on a delayed schedule.
1318  */
1319 static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t prefixlen, bool immediate) {
1320   bool change = false;
1321
1322   if (!gw) {
1323     return;
1324   }
1325
1326   if (gw->expire_timer) {
1327     /* stop expire timer */
1328     olsr_stop_timer(gw->expire_timer);
1329     gw->expire_timer = NULL;
1330   }
1331
1332   if (immediate && gw->cleanup_timer) {
1333     /* stop timer if we have to remove immediately */
1334     olsr_stop_timer(gw->cleanup_timer);
1335     gw->cleanup_timer = NULL;
1336   }
1337
1338   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
1339     /* the gw  is not scheduled for deletion */
1340
1341     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
1342       change = gw->ipv4;
1343       gw->ipv4 = false;
1344       gw->ipv4nat = false;
1345     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
1346       change = gw->ipv6;
1347       gw->ipv6 = false;
1348     } else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
1349       change = gw->ipv4;
1350       gw->ipv4 = false;
1351       gw->ipv4nat = false;
1352     }
1353
1354     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
1355       bool write_status = false;
1356       struct gw_container_entry * gw_in_list;
1357
1358       /* prevent this gateway from being chosen as the new gateway */
1359       gw->ipv4 = false;
1360       gw->ipv4nat = false;
1361       gw->ipv6 = false;
1362
1363       /* handle gateway loss */
1364       assert(gw_handler);
1365       gw_handler->delete(gw);
1366
1367       /* cleanup gateway if necessary */
1368       gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
1369       if (gw_in_list) {
1370         if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
1371           olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
1372           current_ipv4_gw = NULL;
1373         }
1374
1375         if (gw_in_list->tunnel) {
1376           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1377           if (ifn) {
1378             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->tableNr);
1379           }
1380           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1381           set_unused_iptunnel_name(gw_in_list->gw);
1382           gw_in_list->tunnel = NULL;
1383         }
1384
1385         gw_in_list->gw = NULL;
1386         gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
1387         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1388         write_status = true;
1389       }
1390
1391       gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
1392       if (gw_in_list) {
1393         if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
1394           olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
1395           current_ipv6_gw = NULL;
1396         }
1397
1398         if (gw_in_list->tunnel) {
1399           struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
1400           if (ifn) {
1401             olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->tableNr);
1402           }
1403           olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
1404           set_unused_iptunnel_name(gw_in_list->gw);
1405           gw_in_list->tunnel = NULL;
1406         }
1407
1408         gw_in_list->gw = NULL;
1409         gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
1410         olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
1411         write_status = true;
1412       }
1413
1414       if (!immediate) {
1415         /* remove gateway entry on a delayed schedule */
1416         olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
1417       } else {
1418         cleanup_gateway_handler(gw);
1419       }
1420
1421       /* when the current gateway was deleted, then immediately choose a new gateway */
1422       if (!current_ipv4_gw || !current_ipv6_gw) {
1423         assert(gw_handler);
1424         gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
1425       }
1426
1427       if (multi_gateway_mode() && write_status) {
1428         writeProgramStatusFile(GW_MULTI_CHANGE_PHASE_RUNTIME);
1429       }
1430     } else if (change) {
1431       assert(gw_handler);
1432       gw_handler->update(gw);
1433     }
1434   }
1435 }
1436
1437 /**
1438  * Triggers a check if the one of the gateways have been lost or has an
1439  * ETX = infinity
1440  */
1441 void olsr_trigger_gatewayloss_check(void) {
1442   bool ipv4 = false;
1443   bool ipv6 = false;
1444
1445   if (current_ipv4_gw && current_ipv4_gw->gw) {
1446     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
1447     ipv4 = (tc == NULL || tc->path_cost >= ROUTE_COST_BROKEN);
1448   }
1449   if (current_ipv6_gw && current_ipv6_gw->gw) {
1450     struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
1451     ipv6 = (tc == NULL || tc->path_cost >= ROUTE_COST_BROKEN);
1452   }
1453
1454   if (ipv4 || ipv6) {
1455     assert(gw_handler);
1456     gw_handler->choose(ipv4, ipv6);
1457   }
1458 }
1459
1460 /*
1461  * Gateway Plugin Functions
1462  */
1463
1464 /**
1465  * Sets a new internet gateway.
1466  *
1467  * @param the chosen gateway
1468  * @param ipv4 set ipv4 gateway
1469  * @param ipv6 set ipv6 gateway
1470  * @return true if an error happened, false otherwise
1471  */
1472 bool olsr_set_inet_gateway(struct gateway_entry * chosen_gw, bool ipv4, bool ipv6) {
1473   struct gateway_entry *new_gw;
1474
1475   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
1476   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
1477   if (!ipv4 && !ipv6) {
1478     return true;
1479   }
1480
1481   new_gw = node2gateway(avl_find(&gateway_tree, &chosen_gw->originator));
1482   if (!new_gw) {
1483     /* the originator is not in the gateway tree, we can't set it as gateway */
1484     return true;
1485   }
1486
1487   /* handle IPv4 */
1488   if (ipv4 &&
1489       new_gw->ipv4 &&
1490       (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
1491       (!current_ipv4_gw || current_ipv4_gw->gw != new_gw)) {
1492     /* new gw is different than the current gw */
1493
1494     struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
1495     if (new_gw_in_list) {
1496       /* new gw is already in the gw list */
1497       assert(new_gw_in_list->tunnel);
1498       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1499       current_ipv4_gw = new_gw_in_list;
1500
1501       if (multi_gateway_mode()) {
1502         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1503       }
1504     } else {
1505       /* new gw is not yet in the gw list */
1506       char name[IFNAMSIZ];
1507       struct olsr_iptunnel_entry *new_v4gw_tunnel;
1508       struct interfaceName * interfaceName;
1509
1510       if (olsr_gw_list_full(&gw_list_ipv4)) {
1511         /* the list is full: remove the worst active gateway */
1512         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
1513         assert(worst);
1514
1515         removeGatewayFromList(&gw_list_ipv4, true, worst);
1516       }
1517
1518       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1519       new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
1520       if (new_v4gw_tunnel) {
1521         if (interfaceName) {
1522           olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->tableNr);
1523         }
1524         olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1525
1526         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1527         new_gw_in_list->gw = new_gw;
1528         new_gw_in_list->tunnel = new_v4gw_tunnel;
1529         current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
1530
1531         if (multi_gateway_mode()) {
1532           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1533         }
1534       } else {
1535         /* adding the tunnel failed, we try again in the next cycle */
1536         set_unused_iptunnel_name(new_gw);
1537         ipv4 = false;
1538       }
1539     }
1540   }
1541
1542   /* handle IPv6 */
1543   if (ipv6 &&
1544       new_gw->ipv6 &&
1545       (!current_ipv6_gw || current_ipv6_gw->gw != new_gw)) {
1546     /* new gw is different than the current gw */
1547
1548         struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
1549     if (new_gw_in_list) {
1550       /* new gw is already in the gw list */
1551       assert(new_gw_in_list->tunnel);
1552       olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
1553       current_ipv6_gw = new_gw_in_list;
1554
1555       if (multi_gateway_mode()) {
1556         doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1557       }
1558     } else {
1559       /* new gw is not yet in the gw list */
1560       char name[IFNAMSIZ];
1561       struct olsr_iptunnel_entry *new_v6gw_tunnel;
1562       struct interfaceName * interfaceName;
1563
1564       if (olsr_gw_list_full(&gw_list_ipv6)) {
1565         /* the list is full: remove the worst active gateway */
1566         struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
1567         assert(worst);
1568
1569         removeGatewayFromList(&gw_list_ipv6, false, worst);
1570       }
1571
1572       get_unused_iptunnel_name(new_gw, name, &interfaceName);
1573       new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
1574       if (new_v6gw_tunnel) {
1575         if (interfaceName) {
1576           olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->tableNr);
1577         }
1578         olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
1579
1580         new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
1581         new_gw_in_list->gw = new_gw;
1582         new_gw_in_list->tunnel = new_v6gw_tunnel;
1583         current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
1584
1585         if (multi_gateway_mode()) {
1586           doRoutesMultiGw(false, true, GW_MULTI_CHANGE_PHASE_RUNTIME);
1587         }
1588       } else {
1589         /* adding the tunnel failed, we try again in the next cycle */
1590         set_unused_iptunnel_name(new_gw);
1591         ipv6 = false;
1592       }
1593     }
1594   }
1595
1596   return !ipv4 && !ipv6;
1597 }
1598
1599 /**
1600  * @param ipv6 if set to true then the IPv6 gateway is returned, otherwise the IPv4
1601  * gateway is returned
1602  * @return a pointer to the gateway_entry of the current ipv4 internet gw or
1603  * NULL if not set.
1604  */
1605 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
1606         if (ipv6) {
1607                 return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
1608         }
1609
1610         return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
1611 }
1612
1613 /*
1614  * Process Egress Changes
1615  */
1616
1617 #define MSGW_ROUTE_ADD_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_RUNTIME ))
1618 #define MSGW_ROUTE_ADD_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_STARTUP )
1619 #define MSGW_ROUTE_DEL_ALLOWED(phase)   ((phase == GW_MULTI_CHANGE_PHASE_RUNTIME ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1620 #define MSGW_ROUTE_DEL_FORCED(phase)    ( phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)
1621 #define MSGW_ROUTE_FORCED(phase)        ((phase == GW_MULTI_CHANGE_PHASE_STARTUP ) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN))
1622
1623 /**
1624  * Determine best egress link.
1625  * The list of egress interface is ordered on priority (the declaration order),
1626  * so the function will - for multiple egress links with the same costs - set the
1627  * best egress interface to the first declared one of those.
1628  * When there is no best egress interface (that is up) then the function will
1629  * set the best egress interface to NULL.
1630  *
1631  * @param phase the phase of the change (startup/runtime/shutdown)
1632  * @return true when the best egress link changed or when any of its relevant
1633  * parameters has changed
1634  */
1635 static bool determineBestEgressLink(enum sgw_multi_change_phase phase) {
1636   bool changed = false;
1637   struct sgw_egress_if * bestEgress = olsr_cnf->smart_gw_egress_interfaces;
1638
1639   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
1640     bestEgress = NULL;
1641   } else {
1642     struct sgw_egress_if * egress_if = bestEgress;
1643     if (egress_if) {
1644       egress_if = egress_if->next;
1645     }
1646     while (egress_if) {
1647       if (egress_if->upCurrent && (egress_if->bwCurrent.costs < bestEgress->bwCurrent.costs &&
1648           isInterfaceUp(egress_if->if_index))) {
1649         bestEgress = egress_if;
1650       }
1651
1652       egress_if = egress_if->next;
1653     }
1654
1655     if (bestEgress && (!bestEgress->upCurrent || (bestEgress->bwCurrent.costs == INT64_MAX))) {
1656       bestEgress = NULL;
1657     }
1658   }
1659
1660   bestEgressLinkPrevious = bestEgressLink;
1661   bestEgressLink = bestEgress;
1662
1663   changed = (bestEgressLinkPrevious != bestEgressLink) || //
1664       (bestEgressLink && (bestEgressLink->upChanged || bestEgressLink->bwChanged));
1665
1666   if (changed || MSGW_ROUTE_FORCED(phase)) {
1667     if (!bestEgressLink || !bestEgressLink->upCurrent) {
1668       smartgw_set_uplink(olsr_cnf, 0);
1669       smartgw_set_downlink(olsr_cnf, 0);
1670     } else {
1671       smartgw_set_uplink(olsr_cnf, bestEgressLink->bwCurrent.egressUk);
1672       smartgw_set_downlink(olsr_cnf, bestEgressLink->bwCurrent.egressDk);
1673     }
1674     refresh_smartgw_netmask();
1675   }
1676
1677   return changed;
1678 }
1679
1680 /**
1681  * Determine best overall link (choose egress interface over olsrd).
1682  *
1683  * When there is no best overall link, the best overall link will be set to a
1684  * NULL egress interface.
1685  *
1686  * @param phase the phase of the change (startup/runtime/shutdown)
1687  * @return true when the best egress link changed or when any of its relevant
1688  * parameters has changed
1689  */
1690 static bool determineBestOverallLink(enum sgw_multi_change_phase phase) {
1691   struct gw_container_entry * gwContainer = (olsr_cnf->ip_version == AF_INET) ? current_ipv4_gw : current_ipv6_gw;
1692   struct gateway_entry * olsrGw = !gwContainer ? NULL : gwContainer->gw;
1693
1694   int64_t egressCosts = !bestEgressLink ? INT64_MAX : bestEgressLink->bwCurrent.costs;
1695   int64_t olsrCosts = (!olsrGw || olsrInterfacesAllDown) ? INT64_MAX : olsrGw->path_cost;
1696   int64_t bestOverallCosts = MIN(egressCosts, olsrCosts);
1697
1698   bestOverallLinkPrevious = bestOverallLink;
1699   if ((bestOverallCosts == INT64_MAX) || (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN)) {
1700     bestOverallLink.valid = false;
1701     bestOverallLink.isOlsr = false;
1702     bestOverallLink.link.egress = NULL;
1703     bestOverallLink.olsrTunnelIfIndex = 0;
1704   } else if (egressCosts <= olsrCosts) {
1705     bestOverallLink.valid = bestEgressLink;
1706     bestOverallLink.isOlsr = false;
1707     bestOverallLink.link.egress = bestEgressLink;
1708     bestOverallLink.olsrTunnelIfIndex = 0;
1709   } else {
1710     struct olsr_iptunnel_entry * tunnel;
1711
1712     assert(gwContainer);
1713
1714     tunnel = gwContainer->tunnel;
1715
1716     bestOverallLink.valid = olsrGw;
1717     bestOverallLink.isOlsr = true;
1718     bestOverallLink.link.olsr = olsrGw;
1719     bestOverallLink.olsrTunnelIfIndex = !tunnel ? 0 : tunnel->if_index;
1720   }
1721
1722   return memcmp(&bestOverallLink, &bestOverallLinkPrevious, sizeof(bestOverallLink));
1723 }
1724
1725 static bool isInterfaceUp(int if_index) {
1726   char nameBuf[IF_NAMESIZE];
1727   char * name;
1728   struct ifreq ifr;
1729
1730   name = if_indextoname(if_index, nameBuf);
1731   if (!name) {
1732     /* interface doesn't exist */
1733     return false;
1734   }
1735
1736   if (getInterfaceLinkState(name) == LINKSTATE_DOWN) {
1737     return false;
1738   }
1739
1740   memset(&ifr, 0, sizeof(struct ifreq));
1741   strscpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1742
1743   /* Get flags (and check if interface exists) */
1744   if (ioctl(olsr_cnf->ioctl_s, SIOCGIFFLAGS, &ifr) < 0) {
1745     return false;
1746   }
1747
1748   if (ifr.ifr_flags & IFF_UP) {
1749     return true;
1750   }
1751
1752   return false;
1753 }
1754
1755 /**
1756  * Program a route (add or remove) through netlink
1757  *
1758  * @param add true to add the route, false to remove it
1759  * @param route the route
1760  * @param linkName the human readable id of the route, used in error reports in
1761  * the syslog
1762  */
1763 static void programRoute(bool add, struct sgw_route_info * route, const char * linkName) {
1764   if (!route || !route->active) {
1765     return;
1766   }
1767
1768   if (!isInterfaceUp(route->route.if_index)) {
1769     return;
1770   }
1771
1772   if (olsr_new_netlink_route( //
1773       route->route.family, //
1774       route->route.rttable, //
1775       route->route.flags, //
1776       route->route.scope, //
1777       route->route.if_index, //
1778       route->route.metric, //
1779       route->route.protocol, //
1780       !route->route.srcSet ? NULL : &route->route.srcStore, //
1781       !route->route.gwSet ? NULL : &route->route.gwStore, //
1782       !route->route.dstSet ? NULL : &route->route.dstStore, //
1783       add, //
1784       route->route.del_similar, //
1785       route->route.blackhole //
1786       )) {
1787     olsr_syslog(OLSR_LOG_ERR, "Could not %s a route for the %s %s", !add ? "remove" : "add", !add ? "previous" : "current", linkName);
1788     route->active = false;
1789   } else {
1790     route->active = add;
1791   }
1792 }
1793
1794 /**
1795  * Determine the best overall egress/olsr interface routes.
1796  *
1797  * These are a set of 2 /1 routes to override any default gateway
1798  * routes that are setup through other means such as a DHCP client.
1799  *
1800  * @param routes a pointer to the array of 2 /1 routes where to store the
1801  * newly determined routes
1802  */
1803 static void determineBestOverallLinkRoutes(struct sgw_route_info * routes) {
1804   int ifIndex = 0;
1805   union olsr_ip_addr * gw = NULL;
1806   int i;
1807   if (!bestOverallLink.valid) {
1808     /* there is no current best overall link */
1809   } else if (!bestOverallLink.isOlsr) {
1810     /* current best overall link is an egress interface */
1811     struct sgw_egress_if * egress = bestOverallLink.link.egress;
1812     if (egress) {
1813       ifIndex = egress->if_index;
1814       if (egress->bwCurrent.gatewaySet) {
1815         gw = &egress->bwCurrent.gateway;
1816       }
1817     }
1818   } else {
1819     /* current best overall link is an olsr tunnel interface */
1820     struct gw_container_entry * gwContainer = current_ipv4_gw;
1821     struct olsr_iptunnel_entry * tunnel = !gwContainer ? NULL : gwContainer->tunnel;
1822
1823     if (tunnel) {
1824       ifIndex = tunnel->if_index;
1825     }
1826   }
1827
1828   if (!ifIndex) {
1829     for (i = 0; i < 2; i++) {
1830       routes[i].active = false;
1831     }
1832     return;
1833   }
1834
1835   for (i = 0; i < 2; i++) {
1836     memset(&routes[i], 0, sizeof(routes[i]));
1837     routes[i].active = true;
1838     routes[i].route.family = AF_INET;
1839     routes[i].route.rttable = olsr_cnf->rt_table;
1840     routes[i].route.flags = 0;
1841     routes[i].route.scope = !gw ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
1842     routes[i].route.if_index = ifIndex;
1843     routes[i].route.metric = 0;
1844     routes[i].route.protocol = RTPROT_STATIC;
1845     routes[i].route.srcSet = false;
1846     routes[i].route.gwSet = false;
1847     if (gw) {
1848       routes[i].route.gwSet = true;
1849       routes[i].route.gwStore = *gw;
1850     }
1851     routes[i].route.dstSet = true;
1852     routes[i].route.dstStore = ipv4_slash_1_routes[i];
1853     routes[i].route.del_similar = false;
1854     routes[i].route.blackhole = false;
1855   }
1856 }
1857
1858 /**
1859  * Setup default gateway override routes: a set of 2 /1 routes for the best
1860  * overall link
1861  *
1862  * @param phase the phase of the change (startup/runtime/shutdown)
1863  */
1864 static void setupDefaultGatewayOverrideRoutes(enum sgw_multi_change_phase phase) {
1865   bool force = MSGW_ROUTE_FORCED(phase);
1866   int i;
1867
1868   if (!bestOverallLinkPrevious.valid && !bestOverallLink.valid && !force) {
1869     return;
1870   }
1871
1872   memcpy(&bestOverallLinkPreviousRoutes, &bestOverallLinkRoutes, sizeof(bestOverallLinkPreviousRoutes));
1873
1874   determineBestOverallLinkRoutes(bestOverallLinkRoutes);
1875
1876   for (i = 0; i < 2; i++) {
1877     bool routeChanged = //
1878         (bestOverallLinkPreviousRoutes[i].active != bestOverallLinkRoutes[i].active) || //
1879         memcmp(&bestOverallLinkPreviousRoutes[i].route, &bestOverallLinkRoutes[i].route, sizeof(bestOverallLinkRoutes[i].route));
1880
1881     if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
1882       programRoute(false, &bestOverallLinkPreviousRoutes[i], "overall best gateway");
1883     }
1884
1885     if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
1886       programRoute(true, &bestOverallLinkRoutes[i], "overall best gateway");
1887     }
1888   }
1889 }
1890
1891 /**
1892  * Determine the best egress interface route.
1893  *
1894  * @param route a pointer to the an route where to store the
1895  * newly determined route
1896  * @param networkRoute true when the route is a network route (not an internet
1897  * route)
1898  * @param if_index the index of the interface that the route is for
1899  * @param gw the gateway for the route
1900  * @param dst the destination for the route
1901  * @param table the routing table for the route
1902  */
1903 static void determineEgressLinkRoute( //
1904     struct sgw_route_info * route, //
1905     bool networkRoute, //
1906     int if_index, //
1907     union olsr_ip_addr * gw, //
1908     struct olsr_ip_prefix * dst, //
1909     int table) {
1910   // default route
1911   // ----: ip route replace|delete blackhole default                          table 90: !egress_if               (1)
1912   // ppp0: ip route replace|delete           default                 dev ppp0 table 90:  egress_if && dst && !gw (2)
1913   // eth1: ip route replace|delete           default via 192.168.0.1 dev eth1 table 90:  egress_if && dst &&  gw (3)
1914
1915   // network route
1916   // eth1: ip route replace|delete to 192.168.0.0/24                 dev eth1 table 90:  egress_if && dst && !gw (2*)
1917
1918   memset(route, 0, sizeof(*route));
1919   if (if_index <= 0) { /* 1 */
1920     route->active = true;
1921     route->route.family = AF_INET;
1922     route->route.rttable = table;
1923     route->route.flags = RTNH_F_ONLINK;
1924     route->route.scope = RT_SCOPE_UNIVERSE;
1925     route->route.if_index = 0;
1926     route->route.metric = 0;
1927     route->route.protocol = RTPROT_STATIC;
1928     route->route.srcSet = false;
1929     route->route.gwSet = false;
1930     route->route.dstSet = false;
1931     if (dst) {
1932       route->route.dstSet = true;
1933       route->route.dstStore = *dst;
1934     }
1935     route->route.del_similar = false;
1936     route->route.blackhole = true;
1937   } else if (dst && !gw) { /* 2 */
1938     route->active = true;
1939     route->route.family = AF_INET;
1940     route->route.rttable = table;
1941     route->route.flags = !networkRoute ? RTNH_F_ONLINK /* 2 */ : 0 /* 2* */;
1942     route->route.scope = RT_SCOPE_LINK;
1943     route->route.if_index = if_index;
1944     route->route.metric = 0;
1945     route->route.protocol = RTPROT_STATIC;
1946     route->route.srcSet = false;
1947     route->route.gwSet = false;
1948     route->route.dstSet = true;
1949     route->route.dstStore = *dst;
1950     route->route.del_similar = false;
1951     route->route.blackhole = false;
1952   } else if (dst && gw) { /* 3 */
1953     route->active = true;
1954     route->route.family = AF_INET;
1955     route->route.rttable = table;
1956     route->route.flags = 0;
1957     route->route.scope = RT_SCOPE_UNIVERSE;
1958     route->route.if_index = if_index;
1959     route->route.metric = 0;
1960     route->route.protocol = RTPROT_STATIC;
1961     route->route.srcSet = false;
1962     route->route.gwSet = true;
1963     route->route.gwStore = *gw;
1964     route->route.dstSet = true;
1965     route->route.dstStore = *dst;
1966     route->route.del_similar = false;
1967     route->route.blackhole = false;
1968   } else {
1969     /* no destination set */
1970     route->active = false;
1971     olsr_syslog(OLSR_LOG_ERR, "No route destination specified in %s", __FUNCTION__);
1972     return;
1973   }
1974 }
1975
1976 /**
1977  * Setup default route for the best egress interface
1978  *
1979  * When there is no best egress link, then a blackhole route is setup to prevent
1980  * looping smart gateway tunnel traffic.
1981  *
1982  * @param phase the phase of the change (startup/runtime/shutdown)
1983  */
1984 static void configureBestEgressLinkRoute(enum sgw_multi_change_phase phase) {
1985   bool force = MSGW_ROUTE_FORCED(phase);
1986
1987   /*
1988    * bestEgressLinkPrevious  bestEgressLink  Action
1989    *                   NULL            NULL  -
1990    *                   NULL               x  add new route
1991    *                      x            NULL  remove old route
1992    *                      x               x  remove old route && add new routes
1993    */
1994
1995   if (!bestEgressLinkPrevious && !bestEgressLink && !force) {
1996     return;
1997   }
1998
1999   memcpy(&bestEgressLinkPreviousRoute, &bestEgressLinkRoute, sizeof(bestEgressLinkPreviousRoute));
2000
2001   determineEgressLinkRoute( //
2002       &bestEgressLinkRoute, // route
2003       false, // networkRoute
2004       !bestEgressLink ? 0 : bestEgressLink->if_index, // if_index
2005       (!bestEgressLink || !bestEgressLink->bwCurrent.gatewaySet) ? NULL : &bestEgressLink->bwCurrent.gateway, // gw
2006       &ipv4_slash_0_route, // dst
2007       olsr_cnf->smart_gw_offset_tables // table
2008       );
2009
2010   {
2011     bool routeChanged = //
2012         (bestEgressLinkPreviousRoute.active != bestEgressLinkRoute.active) || //
2013         memcmp(&bestEgressLinkPreviousRoute.route, &bestEgressLinkRoute.route, sizeof(bestEgressLinkRoute.route));
2014
2015     if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2016       programRoute(false, &bestEgressLinkPreviousRoute, "best egress link");
2017     }
2018
2019     if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2020       programRoute(true, &bestEgressLinkRoute, "best egress link");
2021     }
2022   }
2023 }
2024
2025 /**
2026  * Setup network (when relevant) and default routes for the every egress
2027  * interface
2028  *
2029  * @param phase the phase of the change (startup/runtime/shutdown)
2030  */
2031 static void configureEgressLinkRoutes(enum sgw_multi_change_phase phase) {
2032   bool force = MSGW_ROUTE_FORCED(phase);
2033
2034   /* egress interfaces */
2035   struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2036   while (egress_if) {
2037     if (!egress_if->bwNetworkChanged && !egress_if->bwGatewayChanged && !egress_if->upChanged && !force) {
2038       /* no relevant change */
2039       goto next;
2040     }
2041
2042     /* network route */
2043     if (egress_if->bwNetworkChanged || force) {
2044       bool routeChanged;
2045
2046       struct sgw_route_info networkRoutePrevious = egress_if->networkRouteCurrent;
2047
2048       if (!egress_if->bwCurrent.networkSet || !egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
2049         memset(&egress_if->networkRouteCurrent, 0, sizeof(egress_if->networkRouteCurrent));
2050         egress_if->networkRouteCurrent.active = false;
2051       } else {
2052         determineEgressLinkRoute( //
2053             &egress_if->networkRouteCurrent, // route
2054             true,// networkRoute
2055             egress_if->if_index, // if_index
2056             NULL, // gw
2057             &egress_if->bwCurrent.network, // dst
2058             egress_if->tableNr // table
2059             );
2060       }
2061
2062       routeChanged = //
2063           (networkRoutePrevious.active != egress_if->networkRouteCurrent.active) || //
2064           memcmp(&networkRoutePrevious.route, &egress_if->networkRouteCurrent.route, sizeof(egress_if->networkRouteCurrent.route));
2065
2066       if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2067         programRoute(false, &networkRoutePrevious, egress_if->name);
2068       }
2069
2070       if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2071         programRoute(true, &egress_if->networkRouteCurrent, egress_if->name);
2072       }
2073     }
2074
2075     /* default route */
2076     if (egress_if->bwGatewayChanged || force) {
2077       bool routeChanged;
2078
2079       struct sgw_route_info egressRoutePrevious = egress_if->egressRouteCurrent;
2080
2081       if (!egress_if->upCurrent || (egress_if->bwCurrent.costs == INT64_MAX)) {
2082         memset(&egress_if->egressRouteCurrent, 0, sizeof(egress_if->egressRouteCurrent));
2083         egress_if->egressRouteCurrent.active = false;
2084       } else {
2085         determineEgressLinkRoute( //
2086             &egress_if->egressRouteCurrent, // route
2087             false,// networkRoute
2088             egress_if->if_index, // if_index
2089             !egress_if->bwCurrent.gatewaySet ? NULL : &egress_if->bwCurrent.gateway, // gw
2090             &ipv4_slash_0_route, // dst
2091             egress_if->tableNr // table
2092             );
2093       }
2094
2095       routeChanged = //
2096           (egressRoutePrevious.active != egress_if->egressRouteCurrent.active) || //
2097           memcmp(&egressRoutePrevious, &egress_if->egressRouteCurrent, sizeof(egress_if->egressRouteCurrent));
2098
2099        if ((routeChanged || MSGW_ROUTE_DEL_FORCED(phase)) && MSGW_ROUTE_DEL_ALLOWED(phase)) {
2100          programRoute(false, &egressRoutePrevious, egress_if->name);
2101        }
2102
2103        if ((routeChanged || MSGW_ROUTE_ADD_FORCED(phase)) && MSGW_ROUTE_ADD_ALLOWED(phase)) {
2104          programRoute(true, &egress_if->egressRouteCurrent, egress_if->name);
2105        }
2106     }
2107
2108     next: egress_if = egress_if->next;
2109   }
2110 }
2111
2112 /*
2113  * Multi-Smart-Gateway Status Overview
2114  */
2115
2116 #define IPNONE    ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0"     : "::")
2117 #define MASKNONE  ((olsr_cnf->ip_version == AF_INET) ? "0.0.0.0/0"   : "::/0")
2118 #define IPLOCAL   ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.1"   : "::1")
2119 #define MASKLOCAL ((olsr_cnf->ip_version == AF_INET) ? "127.0.0.0/8" : "::1/128")
2120
2121 /**
2122  * Print a timestamp to a file
2123  *
2124  * @param f the file
2125  */
2126 static void printDate(FILE * f) {
2127   time_t timer;
2128   struct tm* tm_info;
2129   char buffer[64];
2130
2131   time(&timer);
2132   tm_info = localtime(&timer);
2133
2134   strftime(buffer, sizeof(buffer), "%B %d, %Y at %H:%M:%S", tm_info);
2135   fprintf(f, "%s", buffer);
2136 }
2137
2138 bool isEgressSelected(struct sgw_egress_if * egress_if) {
2139   return bestOverallLink.valid && !bestOverallLink.isOlsr && (bestOverallLink.link.egress == egress_if);
2140 }
2141
2142 /**
2143  * Write multi-smart-gateway status file
2144  *
2145  * <pre>
2146  * # multi-smart-gateway status overview, generated on October 10, 2014 at 08:27:15
2147  *
2148  * #Originator Prefix       Uplink  Downlink  PathCost  Type    Interface  Gateway      Cost
2149  *  127.0.0.1  127.0.0.0/8  0       0         INFINITE  egress  ppp0       0.0.0.0      INFINITE
2150  *  127.0.0.1  127.0.0.0/8  0       0         INFINITE  egress  eth1       192.168.0.1  INFINITE
2151  * *10.0.0.1   0.0.0.0/0    290     1500      0.000     olsr    tnl_4096   10.0.0.1     34.325
2152  * </pre>
2153  *
2154  * @param phase the phase of the change (startup/runtime/shutdown)
2155  */
2156 static void writeProgramStatusFile(enum sgw_multi_change_phase phase) {
2157   /*                                # Origi Prefx Upln Dwnl PthC Type Intfc Gtway Cost */
2158   static const char * fmt_header = "%s%-15s %-18s %-9s %-9s %-8s %-6s %-16s %-15s %s\n";
2159   static const char * fmt_values = "%s%-15s %-18s %-9u %-9u %-8s %-6s %-16s %-15s %s\n";
2160
2161   char * fileName = olsr_cnf->smart_gw_status_file;
2162   FILE * fp = NULL;
2163
2164   if (!fileName || (fileName[0] == '\0')) {
2165     return;
2166   }
2167
2168   if (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN) {
2169     remove(fileName);
2170     return;
2171   }
2172
2173   fp = fopen(fileName, "w");
2174   if (!fp) {
2175     olsr_syslog(OLSR_LOG_ERR, "Could not write to %s", fileName);
2176     return;
2177   }
2178
2179   fprintf(fp, "# OLSRd Multi-Smart-Gateway Status Overview\n");
2180   fprintf(fp, "# Generated on ");
2181   printDate(fp);
2182   fprintf(fp, "\n\n");
2183
2184   /* header */
2185   fprintf(fp, fmt_header, "#", "Originator", "Prefix", "Uplink", "Downlink", "PathCost", "Type", "Interface", "Gateway", "Cost");
2186
2187   /* egress interfaces */
2188   {
2189     struct lqtextbuffer lnkbuf;
2190     struct gwtextbuffer gwbuf;
2191     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2192     while (egress_if) {
2193       struct ipaddr_str gwStr;
2194       const char * gw = !egress_if->bwCurrent.gatewaySet ? IPNONE : olsr_ip_to_string(&gwStr, &egress_if->bwCurrent.gateway);
2195       fprintf(fp, fmt_values, //
2196           isEgressSelected(egress_if) ? "*" : " ", //selected
2197           IPLOCAL, // Originator
2198           MASKLOCAL, // Prefix
2199           egress_if->bwCurrent.egressUk, // Uplink
2200           egress_if->bwCurrent.egressDk, // Downlink
2201           get_linkcost_text(egress_if->bwCurrent.path_cost, true, &lnkbuf), // PathCost
2202           "egress", // Type
2203           egress_if->name, // Interface
2204           gw, // Gateway
2205           get_gwcost_text(egress_if->bwCurrent.costs, &gwbuf) // Cost
2206           );
2207
2208       egress_if = egress_if->next;
2209     }
2210   }
2211
2212   /* olsr */
2213   {
2214     struct lqtextbuffer lnkbuf;
2215     struct gwtextbuffer gwbuf;
2216     struct gateway_entry * current_gw = olsr_get_inet_gateway((olsr_cnf->ip_version == AF_INET) ? false : true);
2217     struct interfaceName * sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
2218
2219     int i = 0;
2220     for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
2221       struct interfaceName * node = &sgwTunnelInterfaceNames[i];
2222       struct gateway_entry * gw = node->gw;
2223
2224       if (gw) {
2225         struct tc_entry* tc = olsr_lookup_tc_entry(&gw->originator);
2226
2227         struct ipaddr_str originatorStr;
2228         const char * originator = olsr_ip_to_string(&originatorStr, &gw->originator);
2229         struct ipaddr_str prefixIpStr;
2230         const char * prefixIPStr = olsr_ip_to_string(&prefixIpStr, &gw->external_prefix.prefix);
2231         uint8_t prefix_len = gw->external_prefix.prefix_len;
2232         struct ipaddr_str tunnelGwStr;
2233         const char * tunnelGw = olsr_ip_to_string(&tunnelGwStr, &gw->originator);
2234         bool selected = bestOverallLink.valid && bestOverallLink.isOlsr && current_gw && (current_gw == gw);
2235
2236         char prefix[strlen(prefixIPStr) + 1 + 3 + 1];
2237         snprintf(prefix, sizeof(prefix), "%s/%d", prefixIPStr, prefix_len);
2238
2239         fprintf(fp, fmt_values, //
2240             selected ? "*" : " ", // selected
2241             originator, // Originator
2242             prefix, // Prefix IP
2243             gw->uplink, // Uplink
2244             gw->downlink, // Downlink
2245             get_linkcost_text(!tc ? ROUTE_COST_BROKEN : tc->path_cost, true, &lnkbuf), // PathCost
2246             "olsr", // Type
2247             node->name, // Interface
2248             tunnelGw, // Gateway
2249             get_gwcost_text(gw->path_cost, &gwbuf) // Cost
2250         );
2251       }
2252     }
2253   }
2254
2255   fclose(fp);
2256 }
2257
2258 /**
2259  * Report a new gateway with its most relevant parameters in the syslog
2260  */
2261 static void reportNewGateway(void) {
2262   if (!bestOverallLink.valid) {
2263     /* best overall link is invalid (none) */
2264     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: none");
2265     return;
2266   }
2267
2268   if (!bestOverallLink.isOlsr) {
2269     /* best overall link is an egress interface */
2270     struct lqtextbuffer lqbuf;
2271     struct ipaddr_str gwStr;
2272     const char * gw = !bestOverallLink.link.egress->bwCurrent.gatewaySet ? //
2273         NULL : //
2274         olsr_ip_to_string(&gwStr, &bestOverallLink.link.egress->bwCurrent.gateway);
2275     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%s", //
2276         bestOverallLink.link.egress->name, //
2277         !gw ? "" : "via ", //
2278         !gw ? "" : gwStr.buf, //
2279         !gw ? "" : " ", //
2280         bestOverallLink.link.egress->bwCurrent.egressUk, //
2281         bestOverallLink.link.egress->bwCurrent.egressDk, //
2282         get_linkcost_text(bestOverallLink.link.egress->bwCurrent.path_cost, true, &lqbuf));
2283     return;
2284   }
2285
2286   /* best overall link is an olsr (tunnel) interface */
2287   {
2288     struct lqtextbuffer lqbuf;
2289     struct tc_entry* tc = olsr_lookup_tc_entry(&bestOverallLink.link.olsr->originator);
2290
2291     char ifNameBuf[IFNAMSIZ];
2292     const char * ifName = if_indextoname(bestOverallLink.olsrTunnelIfIndex, ifNameBuf);
2293
2294     struct ipaddr_str gwStr;
2295     const char * gw = olsr_ip_to_string(&gwStr, &bestOverallLink.link.olsr->originator);
2296
2297     olsr_syslog(OLSR_LOG_INFO, "New gateway selected: %s %s%s%swith uplink/downlink/pathcost = %u/%u/%s", //
2298         !ifName ? "none" : ifName, //
2299         !gw ? "" : "via ", //
2300         !gw ? "" : gwStr.buf, //
2301         !gw ? "" : " ", //
2302         bestOverallLink.link.olsr->uplink, //
2303         bestOverallLink.link.olsr->downlink, //
2304         get_linkcost_text(!tc ? ROUTE_COST_BROKEN : tc->path_cost, true, &lqbuf));
2305   }
2306 }
2307
2308 /**
2309  * Process changes that are relevant to egress interface: changes to the
2310  * egress interfaces themselves and to the smart gateway that is chosen by olsrd
2311  *
2312  * @param egressChanged true when an egress interface changed
2313  * @param olsrChanged true when the smart gateway changed
2314  * @param phase the phase of the change (startup/runtime/shutdown)
2315  */
2316 void doRoutesMultiGw(bool egressChanged, bool olsrChanged, enum sgw_multi_change_phase phase) {
2317   bool bestEgressChanged = false;
2318   bool bestOverallChanged = false;
2319   bool force = MSGW_ROUTE_FORCED(phase);
2320
2321   assert( //
2322       (phase == GW_MULTI_CHANGE_PHASE_STARTUP) || //
2323       (phase == GW_MULTI_CHANGE_PHASE_RUNTIME) || //
2324       (phase == GW_MULTI_CHANGE_PHASE_SHUTDOWN));
2325
2326   if (allOlsrInterfacesDown(olsr_cnf) != olsrInterfacesAllDown) {
2327     olsrInterfacesAllDown = !olsrInterfacesAllDown;
2328     olsrChanged = true;
2329   }
2330
2331   if (!egressChanged && !olsrChanged && !force) {
2332     goto out;
2333   }
2334
2335   assert(multi_gateway_mode());
2336
2337   if (egressChanged || force) {
2338     bestEgressChanged = determineBestEgressLink(phase);
2339     configureEgressLinkRoutes(phase);
2340   }
2341
2342   if (olsrChanged || bestEgressChanged || force) {
2343     bestOverallChanged = determineBestOverallLink(phase);
2344   }
2345
2346   if (bestOverallChanged || force) {
2347     setupDefaultGatewayOverrideRoutes(phase);
2348   }
2349
2350   if (bestEgressChanged || force) {
2351     configureBestEgressLinkRoute(phase);
2352   }
2353
2354   if (bestOverallChanged || force) {
2355     reportNewGateway();
2356   }
2357
2358   writeProgramStatusFile(phase);
2359
2360   out: if (egressChanged) {
2361     /* clear the 'changed' flags of egress interfaces */
2362     struct sgw_egress_if * egress_if = olsr_cnf->smart_gw_egress_interfaces;
2363     while (egress_if) {
2364       egress_if->upChanged = false;
2365
2366       egress_if->bwCostsChanged = false;
2367       egress_if->bwNetworkChanged = false;
2368       egress_if->bwGatewayChanged = false;
2369       egress_if->bwChanged = false;
2370
2371       egress_if = egress_if->next;
2372     }
2373   }
2374 }
2375
2376 #endif /* __linux__ */