Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_ip6_addr.c
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 */
Generated on Tue Jul 12 2022 13:54:28 by
