Merge branch 'stable' into tunnel
[olsrd.git] / src / gateway_default_handler.c
1 /*
2  * gateway_default_handler.c
3  *
4  *  Created on: Jan 29, 2010
5  *      Author: rogge
6  */
7
8 #include "defs.h"
9 #include "gateway.h"
10 #include "gateway_default_handler.h"
11 #include "scheduler.h"
12 #include "tc_set.h"
13
14 #include "assert.h"
15
16 static uint32_t gw_def_nodecount, gw_def_stablecount;
17 static bool gw_def_finished_ipv4, gw_def_finished_ipv6;
18
19 static struct timer_entry *gw_def_timer;
20
21 static void gw_default_startup_handler(void);
22 void olsr_gw_default_lookup_gateway(bool ipv4, bool ipv6);
23 static void gw_default_update_handler(struct gateway_entry *);
24 static void gw_default_delete_handler(struct gateway_entry *);
25
26 static struct olsr_gw_handler gw_def_handler = {
27   &gw_default_startup_handler,
28   &olsr_gw_default_lookup_gateway,
29   &gw_default_update_handler,
30   &gw_default_delete_handler
31 };
32
33 /**
34  * Look through the gateway list and select the best gateway
35  * depending on the distance to this router
36  */
37 static void gw_default_choose_gateway(void) {
38   struct tc_entry *tc;
39   struct gateway_entry *inet_ipv4, *inet_ipv6;
40   olsr_linkcost cost_ipv4, cost_ipv6;
41   struct gateway_entry *gw;
42   bool dual;
43
44   cost_ipv4 = UINT32_MAX;
45   cost_ipv6 = UINT32_MAX;
46
47   inet_ipv4 = NULL;
48   inet_ipv6 = NULL;
49
50   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
51     /* gateways should not exist without tc entry */
52     if ((tc = olsr_lookup_tc_entry(&gw->originator)) == NULL) {
53       continue;
54     }
55
56     if (!gw_def_finished_ipv4 && gw->ipv4 && gw->ipv4nat == olsr_cnf->smart_gw_allow_nat && tc->path_cost < cost_ipv4) {
57       inet_ipv4 = gw;
58     }
59     if (!gw_def_finished_ipv6 && gw->ipv6 && tc->path_cost < cost_ipv6) {
60       inet_ipv6 = gw;
61     }
62   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
63
64   /* found an IPv4 gateway ? */
65   gw_def_finished_ipv4 |= inet_ipv4 != NULL;
66   gw_def_finished_ipv6 |= inet_ipv6 != NULL;
67   dual = inet_ipv4 == inet_ipv6;
68   if (inet_ipv4) {
69     olsr_set_inet_gateway(&inet_ipv4->originator, true, dual, false);
70   }
71   if (inet_ipv6 && !dual) {
72     olsr_set_inet_gateway(&inet_ipv6->originator, false, true, false);
73   }
74
75   /* finished ? */
76   if (gw_def_finished_ipv4 && gw_def_finished_ipv6) {
77     olsr_stop_timer(gw_def_timer);
78     gw_def_timer = NULL;
79   }
80 }
81
82 /* timer for laze gateway selection */
83 static void gw_default_timer(void *unused __attribute__ ((unused))) {
84   if (tc_tree.count < gw_def_nodecount) {
85     gw_def_stablecount++;
86   }
87   else {
88     gw_def_nodecount = tc_tree.count;
89     gw_def_stablecount = 0;
90   }
91
92   if (gw_def_stablecount >= GW_DEFAULT_STABLE_COUNT) {
93     gw_default_choose_gateway();
94   }
95 }
96
97 /* gateway handler callbacks */
98 static void gw_default_startup_handler(void) {
99   olsr_set_timer(&gw_def_timer, GW_DEFAULT_TIMER_INTERVAL, 0, true, &gw_default_timer, NULL, 0);
100 }
101
102 static void gw_default_update_handler(struct gateway_entry *gw) {
103   bool v4changed, v6changed;
104
105   v4changed = gw == olsr_get_inet_gateway(false)
106       && (!gw->ipv4 || (gw->ipv4nat && !olsr_cnf->smart_gw_allow_nat));
107   v6changed = gw == olsr_get_inet_gateway(true) && !gw->ipv6;
108
109   olsr_gw_default_lookup_gateway(v4changed, v6changed);
110 }
111
112 static void gw_default_delete_handler(struct gateway_entry *gw) {
113   bool isv4, isv6;
114
115   isv4 = gw == olsr_get_inet_gateway(false);
116   isv6 = gw == olsr_get_inet_gateway(true);
117
118   if (gw != NULL && (isv4 || isv6)) {
119     olsr_gw_default_lookup_gateway(isv4, isv6);
120   }
121 }
122
123 /**
124  * initialization of default gateway handler
125  */
126 void olsr_gw_default_init(void) {
127   /* initialize values */
128   gw_def_timer = NULL;
129   gw_def_finished_ipv4 = false;
130   gw_def_finished_ipv6 = false;
131   gw_def_nodecount = 0;
132   gw_def_stablecount = 0;
133   gw_def_timer = NULL;
134
135   /* setup default handler */
136   olsr_set_inetgw_handler(&gw_def_handler);
137 }
138
139 /**
140  * Lookup a new gateway based on distance metric
141  *
142  * @param ipv4 lookup new v4 gateway
143  * @param ipv6 lookup new v6 gateway
144  */
145 void olsr_gw_default_lookup_gateway(bool ipv4, bool ipv6) {
146   if (ipv4) {
147     /* get new ipv4 GW if we use OLSRv4 or NIIT */
148     gw_def_finished_ipv4 = olsr_cnf->ip_version == AF_INET6 && !olsr_cnf->use_niit;
149   }
150   if (ipv6) {
151     /* get new ipv6 GW if we use OLSRv6 */
152     gw_def_finished_ipv6 = olsr_cnf->ip_version == AF_INET;
153   }
154
155   if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
156     gw_default_choose_gateway();
157   }
158 }