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