4 * Created on: 05.01.2010
8 #include "common/avl.h"
13 #include "olsr_cookie.h"
14 #include "scheduler.h"
15 #include "gateway_default_handler.h"
20 struct avl_tree gateway_tree;
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;
28 * Reconstructs an uplink/downlink speed value from the encoded
29 * 1 byte transport value (3 bit mantissa, 5 bit exponent)
34 deserialize_gw_speed(uint8_t value) {
37 speed = (value >> 3)+1;
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
52 serialize_gw_speed(uint32_t speed) {
55 if (speed == 0 || speed > 320000000) {
59 while (speed > 32 || (speed % 10) == 0) {
63 return ((speed-1) << 3) | exp;
67 * Initialize gateway system
70 olsr_init_gateways(void) {
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));
75 avl_init(&gateway_tree, avl_comp_default);
76 current_ipv4_gw = NULL;
77 current_ipv6_gw = NULL;
79 memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
81 if (olsr_cnf->smart_gw_active) {
82 union olsr_ip_addr gw_net;
83 memset(&gw_net, 0, sizeof(gw_net));
85 ip = (uint8_t *) &smart_gateway_netmask;
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);
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);
100 * initialize default gateway handler,
101 * can be overwritten with olsr_set_inetgw_handler
103 olsr_gw_default_init();
107 * Triggers the first lookup of an gateway. This lookup might
108 * take some time to wait for routing/gateway information.
111 olsr_trigger_inetgw_startup(void) {
112 gw_handler->handle_startup();
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
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;
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
133 olsr_set_inetgw_handler(struct olsr_gw_handler *h) {
138 * Sets a new internet gateway.
139 * An external set command might trigger an internal one if
140 * address is not a legal gateway.
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
150 olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool external) {
151 struct gateway_entry *entry;
153 ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
154 ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
156 entry = olsr_find_gateway_entry(originator);
158 if (ipv4 && entry->ipv4 && (!entry->ipv4nat || olsr_cnf->smart_gw_allow_nat)) {
159 /* valid ipv4 gateway */
160 current_ipv4_gw = entry;
163 if (ipv6 && entry->ipv6) {
164 /* valid ipv6 gateway */
165 current_ipv6_gw = entry;
170 /* still gateway missing ? */
172 return external ? olsr_trigger_inetgw_selection(ipv4, ipv6) : -1;
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
182 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
183 return ipv6 ? current_ipv6_gw : current_ipv4_gw;
188 * @return gateway_entry for corresponding router
190 struct gateway_entry *
191 olsr_find_gateway_entry(union olsr_ip_addr *originator) {
192 struct avl_node *node = avl_find(&gateway_tree, originator);
194 return node == NULL ? NULL : node2gateway(node);
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
204 olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen) {
205 struct gateway_entry *gw;
208 ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
210 gw = olsr_find_gateway_entry(originator);
212 gw = olsr_cookie_malloc(gw_mem_cookie);
214 gw->originator = *originator;
215 gw->node.key = &gw->originator;
217 avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
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]);
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;
232 if (olsr_cnf->ip_version == AF_INET6) {
233 gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
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));
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);
248 gw_handler->handle_update_gw(gw);
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
259 olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen) {
260 struct gateway_entry *gw;
263 gw = olsr_find_gateway_entry(originator);
265 if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
270 if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
274 if (olsr_cnf->ip_version == AF_INET6 && prefixlen == mapped_v4_gw.prefix_len) {
280 if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
281 /* prevent this gateway from being choosen as the new gateway */
285 /* handle gateway loss */
286 gw_handler->handle_delete_gw(gw);
288 /* cleanup gateway pointer if necessary */
289 if (current_ipv4_gw == gw) {
290 current_ipv4_gw = NULL;
292 if (current_ipv6_gw == gw) {
293 current_ipv6_gw = NULL;
296 /* remove gateway entry */
297 avl_delete(&gateway_tree, &gw->node);
298 olsr_cookie_free(gw_mem_cookie, gw);
301 gw_handler->handle_update_gw(gw);
307 * Checks if a prefix/netmask combination is a smart gateway
310 * @return true if is a valid smart gateway HNA, false otherwise
313 olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
316 if (!is_prefix_inetgw(prefix)) {
320 ptr = ((uint8_t *)mask) + ((prefix->prefix_len+7)/8);
321 return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
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
330 olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
331 uint8_t *ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
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;
337 if (olsr_cnf->smart_gw_uplink_nat) {
338 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
341 if (olsr_cnf->has_ipv6_gateway) {
342 ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
344 if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len){
345 ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
350 * Print debug information about gateway entries
353 olsr_print_gateway_entries(void) {
355 struct ipaddr_str buf;
356 struct gateway_entry *gw;
357 const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
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");
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)