]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/lwip/lib/contrib/src/core/ipv6/ip6_addr.c
Update
[l4.git] / l4 / pkg / lwip / lib / contrib / src / core / ipv6 / ip6_addr.c
index 6c047491cd1b1a760af48fe4eab227c95b25387d..e157b1e75e6ff9d023eb5fabc7b46f669df4ac05 100644 (file)
@@ -6,9 +6,9 @@
 
 /*
  * Copyright (c) 2010 Inico Technologies Ltd.
- * All rights reserved. 
- * 
- * Redistribution and use in source and binary forms, with or without modification, 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *
  * 1. Redistributions of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission. 
+ *    derived from this software without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  * OF SUCH DAMAGE.
  *
  * This file is part of the lwIP TCP/IP stack.
- * 
+ *
  * Author: Ivan Delamer <delamer@inicotech.com>
  *
  * Functions for handling IPv6 addresses.
 
 #if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
 
-#include "lwip/ip6_addr.h"
+#include "lwip/ip_addr.h"
 #include "lwip/def.h"
 
-/* used by IP6_ADDR_ANY in ip6_addr.h */
-const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
+/* used by IP6_ADDR_ANY(6) in ip6_addr.h */
+const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
 
 #ifndef isprint
 #define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
@@ -65,7 +65,7 @@ const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
  * of an IPv6 address and convert to a binary address.
  * Returns 1 if the address is valid, 0 if not.
  *
- * @param cp IPv6 address in ascii represenation (e.g. "FF01::1")
+ * @param cp IPv6 address in ascii representation (e.g. "FF01::1")
  * @param addr pointer to which to save the ip address in network order
  * @return 1 if cp could be converted to addr, 0 on failure
  */
@@ -79,10 +79,11 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
      zero_blocks may be 1 even if there are no :: sequences */
   zero_blocks = 8;
   for (s = cp; *s != 0; s++) {
-    if (*s == ':')
+    if (*s == ':') {
       zero_blocks--;
-    else if (!isxdigit(*s))
+    } else if (!isxdigit(*s)) {
       break;
+    }
   }
 
   /* parse each block */
