From: <ljs...@us...> - 2010-10-13 15:57:26
|
Revision: 680 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=680&view=rev Author: ljsebald Date: 2010-10-13 15:57:20 +0000 (Wed, 13 Oct 2010) Log Message: ----------- Add a few more IPv6-related macros to <netinet/in.h>. Add IPv6 support to inet_ntop. Modified Paths: -------------- kos/include/netinet/in.h kos/kernel/libc/koslib/inet_ntop.c Modified: kos/include/netinet/in.h =================================================================== --- kos/include/netinet/in.h 2010-10-13 04:18:38 UTC (rev 679) +++ kos/include/netinet/in.h 2010-10-13 15:57:20 UTC (rev 680) @@ -10,9 +10,8 @@ This file contains the standard definitions (as directed by the POSIX 2008 standard) for internet-related functionality in the AF_INET address family. - This does not include anything related to AF_INET6 (as IPv6 is not currently - implemented in KOS), and is not guaranteed to have everything that one might - have in a fully-standard compliant implementation of the POSIX standard. + This does is not guaranteed to have everything that one might have in a + fully-standard compliant implementation of the POSIX standard. \author Lawrence Sebald */ @@ -213,6 +212,35 @@ (a)->__s6_addr.__s6_addr8[14] == 0 && \ (a)->__s6_addr.__s6_addr8[15] == 1) +/** \brief Test if an IPv6 Address is an IPv4 mapped address. + + This macro tests whether an IPv6 address (struct in6_addr *) is an IPv4 + mapped address. + + \param a The address to test (struct in6_addr *) + \return Nonzero if the address is IPv4 mapped, 0 otherwise. +*/ +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((a)->__s6_addr.__s6_addr32[0] == 0 && \ + (a)->__s6_addr.__s6_addr32[1] == 0 && \ + (a)->__s6_addr.__s6_addr16[4] == 0 && \ + (a)->__s6_addr.__s6_addr16[5] == 0xFFFF) + +/** \brief Test if an IPv6 Address is an IPv4 compatibility address. + + This macro tests whether an IPv6 address (struct in6_addr *) is an IPv4 + compatibility address. + + \param a The address to test (struct in6_addr *) + \return Nonzero if the address is IPv4 compat, 0 otherwise. +*/ +#define IN6_IS_ADDR_V4COMPAT(a) \ + ((a)->__s6_addr.__s6_addr32[0] == 0 && \ + (a)->__s6_addr.__s6_addr32[1] == 0 && \ + (a)->__s6_addr.__s6_addr32[2] == 0 && \ + (a)->__s6_addr.__s6_addr32[3] != 0 && \ + (a)->__s6_addr.__s6_addr8[15] != 1) + __END_DECLS #endif /* __NETINET_IN_H */ Modified: kos/kernel/libc/koslib/inet_ntop.c =================================================================== --- kos/kernel/libc/koslib/inet_ntop.c 2010-10-13 04:18:38 UTC (rev 679) +++ kos/kernel/libc/koslib/inet_ntop.c 2010-10-13 15:57:20 UTC (rev 680) @@ -1,29 +1,24 @@ /* KallistiOS ##version## inet_ntop.c - Copyright (C) 2007 Lawrence Sebald + Copyright (C) 2007, 2010 Lawrence Sebald */ #include <arpa/inet.h> #include <errno.h> -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { +static const char *inet_ntop4(const void *src, char *dst, socklen_t size) { char tmp[3]; int i, part; char *ch = tmp; char *ch2 = dst; struct in_addr *addr = (struct in_addr *)src; - if(af != AF_INET) { - errno = EAFNOSUPPORT; - return NULL; - } - /* Parse each 8 bits individually. */ for(i = 0; i < 4; ++i) { /* Treat the 32-bit address value as if it were an array of 8-bit - values. This works, regardless of the endianness of the host system + values. This works regardless of the endianness of the host system because the specs require the address passed in here to be in network byte order (big endian). */ part = ((uint8 *) &addr->s_addr)[i]; @@ -42,6 +37,7 @@ } if(!size) { + dst[0] = 0; errno = ENOSPC; return NULL; } @@ -56,3 +52,166 @@ return dst; } + +static const char *inet_ntop6(const void *src, char *dst, socklen_t size) { + struct in6_addr *addr = (struct in6_addr *)src; + int tmp[8] = { 0 }; + int runstart = -1, maxzero = 0, dcs = -1, i; + char tmpstr[4]; + char *ch = tmpstr, *ch2 = dst; + int part; + + /* Handle the special cases of IPv4 Mapped and Compatibility addresses */ + if(IN6_IS_ADDR_V4MAPPED(addr)) { + if(size > 7) { + dst[0] = dst[1] = dst[6] = ':'; + dst[2] = dst[3] = dst[4] = dst[5] = 'f'; + + /* Parse the IPv4 address at the end */ + if(!inet_ntop4(&addr->__s6_addr.__s6_addr32[3], dst + 7, size - 7)) + goto err; + + return dst; + } + else { + goto err; + } + } + else if(IN6_IS_ADDR_V4COMPAT(addr)) { + if(size > 2) { + dst[0] = dst[1] = ':'; + + /* Parse the IPv4 address at the end */ + if(!inet_ntop4(&addr->__s6_addr.__s6_addr32[3], dst + 2, size - 2)) + goto err; + + return dst; + } + else { + goto err; + } + } + + /* Figure out if we have any use for double colons in the address or not */ + for(i = 0; i < 8; ++i) { + if(addr->__s6_addr.__s6_addr16[i] == 0) { + if(runstart != -1) { + ++tmp[runstart]; + } + else { + runstart = i; + tmp[i] = 1; + } + + if(tmp[runstart] > maxzero) { + maxzero = tmp[runstart]; + dcs = runstart; + } + } + else { + runstart = -1; + } + } + + /* We should now know where the double colons will be, and how many zeroes + they will replace, the rest is pretty easy. */ + i = 0; + + if(dcs == 0) { + if(size > 2) { + *ch2++ = ':'; + *ch2++ = ':'; + size -= 2; + i = maxzero; + } + else { + goto err; + } + } + + while(i < 8) { + if(i == dcs) { + if(size > 1) { + *ch2++ = ':'; + --size; + i += maxzero; + } + else { + goto err; + } + } + else { + part = ntohs(addr->__s6_addr.__s6_addr16[i]); + + do { + *ch = (char)(part & 0x0f) + '0'; + part >>= 4; + + /* Deal with digits greater than 9 */ + if(*ch > '9') { + *ch = *ch - ':' + 'a'; + } + + ch++; + } while(part); + + /* tmp now contains the inverse of the number that is in the given + 16 bits. Reverse it for the final result, rewinding ch to the + beginning of tmpstr in the process. */ + while(ch != tmpstr && size) { + *ch2++ = *--ch; + --size; + } + + if(size < 1) { + goto err; + } + + *ch2++ = ':'; + --size; + ++i; + } + } + + /* Change the last : to a NUL terminator, unless the last set was where we + had a run of zeroes replaced by a :: */ + if(dcs + maxzero != 8) { + *(ch2 - 1) = 0; + } + else if(size > 0) { + *ch2 = 0; + } + else { + goto err; + } + + return dst; + +err: + /* In the event of an error, clear whatever we may have done */ + for(i = 0; i < size; ++i) { + dst[i] = 0; + } + + errno = ENOSPC; + return NULL; +} + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { + if(size < 1) { + errno = ENOSPC; + return NULL; + } + + switch(af) { + case AF_INET: + return inet_ntop4(src, dst, size); + + case AF_INET6: + return inet_ntop6(src, dst, size); + + default: + errno = EAFNOSUPPORT; + return NULL; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |