More cleanup for Smart-Gateway distribution code
authorHenning Rogge <hrogge@googlemail.com>
Thu, 14 Jan 2010 20:01:48 +0000 (21:01 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Thu, 14 Jan 2010 20:01:48 +0000 (21:01 +0100)
Add support for ::ffff:0:0 smart gateway

src/build_msg.c
src/cfgparser/olsrd_conf.c
src/gateway.c
src/gateway.h
src/hna_set.c
src/ipcalc.c
src/ipcalc.h
src/olsr_cfg.h

index c48f506..f6401c9 100644 (file)
@@ -1047,13 +1047,12 @@ serialize_hna4(struct interface *ifp)
     OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net));
 #endif
 
+    olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len);
     if (olsr_cnf->smart_gateway_active && h->net.prefix_len == 0) {
       /* this is the default route, overwrite it with the smart gateway */
-      ip_addr.v4 = smart_gateway_netmask.v4;
-    }
-    else {
-      olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len);
+      olsr_modifiy_inetgw_netmask(&ip_addr, h->net.prefix_len);
     }
+
     pair->addr = h->net.prefix.v4.s_addr;
     pair->netmask = ip_addr.v4.s_addr;
     pair++;
@@ -1141,13 +1140,11 @@ serialize_hna6(struct interface *ifp)
     OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net));
 #endif
     olsr_prefix_to_netmask(&tmp_netmask, h->net.prefix_len);
-    if (olsr_cnf->smart_gateway_active && h->net.prefix_len == 0) {
+    if (olsr_cnf->smart_gateway_active && (h->net.prefix_len == 0 || ip_prefix_is_mappedv4_gw(&h->net))) {
       /* this is the default gateway, so overwrite it with the smart one */
-      tmp_netmask = smart_gateway_netmask;
-    }
-    else {
-      olsr_prefix_to_netmask(&tmp_netmask, h->net.prefix_len);
+      olsr_modifiy_inetgw_netmask(&tmp_netmask, h->net.prefix_len);
     }
+
     pair6->addr = h->net.prefix.v6;
     pair6->netmask = tmp_netmask.v6;
     pair6++;
index d8efd3f..160fbf8 100644 (file)
@@ -769,6 +769,24 @@ win32_olsrd_free(void *ptr)
 }
 #endif
 
+static void update_has_gateway_fields(void) {
+  struct ip_prefix_list *h;
+
+  olsr_cnf->has_ipv4_gateway = false;
+  olsr_cnf->has_ipv6_gateway = false;
+
+  for (h = olsr_cnf->hna_entries; h != NULL; h = h->next) {
+    if (h->net.prefix_len == 0) {
+      olsr_cnf->has_ipv4_gateway = true;
+      olsr_cnf->has_ipv6_gateway = olsr_cnf->ip_version == AF_INET6;
+      return;
+    }
+    if (ip_prefix_is_mappedv4_gw(&h->net)) {
+      olsr_cnf->has_ipv4_gateway = true;
+    }
+  }
+}
+
 void
 ip_prefix_list_add(struct ip_prefix_list **list, const union olsr_ip_addr *net, uint8_t prefix_len)
 {
@@ -780,6 +798,9 @@ ip_prefix_list_add(struct ip_prefix_list **list, const union olsr_ip_addr *net,
   /* Queue */
   new_entry->next = *list;
   *list = new_entry;
+
+  /* update gateway flags */
+  update_has_gateway_fields();
 }
 
 int
@@ -796,6 +817,9 @@ ip_prefix_list_remove(struct ip_prefix_list **list, const union olsr_ip_addr *ne
         prev->next = h->next;
       }
       free(h);
+
+      /* update gateway flags */
+      update_has_gateway_fields();
       return 1;
     }
     prev = h;
index b05a968..55369f8 100644 (file)
@@ -15,8 +15,8 @@
 #include "gateway.h"
 
 struct avl_tree gateway_tree;
