| /** |
| * @file |
| * |
| * IPv6 addresses. |
| */ |
| |
| /* |
| * Copyright (c) 2010 Inico Technologies Ltd. |
| * 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. |
| * 2. Redistributions in binary form must reproduce 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. |
| * |
| * 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. |
| * |
| * Please coordinate changes and requests with Ivan Delamer |
| * <delamer@inicotech.com> |
| */ |
| |
| #include "lwip/opt.h" |
| |
| #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ |
| |
| #include "lwip/ip6_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 } }; |
| |
| #ifndef isprint |
| #define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) |
| #define isprint(c) in_range(c, 0x20, 0x7f) |
| #define isdigit(c) in_range(c, '0', '9') |
| #define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) |
| #define islower(c) in_range(c, 'a', 'z') |
| #define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') |
| #define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) |
| #endif |
| |
| /** |
| * Check whether "cp" is a valid ascii representation |
| * 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 addr pointer to which to save the ip address in network order |
| * @return 1 if cp could be converted to addr, 0 on failure |
| */ |
| int |
| ip6addr_aton(const char *cp, ip6_addr_t *addr) |
| { |
| u32_t addr_index, zero_blocks, current_block_index, current_block_value; |
| const char * s; |
| |
| /* Count the number of colons, to count the number of blocks in a "::" sequence |
| zero_blocks may be 1 even if there are no :: sequences */ |
| zero_blocks = 8; |
| for (s = cp; *s != 0; s++) { |
| if (*s == ':') |
| zero_blocks--; |
| else if (!isxdigit(*s)) |
| break; |
| } |
| |
| /* parse each block */ |
| addr_index = 0; |
| current_block_index = 0; |
| current_block_value = 0; |
| for (s = cp; *s != 0; s++) { |
| if (*s == ':') { |
| 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] == ':') { |
| s++; |
| /* "::" found, set zeros */ |
| while (zero_blocks-- > 0) { |
| if (current_block_index & 0x1) { |
| addr_index++; |
| } |
| else { |
| if (addr) { |
| addr->addr[addr_index] = 0; |
| } |
| } |
| current_block_index++; |
| } |
| } |
| } else if (isxdigit(*s)) { |
| /* add current digit */ |
| current_block_value = (current_block_value << 4) + |
| (isdigit(*s) ? *s - '0' : |
| 10 + (islower(*s) ? *s - 'a' : *s - 'A')); |
| } else { |
| /* unexpected digit, space? CRLF? */ |
| break; |
| } |
| } |
| |
| 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. */ |
| 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) { |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| /** |
| * Convert numeric IPv6 address into ASCII representation. |
| * returns ptr to static buffer; not reentrant! |
| * |
| * @param addr ip6 address in network order to convert |
| * @return pointer to a global static (!) buffer that holds the ASCII |
| * represenation of addr |
| */ |
| char * |
| ip6addr_ntoa(const ip6_addr_t *addr) |
| { |
| static char str[40]; |
| return ip6addr_ntoa_r(addr, str, 40); |
| } |
| |
| /** |
| * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. |
| * |
| * @param addr ip6 address in network order to convert |
| * @param buf target buffer where the string is stored |
| * @param buflen length of buf |
| * @return either pointer to buf which now holds the ASCII |
| * representation of addr or NULL if buf was too small |
| */ |
| char * |
| ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) |
| { |
| u32_t current_block_index, current_block_value, current_byte = 0; |
| |
| for (current_block_index = 0; current_block_index < 8; current_block_index++) { |
| /* get the current 16-bit block */ |
| current_block_value = htonl(addr->addr[current_block_index >> 1]); |
| if ((current_block_index & 0x1) == 0) { |
| current_block_value = current_block_value >> 16; |
| } |
| |
| sprintf(&buf[current_byte], "%.4lx", current_block_value & 0xffff); |
| if (current_block_index < 7) |
| { |
| buf[current_byte + 4] = ':'; |
| } |
| current_byte += 5; |
| } |
| |
| return buf; |
| } |
| #endif /* LWIP_IPV6 */ |