Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_ip6_addr.c Source File

lwip_ip6_addr.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  *
00004  * IPv6 addresses.
00005  */
00006 
00007 /*
00008  * Copyright (c) 2010 Inico Technologies Ltd.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Ivan Delamer <delamer@inicotech.com>
00036  *
00037  * Functions for handling IPv6 addresses.
00038  *
00039  * Please coordinate changes and requests with Ivan Delamer
00040  * <delamer@inicotech.com>
00041  */
00042 
00043 #include "lwip/opt.h"
00044 
00045 #if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
00046 
00047 #include "lwip/ip_addr.h"
00048 #include "lwip/def.h"
00049 
00050 /* used by IP6_ADDR_ANY(6) in ip6_addr.h */
00051 const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
00052 
00053 #ifndef isprint
00054 #define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
00055 #define isprint(c)           in_range(c, 0x20, 0x7f)
00056 #define isdigit(c)           in_range(c, '0', '9')
00057 #define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
00058 #define islower(c)           in_range(c, 'a', 'z')
00059 #define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
00060 #define xchar(i)             ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
00061 #endif
00062 
00063 /**
00064  * Check whether "cp" is a valid ascii representation
00065  * of an IPv6 address and convert to a binary address.
00066  * Returns 1 if the address is valid, 0 if not.
00067  *
00068  * @param cp IPv6 address in ascii representation (e.g. "FF01::1")
00069  * @param addr pointer to which to save the ip address in network order
00070  * @return 1 if cp could be converted to addr, 0 on failure
00071  */
00072 int
00073 ip6addr_aton(const char *cp, ip6_addr_t *addr)
00074 {
00075   u32_t addr_index, zero_blocks, current_block_index, current_block_value;
00076   const char *s;
00077 
00078   /* Count the number of colons, to count the number of blocks in a "::" sequence
00079      zero_blocks may be 1 even if there are no :: sequences */
00080   zero_blocks = 8;
00081   for (s = cp; *s != 0; s++) {
00082     if (*s == ':') {
00083       zero_blocks--;
00084     } else if (!isxdigit(*s)) {
00085       break;
00086     }
00087   }
00088 
00089   /* parse each block */
00090   addr_index = 0;
00091   current_block_index = 0;
00092   current_block_value = 0;
00093   for (s = cp; *s != 0; s++) {
00094     if (*s == ':') {
00095       if (addr) {
00096         if (current_block_index & 0x1) {
00097           addr->addr[addr_index++] |= current_block_value;
00098         }
00099         else {
00100           addr->addr[addr_index] = current_block_value << 16;
00101         }
00102       }
00103       current_block_index++;
00104       current_block_value = 0;
00105       if (current_block_index > 7) {
00106         /* address too long! */
00107         return 0;
00108       }
00109       if (s[1] == ':') {
00110         if (s[2] == ':') {
00111           /* invalid format: three successive colons */
00112           return 0;
00113         }
00114         s++;
00115         /* "::" found, set zeros */
00116         while (zero_blocks > 0) {
00117           zero_blocks--;
00118           if (current_block_index & 0x1) {
00119             addr_index++;
00120           } else {
00121             if (addr) {
00122               addr->addr[addr_index] = 0;
00123             }
00124           }
00125           current_block_index++;
00126           if (current_block_index > 7) {
00127             /* address too long! */
00128             return 0;
00129           }
00130         }
00131       }
00132     } else if (isxdigit(*s)) {
00133       /* add current digit */
00134       current_block_value = (current_block_value << 4) +
00135           (isdigit(*s) ? (u32_t)(*s - '0') :
00136           (u32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A')));
00137     } else {
00138       /* unexpected digit, space? CRLF? */
00139       break;
00140     }
00141   }
00142 
00143   if (addr) {
00144     if (current_block_index & 0x1) {
00145       addr->addr[addr_index++] |= current_block_value;
00146     }
00147     else {
00148       addr->addr[addr_index] = current_block_value << 16;
00149     }
00150   }
00151 
00152   /* convert to network byte order. */
00153   if (addr) {
00154     for (addr_index = 0; addr_index < 4; addr_index++) {
00155       addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
00156     }
00157   }
00158 
00159   if (current_block_index != 7) {
00160     return 0;
00161   }
00162 
00163   return 1;
00164 }
00165 
00166 /**
00167  * Convert numeric IPv6 address into ASCII representation.
00168  * returns ptr to static buffer; not reentrant!
00169  *
00170  * @param addr ip6 address in network order to convert
00171  * @return pointer to a global static (!) buffer that holds the ASCII
00172  *         representation of addr
00173  */
00174 char *
00175 ip6addr_ntoa(const ip6_addr_t *addr)
00176 {
00177   static char str[40];
00178   return ip6addr_ntoa_r(addr, str, 40);
00179 }
00180 
00181 /**
00182  * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
00183  *
00184  * @param addr ip6 address in network order to convert
00185  * @param buf target buffer where the string is stored
00186  * @param buflen length of buf
00187  * @return either pointer to buf which now holds the ASCII
00188  *         representation of addr or NULL if buf was too small
00189  */
00190 char *
00191 ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
00192 {
00193   u32_t current_block_index, current_block_value, next_block_value;
00194   s32_t i;
00195   u8_t zero_flag, empty_block_flag;
00196 
00197   i = 0;
00198   empty_block_flag = 0; /* used to indicate a zero chain for "::' */
00199 
00200   for (current_block_index = 0; current_block_index < 8; current_block_index++) {
00201     /* get the current 16-bit block */
00202     current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
00203     if ((current_block_index & 0x1) == 0) {
00204       current_block_value = current_block_value >> 16;
00205     }
00206     current_block_value &= 0xffff;
00207 
00208     /* Check for empty block. */
00209     if (current_block_value == 0) {
00210       if (current_block_index == 7 && empty_block_flag == 1) {
00211         /* special case, we must render a ':' for the last block. */
00212         buf[i++] = ':';
00213         if (i >= buflen) {
00214           return NULL;
00215         }
00216         break;
00217       }
00218       if (empty_block_flag == 0) {
00219         /* generate empty block "::", but only if more than one contiguous zero block,
00220          * according to current formatting suggestions RFC 5952. */
00221         next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
00222         if ((current_block_index & 0x1) == 0x01) {
00223             next_block_value = next_block_value >> 16;
00224         }
00225         next_block_value &= 0xffff;
00226         if (next_block_value == 0) {
00227           empty_block_flag = 1;
00228           buf[i++] = ':';
00229           if (i >= buflen) {
00230             return NULL;
00231           }
00232           continue; /* move on to next block. */
00233         }
00234       } else if (empty_block_flag == 1) {
00235         /* move on to next block. */
00236         continue;
00237       }
00238     } else if (empty_block_flag == 1) {
00239       /* Set this flag value so we don't produce multiple empty blocks. */
00240       empty_block_flag = 2;
00241     }
00242 
00243     if (current_block_index > 0) {
00244       buf[i++] = ':';
00245       if (i >= buflen) {
00246         return NULL;
00247       }
00248     }
00249 
00250     if ((current_block_value & 0xf000) == 0) {
00251       zero_flag = 1;
00252     } else {
00253       buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
00254       zero_flag = 0;
00255       if (i >= buflen) {
00256         return NULL;
00257       }
00258     }
00259 
00260     if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
00261       /* do nothing */
00262     } else {
00263       buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
00264       zero_flag = 0;
00265       if (i >= buflen) {
00266         return NULL;
00267       }
00268     }
00269 
00270     if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
00271       /* do nothing */
00272     }
00273     else {
00274       buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
00275       zero_flag = 0;
00276       if (i >= buflen) {
00277         return NULL;
00278       }
00279     }
00280 
00281     buf[i++] = xchar((current_block_value & 0xf));
00282     if (i >= buflen) {
00283       return NULL;
00284     }
00285   }
00286 
00287   buf[i] = 0;
00288 
00289   return buf;
00290 }
00291 
00292 #endif /* LWIP_IPV6 */