-struct olsr_cookie_info *gw_mem_cookie = NULL;
-union olsr_ip_addr smart_gateway_netmask;
+static struct olsr_cookie_info *gw_mem_cookie = NULL;
+static uint8_t smart_gateway_netmask[15];
 
 static uint32_t deserialize_gw_speed(uint8_t value) {
   uint32_t speed, exp;
@@ -94,9 +94,9 @@ olsr_find_gateway(union olsr_ip_addr *originator) {
 }
 
 void
-olsr_set_gateway(union olsr_ip_addr *originator, union olsr_ip_addr *subnetmask) {
+olsr_set_gateway(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen) {
   struct gateway_entry *gw;
-  uint8_t *ip;
+  uint8_t *ptr = ((uint8_t *)mask) + (prefixlen/8);
 
   gw = olsr_find_gateway(originator);
   if (!gw) {
@@ -108,25 +108,24 @@ olsr_set_gateway(union olsr_ip_addr *originator, union olsr_ip_addr *subnetmask)
     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
   }
 
-  ip = (uint8_t *)subnetmask;
-  if ((ip[GW_HNA_FLAGS] & GW_HNA_FLAG_UPLINK) != 0) {
-    gw->uplink = deserialize_gw_speed(ip[GW_HNA_UPLINK]);
+  if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_UPLINK) != 0) {
+    gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
   }
   else {
     gw->uplink = 1;
   }
 
-  if ((ip[GW_HNA_FLAGS] & GW_HNA_FLAG_DOWNLINK) != 0) {
-    gw->downlink = deserialize_gw_speed(ip[GW_HNA_DOWNLINK]);
+  if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_DOWNLINK) != 0) {
+    gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
   }
   else {
     gw->downlink = 1;
   }
 
   memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
-  if ((ip[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0 && olsr_cnf->ip_version == AF_INET6) {
-    gw->external_prefix.prefix_len = ip[GW_HNA_V6PREFIXLEN];
-    memcpy(&gw->external_prefix.prefix, &ip[GW_HNA_V6PREFIX], 8);
+  if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0 && olsr_cnf->ip_version == AF_INET6) {
+    gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
+    memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
   }
 }
 
@@ -142,15 +141,38 @@ olsr_delete_gateway(union olsr_ip_addr *originator) {
   }
 }
 
-bool olsr_is_smart_gateway(union olsr_ip_addr *net, union olsr_ip_addr *mask) {
-  uint8_t *ip;
+bool olsr_is_smart_gateway(union olsr_ip_addr *net, union olsr_ip_addr *mask, int prefixlen) {
+  uint8_t *ptr = ((uint8_t *)mask) + (prefixlen/8);
 
-  if (memcmp(&in6addr_any, net, olsr_cnf->ipsize) != 0) {
+  if (prefixlen == 0) {
+    if (memcmp(&in6addr_any, net, olsr_cnf->ipsize) != 0) {
+      return false;
+    }
+  }
+  else if (prefixlen == 96) {
+    if (memcmp(&mapped_v4_gw, net, olsr_cnf->ipsize) != 0) {
+      return false;
+    }
+  }
+  else {
     return false;
   }
 
-  ip = (uint8_t *)mask;
-  return ip[0] == 0 && ip[1] != 0;
+  return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
+}
+
+void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
+  uint8_t *ptr = ((uint8_t *)mask) + (prefixlen/8);
+
+  if (olsr_cnf->has_ipv4_gateway) {
+    memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen/8);
+  }
+  if (olsr_cnf->has_ipv6_gateway) {
+    ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
+  }
+  else {
+    ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
+  }
 }
 
 void
@@ -162,12 +184,14 @@ olsr_print_gateway(void) {
 
   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n",
       olsr_wallclock_string());
-  OLSR_PRINTF(0, "%-*s  %-9s %-9s %s\n", addrsize, "IP address", "Uplink", "Downlink",
+  OLSR_PRINTF(0, "%-*s %5s %-9s %-9s %s\n", addrsize, "IP address", "IPv6", "Uplink", "Downlink",
       olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
 
   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
-    OLSR_PRINTF(0, "%-*s  %-9u %-9u %s\n", addrsize, olsr_ip_to_string(&buf, &gw->originator),
-        gw->uplink, gw->downlink, gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
+    OLSR_PRINTF(0, "%-*s %5s %-9u %-9u %s\n", addrsize, olsr_ip_to_string(&buf, &gw->originator),
+        gw->ipv6 ? "true" : "false",
+        gw->uplink, gw->downlink,
+        gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
 #endif
 }
index 9950ce4..037eb22 100644 (file)
@@ -18,9 +18,11 @@ enum gateway_hna_flags {
   GW_HNA_FLAG_SMART      = 1<<0,
   GW_HNA_FLAG_UPLINK     = 1<<1,
   GW_HNA_FLAG_DOWNLINK   = 1<<2,
-  GW_HNA_FLAG_IPV6PREFIX = 1<<3
+  GW_HNA_FLAG_IPV6       = 1<<3,
+  GW_HNA_FLAG_IPV6PREFIX = 1<<4
 };
 
+/* relative to the first zero byte in the netmask (0 or 12) */
 enum gateway_hna_fields {
   GW_HNA_PAD         = 0,
   GW_HNA_FLAGS       = 1,
@@ -36,6 +38,7 @@ struct gateway_entry {
   struct olsr_ip_prefix external_prefix;
   uint32_t uplink;
   uint32_t downlink;
+  bool ipv6;
 };
 
 AVLNODE2STRUCT(node2gateway, struct gateway_entry, node);
@@ -53,11 +56,9 @@ extern struct avl_tree gateway_tree;
 
 void olsr_init_gateways(void);
 struct gateway_entry *olsr_find_gateway(union olsr_ip_addr *originator);
-void olsr_set_gateway(union olsr_ip_addr *originator, union olsr_ip_addr *subnetmask);
+void olsr_set_gateway(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen);
 void olsr_delete_gateway(union olsr_ip_addr *originator);
-bool olsr_is_smart_gateway(union olsr_ip_addr *net, union olsr_ip_addr *mask);
+bool olsr_is_smart_gateway(union olsr_ip_addr *net, union olsr_ip_addr *mask, int prefixlen);
 void olsr_print_gateway(void);
-
-extern union olsr_ip_addr smart_gateway_netmask;
-
+void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen);
 #endif /* GATEWAY_H_ */
index 74664f6..edf9c7c 100644 (file)
@@ -444,11 +444,12 @@ olsr_input_hna(union olsr_message *m, struct interface *in_if __attribute__ ((un
 
     pkt_get_ipaddress(&curr, &net);
     pkt_get_ipaddress(&curr, &mask);
-    if (olsr_cnf->smart_gateway_active && olsr_is_smart_gateway(&net, &mask)) {
-      olsr_set_gateway(&originator, &mask);
+    prefixlen = olsr_netmask_to_prefix(&mask);
+
+    if (olsr_cnf->smart_gateway_active && olsr_is_smart_gateway(&net, &mask, prefixlen)) {
+      olsr_set_gateway(&originator, &mask, prefixlen);
     }
 
-    prefixlen = olsr_netmask_to_prefix(&mask);
     if (olsr_cnf->smart_gateway_active && prefixlen > 0 && prefixlen <= MAXIMUM_GATEWAY_PREFIX_LENGTH) {
       continue;
     }
index 89eccc5..f94b6b9 100644 (file)
  *
  */
 
+#include "defs.h"
 #include "ipcalc.h"
 
+const uint8_t mapped_v4_gw[] = { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0};
+
 int
 prefix_to_netmask(uint8_t * a, int len, uint8_t prefixlen)
 {
index dde66f0..a8769d4 100644 (file)
@@ -53,6 +53,8 @@ struct ipaddr_str {
   char buf[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
 } __attribute__ ((unused));
 
+extern const uint8_t mapped_v4_gw[];
+
 /*
  * Macros for comparing and copying IP addresses
  */
@@ -177,6 +179,13 @@ olsr_ipv6_to_ipv4(const union olsr_ip_addr *ipv6, union olsr_ip_addr *ipv4) {
   return ipv4;
 }
 
+
+static INLINE bool
+ip_prefix_is_mappedv4_gw(struct olsr_ip_prefix *prefix) {
+  return olsr_cnf->ip_version == AF_INET6 && prefix->prefix_len == 96
+      && memcmp(&prefix->prefix, mapped_v4_gw, sizeof(prefix->prefix)) == 0;
+}
+
 #endif
 
 /*
index aa77784..f289975 100644 (file)
@@ -253,6 +253,7 @@ struct olsrd_config {
   int niit_if_index;
 
   /*many potential parameters or helper variables for smartgateway*/
+  bool has_ipv4_gateway, has_ipv6_gateway;
   bool smart_gateway_active;
   uint32_t smart_gateway_uplink;
   uint32_t smart_gateway_downlink;