Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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 #include <string.h>
00051 
00052 #if LWIP_IPV4
00053 #include "lwip/ip4_addr.h" /* for ip6addr_aton to handle IPv4-mapped addresses */
00054 #endif /* LWIP_IPV4 */
00055 
00056 /* used by IP6_ADDR_ANY(6) in ip6_addr.h */
00057 const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
00058 
00059 #define lwip_xchar(i)        ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10))
00060 
00061 /**
00062  * Check whether "cp" is a valid ascii representation
00063  * of an IPv6 address and convert to a binary address.
00064  * Returns 1 if the address is valid, 0 if not.
00065  *
00066  * @param cp IPv6 address in ascii representation (e.g. "FF01::1")
00067  * @param addr pointer to which to save the ip address in network order
00068  * @return 1 if cp could be converted to addr, 0 on failure
00069  */
00070 int
00071 ip6addr_aton(const char *cp, ip6_addr_t *addr)
00072 {
00073   u32_t addr_index, zero_blocks, current_block_index, current_block_value;
00074   const char *s;
00075 #if LWIP_IPV4
00076   int check_ipv4_mapped = 0;
00077 #endif /* LWIP_IPV4 */
00078 
00079   /* Count the number of colons, to count the number of blocks in a "::" sequence
00080      zero_blocks may be 1 even if there are no :: sequences */
00081   zero_blocks = 8;
00082   for (s = cp; *s != 0; s++) {
00083     if (*s == ':') {
00084       zero_blocks--;
00085 #if LWIP_IPV4
00086     } else if (*s == '.') {
00087       if ((zero_blocks == 5) ||(zero_blocks == 2)) {
00088         check_ipv4_mapped = 1;
00089         /* last block could be the start of an IPv4 address */
00090         zero_blocks--;
00091       } else {
00092         /* invalid format */
00093         return 0;
00094       }
00095       break;
00096 #endif /* LWIP_IPV4 */
00097     } else if (!lwip_isxdigit(*s)) {
00098       break;
00099     }
00100   }
00101 
00102   /* parse each block */
00103   addr_index = 0;
00104   current_block_index = 0;
00105   current_block_value = 0;
00106   for (s = cp; *s != 0; s++) {
00107     if (*s == ':') {
00108       if (addr) {
00109         if (current_block_index & 0x1) {
00110           addr->addr[addr_index++] |= current_block_value;
00111         }
00112         else {
00113           addr->addr[addr_index] = current_block_value << 16;
00114         }
00115       }
00116       current_block_index++;
00117 #if LWIP_IPV4
00118       if (check_ipv4_mapped) {
00119         if (current_block_index == 6) {
00120           ip4_addr_t ip4;
00121           int ret = ip4addr_aton(s + 1, &ip4);
00122           if (ret) {
00123             if (addr) {
00124               addr->addr[3] = lwip_htonl(ip4.addr);
00125               current_block_index++;
00126               goto fix_byte_order_and_return;
00127             }
00128             return 1;
00129           }
00130         }
00131       }
00132 #endif /* LWIP_IPV4 */
00133       current_block_value = 0;
00134       if (current_block_index > 7) {
00135         /* address too long! */
00136         return 0;
00137       }
00138       if (s[1] == ':') {
00139         if (s[2] == ':') {
00140           /* invalid format: three successive colons */
00141           return 0;
00142         }
00143         s++;
00144         /* "::" found, set zeros */
00145         while (zero_blocks > 0) {
00146           zero_blocks--;
00147           if (current_block_index & 0x1) {
00148             addr_index++;
00149           } else {
00150             if (addr) {
00151               addr->addr[addr_index] = 0;
00152             }
00153           }
00154           current_block_index++;
00155           if (current_block_index > 7) {
00156             /* address too long! */
00157             return 0;
00158           }
00159         }
00160       }
00161     } else if (lwip_isxdigit(*s)) {
00162       /* add current digit */
00163       current_block_value = (current_block_value << 4) +
00164           (lwip_isdigit(*s) ? (u32_t)(*s - '0') :
00165           (u32_t)(10 + (lwip_islower(*s) ? *s - 'a' : *s - 'A')));
00166     } else {
00167       /* unexpected digit, space? CRLF? */
00168       break;
00169     }
00170   }
00171 
00172   if (addr) {
00173     if (current_block_index & 0x1) {
00174       addr->addr[addr_index++] |= current_block_value;
00175     }
00176     else {
00177       addr->addr[addr_index] = current_block_value << 16;
00178     }
00179 #if LWIP_IPV4
00180 fix_byte_order_and_return:
00181 #endif
00182     /* convert to network byte order. */
00183     for (addr_index = 0; addr_index < 4; addr_index++) {
00184       addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
00185     }
00186 
00187     ip6_addr_clear_zone(addr);
00188   }
00189 
00190   if (current_block_index != 7) {
00191     return 0;
00192   }
00193 
00194   return 1;
00195 }
00196 
00197 /**
00198  * Convert numeric IPv6 address into ASCII representation.
00199  * returns ptr to static buffer; not reentrant!
00200  *
00201  * @param addr ip6 address in network order to convert
00202  * @return pointer to a global static (!) buffer that holds the ASCII
00203  *         representation of addr
00204  */
00205 char *
00206 ip6addr_ntoa(const ip6_addr_t *addr)
00207 {
00208   static char str[40];
00209   return ip6addr_ntoa_r(addr, str, 40);
00210 }
00211 
00212 /**
00213  * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
00214  *
00215  * @param addr ip6 address in network order to convert
00216  * @param buf target buffer where the string is stored
00217  * @param buflen length of buf
00218  * @return either pointer to buf which now holds the ASCII
00219  *         representation of addr or NULL if buf was too small
00220  */
00221 char *
00222 ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
00223 {
00224   u32_t current_block_index, current_block_value, next_block_value;
00225   s32_t i;
00226   u8_t zero_flag, empty_block_flag;
00227 
00228 #if LWIP_IPV4
00229   if (ip6_addr_isipv4mappedipv6(addr)) {
00230     /* This is an IPv4 mapped address */
00231     ip4_addr_t addr4;
00232     char *ret;
00233 #define IP4MAPPED_HEADER "::FFFF:"
00234     char *buf_ip4 = buf + sizeof(IP4MAPPED_HEADER) - 1;
00235     int buflen_ip4 = buflen - sizeof(IP4MAPPED_HEADER) + 1;
00236     if (buflen < (int)sizeof(IP4MAPPED_HEADER)) {
00237       return NULL;
00238     }
00239     memcpy(buf, IP4MAPPED_HEADER, sizeof(IP4MAPPED_HEADER));
00240     addr4.addr = addr->addr[3];
00241     ret = ip4addr_ntoa_r(&addr4, buf_ip4, buflen_ip4);
00242     if (ret != buf_ip4) {
00243       return NULL;
00244     }
00245     return buf;
00246   }
00247 #endif /* LWIP_IPV4 */
00248   i = 0;
00249   empty_block_flag = 0; /* used to indicate a zero chain for "::' */
00250 
00251   for (current_block_index = 0; current_block_index < 8; current_block_index++) {
00252     /* get the current 16-bit block */
00253     current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
00254     if ((current_block_index & 0x1) == 0) {
00255       current_block_value = current_block_value >> 16;
00256     }
00257     current_block_value &= 0xffff;
00258 
00259     /* Check for empty block. */
00260     if (current_block_value == 0) {
00261       if (current_block_index == 7 && empty_block_flag == 1) {
00262         /* special case, we must render a ':' for the last block. */
00263         buf[i++] = ':';
00264         if (i >= buflen) {
00265           return NULL;
00266         }
00267         break;
00268       }
00269       if (empty_block_flag == 0) {
00270         /* generate empty block "::", but only if more than one contiguous zero block,
00271          * according to current formatting suggestions RFC 5952. */
00272         next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
00273         if ((current_block_index & 0x1) == 0x01) {
00274             next_block_value = next_block_value >> 16;
00275         }
00276         next_block_value &= 0xffff;
00277         if (next_block_value == 0) {
00278           empty_block_flag = 1;
00279           buf[i++] = ':';
00280           if (i >= buflen) {
00281             return NULL;
00282           }
00283           continue; /* move on to next block. */
00284         }
00285       } else if (empty_block_flag == 1) {
00286         /* move on to next block. */
00287         continue;
00288       }
00289     } else if (empty_block_flag == 1) {
00290       /* Set this flag value so we don't produce multiple empty blocks. */
00291       empty_block_flag = 2;
00292     }
00293 
00294     if (current_block_index > 0) {
00295       buf[i++] = ':';
00296       if (i >= buflen) {
00297         return NULL;
00298       }
00299     }
00300 
00301     if ((current_block_value & 0xf000) == 0) {
00302       zero_flag = 1;
00303     } else {
00304       buf[i++] = lwip_xchar(((current_block_value & 0xf000) >> 12));
00305       zero_flag = 0;
00306       if (i >= buflen) {
00307         return NULL;
00308       }
00309     }
00310 
00311     if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
00312       /* do nothing */
00313     } else {
00314       buf[i++] = lwip_xchar(((current_block_value & 0xf00) >> 8));
00315       zero_flag = 0;
00316       if (i >= buflen) {
00317         return NULL;
00318       }
00319     }
00320 
00321     if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
00322       /* do nothing */
00323     }
00324     else {
00325       buf[i++] = lwip_xchar(((current_block_value & 0xf0) >> 4));
00326       zero_flag = 0;
00327       if (i >= buflen) {
00328         return NULL;
00329       }
00330     }
00331 
00332     buf[i++] = lwip_xchar((current_block_value & 0xf));
00333     if (i >= buflen) {
00334       return NULL;
00335     }
00336   }
00337 
00338   buf[i] = 0;
00339 
00340   return buf;
00341 }
00342 
00343 #endif /* LWIP_IPV6 */