Export smartgw netmask refresh as function
[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 "kernel_routes.h"
16 #include "kernel_tunnel.h"
17 #include "net_os.h"
18 #include "duplicate_set.h"
19 #include "log.h"
20 #include "gateway_default_handler.h"
21 #include "gateway.h"
22
23 #include <assert.h>
24 #include <net/if.h>
25
26 #ifdef LINUX_NETLINK_ROUTING
27 struct avl_tree gateway_tree;
28
29 static struct olsr_cookie_info *gw_mem_cookie = NULL;
30 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
31 static struct gateway_entry *current_ipv4_gw, *current_ipv6_gw;
32 static struct olsr_gw_handler *gw_handler;
33
34 static struct olsr_iptunnel_entry *v4gw_tunnel, *v6gw_tunnel;
35 static bool v4gw_choosen_external, v6gw_choosen_external;
36
37 /**
38  * Reconstructs an uplink/downlink speed value from the encoded
39  * 1 byte transport value (3 bit mantissa, 5 bit exponent)
40  * @param value
41  * @return
42  */
43 static uint32_t
44 deserialize_gw_speed(uint8_t value) {
45   uint32_t speed, exp;
46
47   speed = (value >> 3)+1;
48   exp = value & 7;
49   while (exp-- > 0) {
50     speed *= 10;
51   }
52   return speed;
53 }
54
55 /**
56  * Convert an uplink/downlink speed into an exponential encoded
57  * transport value (1 byte, 3 bit mantissa and 5 bit exponent)
58  * @param value uplink/downlink speed in kbit/s
59  * @return encoded byte value
60  */
61 static uint8_t
62 serialize_gw_speed(uint32_t speed) {
63   uint8_t exp = 0;
64
65   if (speed == 0 || speed > 320000000) {
66     return 0;
67   }
68
69   while (speed > 32 || (speed % 10) == 0) {
70     speed /= 10;
71     exp ++;
72   }
73   return ((speed-1) << 3) | exp;
74 }
75
76 /**
77  * Initialize gateway system
78  */
79 int
80 olsr_init_gateways(void) {
81   gw_mem_cookie = olsr_alloc_cookie("Gateway cookie", OLSR_COOKIE_TYPE_MEMORY);
82   olsr_cookie_set_memory_size(gw_mem_cookie, sizeof(struct gateway_entry));
83
84   avl_init(&gateway_tree, avl_comp_default);
85   current_ipv4_gw = NULL;
86   current_ipv6_gw = NULL;
87
88   v4gw_tunnel = NULL;
89   v6gw_tunnel = NULL;
90
91   refresh_smartgw_netmask();
92
93   if (olsr_os_init_iptunnel()) {
94     return 1;
95   }
96   /*
97    * initialize default gateway handler,
98    * can be overwritten with olsr_set_inetgw_handler
99    */
100   olsr_gw_default_init();
101   return 0;
102 }
103
104 void refresh_smartgw_netmask(void) {
105   uint8_t *ip;
106   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
107
108   if (olsr_cnf->smart_gw_active) {
109     union olsr_ip_addr gw_net;
110     memset(&gw_net, 0, sizeof(gw_net));
111
112     ip = (uint8_t *) &smart_gateway_netmask;
113
114     if (olsr_cnf->smart_gw_uplink > 0 || olsr_cnf->smart_gw_downlink > 0) {
115       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
116       ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
117       ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
118     }
119     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
120       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
121       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
122       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
123     }
124   }
125 }
126
127 /**
128  * Cleanup gateway tunnel system
129  */
130 void olsr_cleanup_gateways(void) {
131   if (current_ipv4_gw) {
132     olsr_os_del_ipip_tunnel(v4gw_tunnel);
133   }
134   if (current_ipv6_gw) {
135     olsr_os_del_ipip_tunnel(v6gw_tunnel);
136   }
137   olsr_os_cleanup_iptunnel();
138 }
139
140 /**
141  * Triggers the first lookup of an gateway. This lookup might
142  * take some time to wait for routing/gateway information.
143  */
144 void
145 olsr_trigger_inetgw_startup(void) {
146   gw_handler->handle_startup();
147 }
148
149 /**
150  * Triggers an instant gateway selection based on the current data
151  * @param ipv4 trigger a ipv4 gateway lookup
152  * @param ipv6 trigger a ipv6 gateway lookup
153  * @return 0 if successful, -1 otherwise
154  */
155 int
156 olsr_trigger_inetgw_selection(bool ipv4, bool ipv6) {
157   gw_handler->select_gateway(ipv4, ipv6);
158   return ((ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL)) ? -1 : 0;
159 }
160
161 /**
162  * Triggers a check if the one of the gateways have been lost
163  * through ETX = infinity
164  */
165 void olsr_trigger_gatewayloss_check(void) {
166   struct tc_entry *tc;
167   bool ipv4 = false, ipv6 = false;
168   if (current_ipv4_gw) {
169     tc = olsr_lookup_tc_entry(&current_ipv4_gw->originator);
170     if (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN) {
171       ipv4 = true;
172     }
173   }
174   if (current_ipv6_gw) {
175     tc = olsr_lookup_tc_entry(&current_ipv6_gw->originator);
176     if (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN) {
177       ipv6 = true;
178     }
179   }
180   if (ipv4 || ipv6) {
181     olsr_trigger_inetgw_selection(ipv4, ipv6);
182   }
183 }
184 /**
185  * Set a new gateway handler. Do only call this once during startup from
186  * a plugin to overwrite the default handler.
187  * @param h pointer to gateway handler struct
188  */
189 void
190 olsr_set_inetgw_handler(struct olsr_gw_handler *h) {
191   gw_handler = h;
192 }
193
194 /**
195  * Sets a new internet gateway.
196  * An external set command might trigger an internal one if
197  * address is not a legal gateway.
198  *
199  * @param originator ip address of the node with the new gateway
200  * @param ipv4 set ipv4 gateway
201  * @param ipv6 set ipv6 gateway
202  * @param external true if change was triggered directly by an user,
203  *   false if triggered by automatic lookup.
204  * @return true if an error happened, false otherwise
205  */
206 bool
207 olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool external) {
208   struct gateway_entry *entry, *oldV4, *oldV6;
209   struct olsr_iptunnel_entry *tunnelV4, *tunnelV6;
210
211   oldV4 = current_ipv4_gw;
212   oldV6 = current_ipv6_gw;
213   tunnelV4 = v4gw_tunnel;
214   tunnelV6 = v6gw_tunnel;
215
216   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
217   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
218
219   if (ipv4) {
220     current_ipv4_gw = NULL;
221   }
222   if (ipv6) {
223     current_ipv6_gw = NULL;
224   }
225
226   entry = olsr_find_gateway_entry(originator);
227   if (entry != NULL) {
228     if (ipv4 && entry != current_ipv4_gw && entry->ipv4
229         && (!entry->ipv4nat || olsr_cnf->smart_gw_allow_nat)) {
230       /* valid ipv4 gateway */
231       current_ipv4_gw = entry;
232     }
233     if (ipv6 && entry != current_ipv6_gw && entry->ipv6) {
234       /* valid ipv6 gateway */
235       current_ipv6_gw = entry;
236     }
237   }
238
239   /* handle IPv4 */
240   if (oldV4 != current_ipv4_gw) {
241     if ((v4gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv4_gw->originator, true)) != NULL) {
242       olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, true);
243       v4gw_choosen_external = external;
244     }
245     else {
246       // TODO: what to do now ? Choose another one ? Fire up a timer ?
247       current_ipv4_gw = NULL;
248     }
249     if (oldV4 != NULL) {
250       olsr_os_del_ipip_tunnel(tunnelV4);
251     }
252   }
253   /* handle IPv6 */
254   if (oldV6 != current_ipv6_gw) {
255     if ((v6gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv6_gw->originator, false)) != NULL) {
256       olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, true);
257       v6gw_choosen_external = external;
258     }
259     else {
260       // TODO: what to do now ? Choose another one ? Fire up a timer ?
261       current_ipv6_gw = NULL;
262     }
263     if (oldV6 != NULL) {
264       olsr_os_del_ipip_tunnel(tunnelV6);
265     }
266   }
267   return (ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL);
268 }
269
270 /**
271  * returns the gateway_entry of the current ipv4 internet gw.
272  * @return pointer to gateway_entry or NULL if not set
273  */
274 struct gateway_entry *olsr_get_ipv4_inet_gateway(bool *ext) {
275   if (ext) {
276     *ext = v4gw_choosen_external;
277   }
278   return current_ipv4_gw;
279 }
280
281 /**
282  * returns the gateway_entry of the current ipv6 internet gw.
283  * @return pointer to gateway_entry or NULL if not set
284  */
285 struct gateway_entry *olsr_get_ipv6_inet_gateway(bool *ext) {
286   if (ext) {
287     *ext = v6gw_choosen_external;
288   }
289   return current_ipv6_gw;
290 }
291
292 /**
293  * @param originator
294  * @return gateway_entry for corresponding router
295  */
296 struct gateway_entry *
297 olsr_find_gateway_entry(union olsr_ip_addr *originator) {
298   struct avl_node *node = avl_find(&gateway_tree, originator);
299
300   return node == NULL ? NULL : node2gateway(node);
301 }
302
303 /**
304  * update a gateway_entry based on data received from a HNA
305  * @param originator ip of the source of the HNA
306  * @param mask netmask of the HNA
307  * @param prefixlen of the HNA
308  */
309 void
310 olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
311   struct gateway_entry *gw;
312   uint8_t *ptr;
313
314   ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
315
316   gw = olsr_find_gateway_entry(originator);
317   if (!gw) {
318     struct ipaddr_str buf;
319     gw = olsr_cookie_malloc(gw_mem_cookie);
320
321     gw->originator = *originator;
322     gw->node.key = &gw->originator;
323
324     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
325   }
326   else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
327     /* ignore older HNAs */
328     return;
329   }
330
331   /* keep new HNA seqno */
332   gw->seqno = seqno;
333
334   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
335     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
336     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
337   }
338   else {
339     gw->uplink = 1;
340     gw->downlink = 1;
341   }
342
343   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
344   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
345
346   if (olsr_cnf->ip_version == AF_INET6) {
347     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
348
349     /* do not reset prefixlength for ::ffff:0:0 HNAs */
350     if (prefixlen == ipv6_internet_route.prefix_len) {
351       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
352
353       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
354           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
355         /* this is the right prefix (2000::/3), so we can copy the prefix */
356         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
357         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
358       }
359     }
360   }
361
362   /* stop cleanup timer if necessary */
363   if (gw->cleanup_timer) {
364     olsr_stop_timer(gw->cleanup_timer);
365     gw->cleanup_timer = NULL;
366   }
367
368   /* call update handler */
369   gw_handler->handle_update_gw(gw);
370 }
371
372 static void cleanup_gateway_handler(void *ptr) {
373   struct gateway_entry *gw = ptr;
374
375   if (gw->ipv4 || gw->ipv6) {
376     return;
377   }
378
379   /* remove gateway entry */
380   avl_delete(&gateway_tree, &gw->node);
381   olsr_cookie_free(gw_mem_cookie, gw);
382 }
383
384 /**
385  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
386  * Should only be called if prefix is a smart_gw prefix or if node is removed
387  * from TC set.
388  * @param originator
389  * @param prefixlen
390  */
391 void
392 olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen) {
393   struct gateway_entry *gw;
394   bool change = false;
395   gw = olsr_find_gateway_entry(originator);
396   if (gw && (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6)) {
397     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
398       change = gw->ipv4;
399       gw->ipv4 = false;
400       gw->ipv4nat = false;
401     }
402     else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
403       change = gw->ipv6;
404       gw->ipv6 = false;
405     }
406     else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
407       change = gw->ipv4;
408       gw->ipv4 = false;
409       gw->ipv4nat = false;
410     }
411
412     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
413       /* prevent this gateway from being choosen as the new gateway */
414       gw->ipv4 = false;
415       gw->ipv4nat = false;
416       gw->ipv6 = false;
417
418       /* handle gateway loss */
419       gw_handler->handle_delete_gw(gw);
420       /* cleanup gateway if necessary */
421       if (current_ipv4_gw == gw) {
422         olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, false);
423         olsr_os_del_ipip_tunnel(v4gw_tunnel);
424         current_ipv4_gw = NULL;
425         v4gw_tunnel = NULL;
426       }
427       if (current_ipv6_gw == gw) {
428         olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, false);
429         olsr_os_del_ipip_tunnel(v6gw_tunnel);
430         current_ipv6_gw = NULL;
431         v6gw_tunnel = NULL;
432       }
433
434       /* remove gateway entry */
435       olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
436     }
437     else if (change) {
438       gw_handler->handle_update_gw(gw);
439     }
440   }
441 }
442
443 /**
444  * Checks if a prefix/netmask combination is a smart gateway
445  * @param prefix
446  * @param mask
447  * @return true if is a valid smart gateway HNA, false otherwise
448  */
449 bool
450 olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
451   uint8_t *ptr;
452
453   if (!is_prefix_inetgw(prefix)) {
454     return false;
455   }
456
457   ptr = ((uint8_t *)mask) + ((prefix->prefix_len+7)/8);
458   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
459 }
460
461 /**
462  * Apply the smart gateway modifications to an outgoing HNA
463  * @param mask pointer to netmask of the HNA
464  * @param prefixlen of the HNA
465  */
466 void
467 olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
468   uint8_t *ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
469
470   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen/8);
471   if (olsr_cnf->has_ipv4_gateway) {
472     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
473
474     if (olsr_cnf->smart_gw_uplink_nat) {
475       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
476     }
477   }
478   if (olsr_cnf->has_ipv6_gateway) {
479     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
480   }
481   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len){
482     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
483   }
484 }
485
486 /**
487  * Print debug information about gateway entries
488  */
489 void
490 olsr_print_gateway_entries(void) {
491 #ifndef NODEBUG
492   struct ipaddr_str buf;
493   struct gateway_entry *gw;
494   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
495
496   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n",
497       olsr_wallclock_string());
498   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n", addrsize, "IP address", "Type", "Uplink", "Downlink",
499       olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
500
501   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
502     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n", addrsize, olsr_ip_to_string(&buf, &gw->originator),
503         gw->ipv4nat ? "" : "   ",
504         gw->ipv4 ? '4' : ' ',
505         gw->ipv4nat ? "(N)" : "",
506         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
507         gw->ipv6 ? '6' : ' ',
508         gw->uplink, gw->downlink,
509         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
510   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
511 #endif
512 }
513
514 #endif /* !WIN32 */