Merge branch 'stable' into tunnel
[olsrd.git] / src / gateway.c
1 /*
2  * gateway.c
3  *
4  *  Created on: 05.01.2010
5  *      Author: henning
6  */
7
8 #include "common/avl.h"
9 #include "defs.h"
10 #include "ipcalc.h"
11 #include "olsr.h"
12 #include "olsr_cfg.h"
13 #include "olsr_cookie.h"
14 #include "scheduler.h"
15 #include "gateway_default_handler.h"
16 #include "gateway.h"
17
18 #include "assert.h"
19
20 struct avl_tree gateway_tree;
21
22 static struct olsr_cookie_info *gw_mem_cookie = NULL;
23 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
24 static struct gateway_entry *current_ipv4_gw, *current_ipv6_gw;
25 static struct olsr_gw_handler *gw_handler;
26
27 /**
28  * Reconstructs an uplink/downlink speed value from the encoded
29  * 1 byte transport value (3 bit mantissa, 5 bit exponent)
30  * @param value
31  * @return
32  */
33 static uint32_t
34 deserialize_gw_speed(uint8_t value) {
35   uint32_t speed, exp;
36
37   speed = (value >> 3)+1;
38   exp = value & 7;
39   while (exp-- > 0) {
40     speed *= 10;
41   }
42   return speed;
43 }
44
45 /**
46  * Convert an uplink/downlink speed into an exponential encoded
47  * transport value (1 byte, 3 bit mantissa and 5 bit exponent)
48  * @param value uplink/downlink speed in kbit/s
49  * @return encoded byte value
50  */
51 static uint8_t
52 serialize_gw_speed(uint32_t speed) {
53   uint8_t exp = 0;
54
55   if (speed == 0 || speed > 320000000) {
56     return 0;
57   }
58
59   while (speed > 32 || (speed % 10) == 0) {
60     speed /= 10;
61     exp ++;
62   }
63   return ((speed-1) << 3) | exp;
64 }
65
66 /**
67  * Initialize gateway system
68  */
69 void
70 olsr_init_gateways(void) {
71   uint8_t *ip;
72   gw_mem_cookie = olsr_alloc_cookie("Gateway cookie", OLSR_COOKIE_TYPE_MEMORY);
73   olsr_cookie_set_memory_size(gw_mem_cookie, sizeof(struct gateway_entry));
74
75   avl_init(&gateway_tree, avl_comp_default);
76   current_ipv4_gw = NULL;
77   current_ipv6_gw = NULL;
78
79   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
80
81   if (olsr_cnf->smart_gw_active) {
82     union olsr_ip_addr gw_net;
83     memset(&gw_net, 0, sizeof(gw_net));
84
85     ip = (uint8_t *) &smart_gateway_netmask;
86
87     if (olsr_cnf->smart_gw_uplink > 0 || olsr_cnf->smart_gw_downlink > 0) {
88       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
89       ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
90       ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
91     }
92     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
93       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
94       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
95       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
96     }
97   }
98
99   /*
100    * initialize default gateway handler,
101    * can be overwritten with olsr_set_inetgw_handler
102    */
103   olsr_gw_default_init();
104 }
105
106 /**
107  * Triggers the first lookup of an gateway. This lookup might
108  * take some time to wait for routing/gateway information.
109  */
110 void
111 olsr_trigger_inetgw_startup(void) {
112   gw_handler->handle_startup();
113 }
114
115 /**
116  * Triggers an instant gateway selection based on the current data
117  * @param ipv4 trigger a ipv4 gateway lookup
118  * @param ipv6 trigger a ipv6 gateway lookup
119  * @return 0 if successful, -1 otherwise
120  */
121 int
122 olsr_trigger_inetgw_selection(bool ipv4, bool ipv6) {
123   gw_handler->select_gateway(ipv4, ipv6);
124   return ((ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL)) ? -1 : 0;
125 }
126
127 /**
128  * Set a new gateway handler. Do only call this once during startup from
129  * a plugin to overwrite the default handler.
130  * @param h pointer to gateway handler struct
131  */
132 void
133 olsr_set_inetgw_handler(struct olsr_gw_handler *h) {
134   gw_handler = h;
135 }
136
137 /**
138  * Sets a new internet gateway.
139  * An external set command might trigger an internal one if
140  * address is not a legal gateway.
141  *
142  * @param originator ip address of the node with the new gateway
143  * @param ipv4 set ipv4 gateway
144  * @param ipv6 set ipv6 gateway
145  * @param external true if change was triggered directly by an user,
146  *   false if triggered by automatic lookup.
147  * @return 0 if successful, -1 otherwise
148  */
149 int
150 olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool external) {
151   struct gateway_entry *entry;
152
153   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
154   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
155
156   entry = olsr_find_gateway_entry(originator);
157   if (entry != NULL) {
158     if (ipv4 && entry->ipv4 && (!entry->ipv4nat || olsr_cnf->smart_gw_allow_nat)) {
159       /* valid ipv4 gateway */
160       current_ipv4_gw = entry;
161       ipv4 = false;
162     }
163     if (ipv6 && entry->ipv6) {
164       /* valid ipv6 gateway */
165       current_ipv6_gw = entry;
166       ipv6 = false;
167     }
168   }
169
170   /* still gateway missing ? */
171   if (ipv4 || ipv6) {
172     return external ? olsr_trigger_inetgw_selection(ipv4, ipv6) : -1;
173   }
174   return 0;
175 }
176
177 /**
178  * returns the gateway_entry of the current internet gw.
179  * @param ipv6 true to lookup ipv6 gateway, false to lookup ipv4
180  * @return pointer to gateway_entry or NULL if not set
181  */
182 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
183   return ipv6 ? current_ipv6_gw : current_ipv4_gw;
184 }
185
186 /**
187  * @param originator
188  * @return gateway_entry for corresponding router
189  */
190 struct gateway_entry *
191 olsr_find_gateway_entry(union olsr_ip_addr *originator) {
192   struct avl_node *node = avl_find(&gateway_tree, originator);
193
194   return node == NULL ? NULL : node2gateway(node);
195 }
196
197 /**
198  * update a gateway_entry based on data received from a HNA
199  * @param originator ip of the source of the HNA
200  * @param mask netmask of the HNA
201  * @param prefixlen of the HNA
202  */
203 void
204 olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen) {
205   struct gateway_entry *gw;
206   uint8_t *ptr;
207
208   ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
209
210   gw = olsr_find_gateway_entry(originator);
211   if (!gw) {
212     gw = olsr_cookie_malloc(gw_mem_cookie);
213
214     gw->originator = *originator;
215     gw->node.key = &gw->originator;
216
217     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
218   }
219
220   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
221     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
222     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
223   }
224   else {
225     gw->uplink = 1;
226     gw->downlink = 1;
227   }
228
229   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
230   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
231
232   if (olsr_cnf->ip_version == AF_INET6) {
233     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
234
235     /* do not reset prefixlength for ::ffff:0:0 HNAs */
236     if (prefixlen == ipv6_internet_route.prefix_len) {
237       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
238
239       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
240           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
241         /* this is the right prefix (2000::/3), so we can copy the prefix */
242         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
243         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
244       }
245     }
246   }
247
248   gw_handler->handle_update_gw(gw);
249 }
250
251 /**
252  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
253  * Should only be called if prefix is a smart_gw prefix or if node is removed
254  * from TC set.
255  * @param originator
256  * @param prefixlen
257  */
258 void
259 olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen) {
260   struct gateway_entry *gw;
261   bool change = false;
262
263   gw = olsr_find_gateway_entry(originator);
264   if (gw) {
265     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
266       gw->ipv4 = false;
267       gw->ipv4nat = false;
268       change = true;
269     }
270     if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
271       gw->ipv6 = false;
272       change = true;
273     }
274     if (olsr_cnf->ip_version == AF_INET6 && prefixlen == mapped_v4_gw.prefix_len) {
275       gw->ipv4 = false;
276       gw->ipv4nat = false;
277       change = true;
278     }
279
280     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
281       /* prevent this gateway from being choosen as the new gateway */
282       gw->ipv4 = false;
283       gw->ipv6 = false;
284
285       /* handle gateway loss */
286       gw_handler->handle_delete_gw(gw);
287
288       /* cleanup gateway pointer if necessary */
289       if (current_ipv4_gw == gw) {
290         current_ipv4_gw = NULL;
291       }
292       if (current_ipv6_gw == gw) {
293         current_ipv6_gw = NULL;
294       }
295
296       /* remove gateway entry */
297       avl_delete(&gateway_tree, &gw->node);
298       olsr_cookie_free(gw_mem_cookie, gw);
299     }
300     else if (change) {
301       gw_handler->handle_update_gw(gw);
302     }
303   }
304 }
305
306 /**
307  * Checks if a prefix/netmask combination is a smart gateway
308  * @param prefix
309  * @param mask
310  * @return true if is a valid smart gateway HNA, false otherwise
311  */
312 bool
313 olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
314   uint8_t *ptr;
315
316   if (!is_prefix_inetgw(prefix)) {
317     return false;
318   }
319
320   ptr = ((uint8_t *)mask) + ((prefix->prefix_len+7)/8);
321   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
322 }
323
324 /**
325  * Apply the smart gateway modifications to an outgoing HNA
326  * @param mask pointer to netmask of the HNA
327  * @param prefixlen of the HNA
328  */
329 void
330 olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
331   uint8_t *ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
332
333   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen/8);
334   if (olsr_cnf->has_ipv4_gateway) {
335     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
336
337     if (olsr_cnf->smart_gw_uplink_nat) {
338       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
339     }
340   }
341   if (olsr_cnf->has_ipv6_gateway) {
342     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
343   }
344   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len){
345     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
346   }
347 }
348
349 /**
350  * Print debug information about gateway entries
351  */
352 void
353 olsr_print_gateway_entries(void) {
354 #ifndef NODEBUG
355   struct ipaddr_str buf;
356   struct gateway_entry *gw;
357   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
358
359   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n",
360       olsr_wallclock_string());
361   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n", addrsize, "IP address", "Type", "Uplink", "Downlink",
362       olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
363
364   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
365     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n", addrsize, olsr_ip_to_string(&buf, &gw->originator),
366         gw->ipv4nat ? "" : "   ",
367         gw->ipv4 ? '4' : ' ',
368         gw->ipv4nat ? "(N)" : "",
369         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
370         gw->ipv6 ? '6' : ' ',
371         gw->uplink, gw->downlink,
372         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
373   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
374 #endif
375 }