#include "lwip/opt.h"
#if LWIP_IPV6
#include "lwip/ip_addr.h"
#include "lwip/def.h"
#include "lwip/netif.h"
#include <string.h>
#if LWIP_IPV4
#include "lwip/ip4_addr.h"
#endif
const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
#define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10))
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;
#if LWIP_IPV4
int check_ipv4_mapped = 0;
#endif
zero_blocks = 8;
for (s = cp; *s != 0; s++) {
if (*s == ':') {
zero_blocks--;
#if LWIP_IPV4
} else if (*s == '.') {
if ((zero_blocks == 5) ||(zero_blocks == 2)) {
check_ipv4_mapped = 1;
zero_blocks--;
} else {
return 0;
}
break;
#endif
} else if (!lwip_isxdigit(*s)) {
break;
}
}
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++;
#if LWIP_IPV4
if (check_ipv4_mapped) {
if (current_block_index == 6) {
ip4_addr_t ip4;
int ret = ip4addr_aton(s + 1, &ip4);
if (ret) {
if (addr) {
addr->addr[3] = lwip_htonl(ip4.addr);
current_block_index++;
goto fix_byte_order_and_return;
}
return 1;
}
}
}
#endif
current_block_value = 0;
if (current_block_index > 7) {
return 0;
}
if (s[1] == ':') {
if (s[2] == ':') {
return 0;
}
s++;
while (zero_blocks > 0) {
zero_blocks--;
if (current_block_index & 0x1) {
addr_index++;
} else {
if (addr) {
addr->addr[addr_index] = 0;
}
}
current_block_index++;
if (current_block_index > 7) {
return 0;
}
}
}
} else if (lwip_isxdigit(*s)) {
current_block_value = (current_block_value << 4) +
(lwip_isdigit(*s) ? (u32_t)(*s - '0') :
(u32_t)(10 + (lwip_islower(*s) ? *s - 'a' : *s - 'A')));
} else {
break;
}
}
if (addr) {
if (current_block_index & 0x1) {
addr->addr[addr_index++] |= current_block_value;
}
else {
addr->addr[addr_index] = current_block_value << 16;
}
#if LWIP_IPV4
fix_byte_order_and_return:
#endif
for (addr_index = 0; addr_index < 4; addr_index++) {
addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
}
ip6_addr_clear_zone(addr);
#if LWIP_IPV6_SCOPES
if (*s == '%') {
const char *scopestr = s + 1;
if (*scopestr) {
struct netif *netif = netif_find(scopestr);
if (netif) {
ip6_addr_assign_zone(addr, IP6_UNKNOWN, netif);
}
}
}
#endif
}
if (current_block_index != 7) {
return 0;
}
return 1;
}
char *
ip6addr_ntoa(const ip6_addr_t *addr)
{
static char str[40];
return ip6addr_ntoa_r(addr, str, 40);
}
char *
ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
{
u32_t current_block_index, current_block_value, next_block_value;
s32_t i;
u8_t zero_flag, empty_block_flag;
#if LWIP_IPV4
if (ip6_addr_isipv4mappedipv6(addr)) {
ip4_addr_t addr4;
char *ret;
#define IP4MAPPED_HEADER "::FFFF:"
char *buf_ip4 = buf + sizeof(IP4MAPPED_HEADER) - 1;
int buflen_ip4 = buflen - sizeof(IP4MAPPED_HEADER) + 1;
if (buflen < (int)sizeof(IP4MAPPED_HEADER)) {
return NULL;
}
memcpy(buf, IP4MAPPED_HEADER, sizeof(IP4MAPPED_HEADER));
addr4.addr = addr->addr[3];
ret = ip4addr_ntoa_r(&addr4, buf_ip4, buflen_ip4);
if (ret != buf_ip4) {
return NULL;
}
return buf;
}
#endif
i = 0;
empty_block_flag = 0;
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16;
}
current_block_value &= 0xffff;
if (current_block_value == 0) {
if (current_block_index == 7 && empty_block_flag == 1) {
buf[i++] = ':';
if (i >= buflen) {
return NULL;
}
break;
}
if (empty_block_flag == 0) {
next_block_value = lwip_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;
}
continue;
}
} else if (empty_block_flag == 1) {
continue;
}
} else if (empty_block_flag == 1) {
empty_block_flag = 2;
}
if (current_block_index > 0) {
buf[i++] = ':';
if (i >= buflen) {
return NULL;
}
}
if ((current_block_value & 0xf000) == 0) {
zero_flag = 1;
} else {
buf[i++] = lwip_xchar(((current_block_value & 0xf000) >> 12));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
} else {
buf[i++] = lwip_xchar(((current_block_value & 0xf00) >> 8));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
}
else {
buf[i++] = lwip_xchar(((current_block_value & 0xf0) >> 4));
zero_flag = 0;
if (i >= buflen) {
return NULL;
}
}
buf[i++] = lwip_xchar((current_block_value & 0xf));
if (i >= buflen) {
return NULL;
}
}
buf[i] = 0;
return buf;
}
#endif