@@ -91,28 +92,41 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
   current_block_value = 0;
   for (s = cp; *s != 0; s++) {
     if (*s == ':') {
-      if (current_block_index & 0x1) {
-        addr->addr[addr_index++] |= current_block_value;
-      }
-      else {
-        addr->addr[addr_index] = current_block_value << 16;
+      if (addr) {
+        if (current_block_index & 0x1) {
+          addr->addr[addr_index++] |= current_block_value;
+        }
+        else {
+          addr->addr[addr_index] = current_block_value << 16;
+        }
       }
       current_block_index++;
       current_block_value = 0;
       if (current_block_index > 7) {
         /* address too long! */
         return 0;
-      } if (s[1] == ':') {
+      }
+      if (s[1] == ':') {
+        if (s[2] == ':') {
+          /* invalid format: three successive colons */
+          return 0;
+        }
         s++;
         /* "::" found, set zeros */
-        while (zero_blocks-- > 0) {
+        while (zero_blocks > 0) {
+          zero_blocks--;
           if (current_block_index & 0x1) {
             addr_index++;
-          }
-          else {
-            addr->addr[addr_index] = 0;
+          } else {
+            if (addr) {
+              addr->addr[addr_index] = 0;
+            }
           }
           current_block_index++;
+          if (current_block_index > 7) {
+            /* address too long! */
+            return 0;
+          }
         }
       }
     } else if (isxdigit(*s)) {
@@ -126,16 +140,20 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
     }
   }
 
-  if (current_block_index & 0x1) {
-    addr->addr[addr_index++] |= current_block_value;
-  }
-  else {
-    addr->addr[addr_index] = current_block_value << 16;
+  if (addr) {
+    if (current_block_index & 0x1) {
+      addr->addr[addr_index++] |= current_block_value;
+    }
+    else {
+      addr->addr[addr_index] = current_block_value << 16;
+    }
   }
 
   /* convert to network byte order. */
-  for (addr_index = 0; addr_index < 4; addr_index++) {
-    addr->addr[addr_index] = htonl(addr->addr[addr_index]);
+  if (addr) {
+    for (addr_index = 0; addr_index < 4; addr_index++) {
+      addr->addr[addr_index] = htonl(addr->addr[addr_index]);
+    }
   }
 
   if (current_block_index != 7) {
@@ -143,7 +161,6 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
   }
 
   return 1;
-
 }
 
 /**
@@ -152,7 +169,7 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr)
  *
  * @param addr ip6 address in network order to convert
  * @return pointer to a global static (!) buffer that holds the ASCII
- *         represenation of addr
+ *         representation of addr
  */
 char *
 ip6addr_ntoa(const ip6_addr_t *addr)
@@ -173,11 +190,12 @@ ip6addr_ntoa(const ip6_addr_t *addr)
 char *
 ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
 {
-  u32_t current_block_index, current_block_value;
-  s32_t zero_flag, i;
+  u32_t current_block_index, current_block_value, next_block_value;
+  s32_t i;
+  u8_t zero_flag, empty_block_flag;
 
   i = 0;
-  zero_flag = 0; /* used to indicate a zero chain for "::' */
+  empty_block_flag = 0; /* used to indicate a zero chain for "::' */
 
   for (current_block_index = 0; current_block_index < 8; current_block_index++) {
     /* get the current 16-bit block */
@@ -187,53 +205,82 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
     }
     current_block_value &= 0xffff;
 
+    /* Check for empty block. */
     if (current_block_value == 0) {
-      /* generate empty block "::" */
-      if (!zero_flag) {
-        if (current_block_index > 0) {
-          zero_flag = 1;
+      if (current_block_index == 7) {
+        /* special case, we must render a ':' for the last block. */
+        buf[i++] = ':';
+        if (i >= buflen) {
+          return NULL;
+        }
+        break;
+      }
+      if (empty_block_flag == 0) {
+        /* generate empty block "::", but only if more than one contiguous zero block,
+         * according to current formatting suggestions RFC 5952. */
+        next_block_value = htonl(addr->addr[(current_block_index + 1) >> 1]);
+        if ((current_block_index & 0x1) == 0x01) {
+            next_block_value = next_block_value >> 16;
+        }
+        next_block_value &= 0xffff;
+        if (next_block_value == 0) {
+          empty_block_flag = 1;
           buf[i++] = ':';
-          if (i >= buflen) return NULL;
+          if (i >= buflen) {
+            return NULL;
+          }
+          continue; /* move on to next block. */
         }
+      } else if (empty_block_flag == 1) {
+        /* move on to next block. */
+        continue;
       }
+    } else if (empty_block_flag == 1) {
+      /* Set this flag value so we don't produce multiple empty blocks. */
+      empty_block_flag = 2;
     }
-    else {
-      if (current_block_index > 0) {
-        buf[i++] = ':';
-        if (i >= buflen) return NULL;
-      }
 
-      if ((current_block_value & 0xf000) == 0) {
-        zero_flag = 1;
-      }
-      else {
-        buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
-        zero_flag = 0;
-        if (i >= buflen) return NULL;
+    if (current_block_index > 0) {
+      buf[i++] = ':';
+      if (i >= buflen) {
+        return NULL;
       }
+    }
 
-      if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
-        /* do nothing */
-      }
-      else {
-        buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
-        zero_flag = 0;
-        if (i >= buflen) return NULL;
+    if ((current_block_value & 0xf000) == 0) {
+      zero_flag = 1;
+    } else {
+      buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
+      zero_flag = 0;
+      if (i >= buflen) {
+        return NULL;
       }
+    }
 
-      if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
-        /* do nothing */
-      }
-      else {
-        buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
-        zero_flag = 0;
-        if (i >= buflen) return NULL;
+    if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
+      /* do nothing */
+    } else {
+      buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
+      zero_flag = 0;
+      if (i >= buflen) {
+        return NULL;
       }
+    }
 
-      buf[i++] = xchar((current_block_value & 0xf));
-      if (i >= buflen) return NULL;
-
+    if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
+      /* do nothing */
+    }
+    else {
+      buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
       zero_flag = 0;
+      if (i >= buflen) {
+        return NULL;
+      }
+    }
+
+    buf[i++] = xchar((current_block_value & 0xf));
+    if (i >= buflen) {
+      return NULL;
     }
   }
 
@@ -241,4 +288,43 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
 
   return buf;
 }
+
+#if LWIP_IPV4
+/** Convert IP address string (both versions) to numeric.
+ * The version is auto-detected from the string.
+ *
+ * @param cp IP address string to convert
+ * @param addr conversion result is stored here
+ * @return 1 on success, 0 on error
+ */
+int
+ipaddr_aton(const char *cp, ip_addr_t *addr)
+{
+  if (cp != NULL) {
+    const char* c;
+    for (c = cp; *c != 0; c++) {
+      if (*c == ':') {
+        /* contains a colon: IPv6 address */
+        if (addr) {
+          IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6);
+        }
+        return ip6addr_aton(cp, ip_2_ip6(addr));
+      } else if (*c == '.') {
+        /* contains a dot: IPv4 address */
+        if (addr) {
+          IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4);
+        }
+        return ip4addr_aton(cp, ip_2_ip4(addr));
+      }
+    }
+    /* nothing found, call ip4addr_aton as fallback */
+    if (addr) {
+      IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4);
+    }
+    return ip4addr_aton(cp, ip_2_ip4(addr));
+  }
+  return 0;
+}
+#endif /* LWIP_IPV4 */
+
 #endif /* LWIP_IPV6 */