Index: uspace/lib/c/generic/inet/addr.c
===================================================================
--- uspace/lib/c/generic/inet/addr.c	(revision 679ee84093527838b4f51339e86d1cd6c4ea1815)
+++ uspace/lib/c/generic/inet/addr.c	(revision 1d24ad312b4ddcdf3dc7c30ee0effc5293fd669c)
@@ -39,14 +39,145 @@
 #include <net/inet.h>
 #include <stdio.h>
-
-static inet_addr_t inet_addr_any_addr = {
+#include <malloc.h>
+#include <bitops.h>
+
+#define INET_PREFIXSTRSIZE  5
+
+#if !(defined(__BE__) ^ defined(__LE__))
+	#error The architecture must be either big-endian or little-endian.
+#endif
+
+const addr48_t addr48_broadcast = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const inet_addr_t inet_addr_any_addr = {
 	.family = AF_INET,
-	.addr = {0, 0, 0, 0}
+	.addr = 0
 };
 
-static inet_addr_t inet_addr_any_addr6 = {
+static const inet_addr_t inet_addr_any_addr6 = {
 	.family = AF_INET6,
-	.addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	.addr6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 };
+
+void addr48(const addr48_t src, addr48_t dst)
+{
+	memcpy(dst, src, 6);
+}
+
+void addr128(const addr128_t src, addr128_t dst)
+{
+	memcpy(dst, src, 16);
+}
+
+void host2addr128_t_be(const addr128_t host, addr128_t be)
+{
+#ifdef __BE__
+	memcpy(be, host, 16);
+#else
+	be[0] = host[15];
+	be[1] = host[14];
+	be[2] = host[13];
+	be[3] = host[12];
+	be[4] = host[11];
+	be[5] = host[10];
+	be[6] = host[9];
+	be[7] = host[8];
+	be[8] = host[7];
+	be[9] = host[6];
+	be[10] = host[5];
+	be[11] = host[4];
+	be[12] = host[3];
+	be[13] = host[2];
+	be[14] = host[1];
+	be[15] = host[0];
+#endif
+}
+
+void addr128_t_be2host(const addr128_t be, addr128_t host)
+{
+#ifdef __BE__
+	memcpy(host, be, 16);
+#else
+	host[0] = be[15];
+	host[1] = be[14];
+	host[2] = be[13];
+	host[3] = be[12];
+	host[4] = be[11];
+	host[5] = be[10];
+	host[6] = be[9];
+	host[7] = be[8];
+	host[8] = be[7];
+	host[9] = be[6];
+	host[10] = be[5];
+	host[11] = be[4];
+	host[12] = be[3];
+	host[13] = be[2];
+	host[14] = be[1];
+	host[15] = be[0];
+#endif
+}
+
+void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+{
+	addr->family = AF_INET;
+	addr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
+	    ((addr32_t) c << 8) | ((addr32_t) d);
+}
+
+void inet_naddr(inet_naddr_t *naddr, uint8_t a, uint8_t b, uint8_t c, uint8_t d,
+    uint8_t prefix)
+{
+	naddr->family = AF_INET;
+	naddr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
+	    ((addr32_t) c << 8) | ((addr32_t) d);
+	naddr->prefix = prefix;
+}
+
+void inet_addr6(inet_addr_t *addr, uint16_t a, uint16_t b, uint16_t c,
+    uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
+{
+	addr->family = AF_INET6;
+	addr->addr6[0] = (a >> 8) & 0xff;
+	addr->addr6[1] = a & 0xff;
+	addr->addr6[2] = (b >> 8) & 0xff;
+	addr->addr6[3] = b & 0xff;
+	addr->addr6[4] = (c >> 8) & 0xff;
+	addr->addr6[5] = c & 0xff;
+	addr->addr6[6] = (d >> 8) & 0xff;
+	addr->addr6[7] = d & 0xff;
+	addr->addr6[8] = (e >> 8) & 0xff;
+	addr->addr6[9] = e & 0xff;
+	addr->addr6[10] = (f >> 8) & 0xff;
+	addr->addr6[11] = f & 0xff;
+	addr->addr6[12] = (g >> 8) & 0xff;
+	addr->addr6[13] = g & 0xff;
+	addr->addr6[14] = (h >> 8) & 0xff;
+	addr->addr6[15] = h & 0xff;
+}
+
+void inet_naddr6(inet_naddr_t *naddr, uint16_t a, uint16_t b, uint16_t c,
+    uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint8_t prefix)
+{
+	naddr->family = AF_INET6;
+	naddr->addr6[0] = (a >> 8) & 0xff;
+	naddr->addr6[1] = a & 0xff;
+	naddr->addr6[2] = (b >> 8) & 0xff;
+	naddr->addr6[3] = b & 0xff;
+	naddr->addr6[4] = (c >> 8) & 0xff;
+	naddr->addr6[5] = c & 0xff;
+	naddr->addr6[6] = (d >> 8) & 0xff;
+	naddr->addr6[7] = d & 0xff;
+	naddr->addr6[8] = (e >> 8) & 0xff;
+	naddr->addr6[9] = e & 0xff;
+	naddr->addr6[10] = (f >> 8) & 0xff;
+	naddr->addr6[11] = f & 0xff;
+	naddr->addr6[12] = (g >> 8) & 0xff;
+	naddr->addr6[13] = g & 0xff;
+	naddr->addr6[14] = (h >> 8) & 0xff;
+	naddr->addr6[15] = h & 0xff;
+	naddr->prefix = prefix;
+}
 
 /** Parse network address family.
@@ -72,6 +203,90 @@
 	}
 	
-	*af = AF_NONE;
 	return EINVAL;
+}
+
+void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
+{
+	addr->family = naddr->family;
+	memcpy(addr->addr6, naddr->addr6, 16);
+}
+
+void inet_addr_any(inet_addr_t *addr)
+{
+	addr->family = AF_NONE;
+	memset(addr->addr6, 0, 16);
+}
+
+void inet_naddr_any(inet_naddr_t *naddr)
+{
+	naddr->family = AF_NONE;
+	memset(naddr->addr6, 0, 16);
+	naddr->prefix = 0;
+}
+
+int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
+{
+	if (a->family != b->family)
+		return 0;
+	
+	switch (a->family) {
+	case AF_INET:
+		return (a->addr == b->addr);
+	case AF_INET6:
+		return memcmp(&a->addr6, &b->addr6, 16);
+	default:
+		return 0;
+	}
+}
+
+int inet_addr_is_any(const inet_addr_t *addr)
+{
+	return ((addr->family == 0) ||
+	    (inet_addr_compare(addr, &inet_addr_any_addr)) ||
+	    (inet_addr_compare(addr, &inet_addr_any_addr6)));
+}
+
+int inet_naddr_compare_mask(const inet_naddr_t *naddr, const inet_addr_t *addr)
+{
+	if (naddr->family != addr->family)
+		return 0;
+	
+	switch (naddr->family) {
+	case AF_INET:
+		if (naddr->prefix > 32)
+			return 0;
+		
+		addr32_t mask =
+		    BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
+		return ((naddr->addr & mask) == (addr->addr & mask));
+	case AF_INET6:
+		if (naddr->prefix > 128)
+			return 0;
+		
+		size_t pos = 0;
+		for (size_t i = 0; i < 16; i++) {
+			/* Further bits do not matter */
+			if (naddr->prefix < pos)
+				break;
+			
+			if (naddr->prefix - pos > 8) {
+				/* Comparison without masking */
+				if (naddr->addr6[i] != addr->addr6[i])
+					return 0;
+			} else {
+				/* Comparison with masking */
+				uint8_t mask =
+				    BIT_RANGE(uint8_t, 8, 8 - (naddr->prefix - pos - 1));
+				if ((naddr->addr6[i] & mask) != (addr->addr6[i] & mask))
+					return 0;
+			}
+			
+			pos += 8;
+		}
+		
+		return 1;
+	default:
+		return 0;
+	}
 }
 
@@ -90,7 +305,20 @@
 		return rc;
 	
-	rc = inet_pton(addr->family, text, addr->addr);
+	uint8_t buf[16];
+	rc = inet_pton(addr->family, text, buf);
 	if (rc != EOK)
 		return rc;
+	
+	switch (addr->family) {
+	case AF_INET:
+		addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
+		    buf[3];
+		break;
+	case AF_INET6:
+		memcpy(addr->addr6, buf, 16);
+		break;
+	default:
+		return EINVAL;
+	}
 	
 	return EOK;
@@ -117,5 +345,6 @@
 		return rc;
 	
-	rc = inet_pton(naddr->family, text, naddr->addr);
+	uint8_t buf[16];
+	rc = inet_pton(naddr->family, text, buf);
 	*slash = '/';
 	
@@ -124,15 +353,25 @@
 	
 	slash++;
+	uint8_t prefix;
 	
 	switch (naddr->family) {
 	case AF_INET:
-		naddr->prefix = strtoul(slash, &slash, 10);
-		if (naddr->prefix > 32)
+		prefix = strtoul(slash, &slash, 10);
+		if (prefix > 32)
 			return EINVAL;
-		break;
-	case AF_INET6:
-		naddr->prefix = strtoul(slash, &slash, 10);
-		if (naddr->prefix > 128)
+		
+		naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
+		    buf[3];
+		naddr->prefix = prefix;
+		
+		break;
+	case AF_INET6:
+		prefix = strtoul(slash, &slash, 10);
+		if (prefix > 128)
 			return EINVAL;
+		
+		memcpy(naddr->addr6, buf, 16);
+		naddr->prefix = prefix;
+		
 		break;
 	default:
@@ -153,7 +392,7 @@
  *
  */
-int inet_addr_format(inet_addr_t *addr, char **bufp)
-{
-	int rc;
+int inet_addr_format(const inet_addr_t *addr, char **bufp)
+{
+	int rc = 0;
 	
 	switch (addr->family) {
@@ -162,10 +401,14 @@
 		break;
 	case AF_INET:
-		rc = asprintf(bufp, "%u.%u.%u.%u", addr->addr[0],
-		    addr->addr[1], addr->addr[2], addr->addr[3]);
-		break;
-	case AF_INET6:
-		// FIXME TODO
-		return ENOTSUP;
+		rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
+		    (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
+		    addr->addr & 0xff);
+		break;
+	case AF_INET6:
+		*bufp = (char *) malloc(INET6_ADDRSTRLEN);
+		if (*bufp == NULL)
+			return ENOMEM;
+		
+		return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN);
 	default:
 		return ENOTSUP;
@@ -188,7 +431,8 @@
  *
  */
-int inet_naddr_format(inet_naddr_t *naddr, char **bufp)
-{
-	int rc;
+int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
+{
+	int rc = 0;
+	char prefix[INET_PREFIXSTRSIZE];
 	
 	switch (naddr->family) {
@@ -197,11 +441,31 @@
 		break;
 	case AF_INET:
-		rc = asprintf(bufp, "%u.%u.%u.%u/%u", naddr->addr[0],
-		    naddr->addr[1], naddr->addr[2], naddr->addr[3],
+		rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
+		    "/%" PRIu8, (naddr->addr >> 24) & 0xff,
+		    (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff,
+		    naddr->addr & 0xff, naddr->prefix);
+		break;
+	case AF_INET6:
+		*bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
+		if (*bufp == NULL)
+			return ENOMEM;
+		
+		rc = inet_ntop(AF_INET6, naddr->addr6, *bufp,
+		    INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
+		if (rc != EOK) {
+			free(*bufp);
+			return rc;
+		}
+		
+		rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8,
 		    naddr->prefix);
-		break;
-	case AF_INET6:
-		// FIXME TODO
-		return ENOTSUP;
+		if (rc < 0) {
+			free(*bufp);
+			return ENOMEM;
+		}
+		
+		str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix);
+		
+		break;
 	default:
 		return ENOTSUP;
@@ -214,141 +478,107 @@
 }
 
-/** Create packed IPv4 address
- *
- * Convert an IPv4 address to a packed 32 bit representation.
- *
- * @param addr   Source address.
- * @param packed Place to store the packed 32 bit representation.
- *
- * @return EOK on success.
- * @return EINVAL if addr is not an IPv4 address.
- *
- */
-int inet_addr_pack(inet_addr_t *addr, uint32_t *packed)
-{
-	if (addr->family != AF_INET)
-		return EINVAL;
-	
-	*packed = (addr->addr[0] << 24) | (addr->addr[1] << 16) |
-	    (addr->addr[2] << 8) | addr->addr[3];
-	return EOK;
-}
-
-/** Create packed IPv4 address
- *
- * Convert an IPv4 address to a packed 32 bit representation.
- *
- * @param naddr  Source address.
- * @param packed Place to store the packed 32 bit representation.
- * @param prefix Place to store the number of valid bits.
- *
- * @return EOK on success.
- * @return EINVAL if addr is not an IPv4 address.
- *
- */
-int inet_naddr_pack(inet_naddr_t *naddr, uint32_t *packed, uint8_t *prefix)
-{
-	if (naddr->family != AF_INET)
-		return EINVAL;
-	
-	*packed = (naddr->addr[0] << 24) | (naddr->addr[1] << 16) |
-	    (naddr->addr[2] << 8) | naddr->addr[3];
-	*prefix = naddr->prefix;
-	
-	return EOK;
-}
-
-void inet_addr_unpack(uint32_t packed, inet_addr_t *addr)
+uint16_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
+{
+	switch (addr->family) {
+	case AF_INET:
+		if (v4 != NULL)
+			*v4 = addr->addr;
+		
+		break;
+	case AF_INET6:
+		if (v6 != NULL)
+			memcpy(*v6, addr->addr6, 16);
+		
+		break;
+	}
+	
+	return addr->family;
+}
+
+uint16_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
+    uint8_t *prefix)
+{
+	switch (naddr->family) {
+	case AF_INET:
+		if (v4 != NULL)
+			*v4 = naddr->addr;
+		
+		if (prefix != NULL)
+			*prefix = naddr->prefix;
+		
+		break;
+	case AF_INET6:
+		if (v6 != NULL)
+			memcpy(*v6, naddr->addr6, 16);
+		
+		if (prefix != NULL)
+			*prefix = naddr->prefix;
+		
+		break;
+	}
+	
+	return naddr->family;
+}
+
+void inet_addr_set(addr32_t v4, inet_addr_t *addr)
 {
 	addr->family = AF_INET;
-	addr->addr[0] = (packed >> 24) & 0xff;
-	addr->addr[1] = (packed >> 16) & 0xff;
-	addr->addr[2] = (packed >> 8) & 0xff;
-	addr->addr[3] = packed & 0xff;
-}
-
-void inet_naddr_unpack(uint32_t packed, uint8_t prefix, inet_naddr_t *naddr)
+	addr->addr = v4;
+}
+
+void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
 {
 	naddr->family = AF_INET;
-	naddr->addr[0] = (packed >> 24) & 0xff;
-	naddr->addr[1] = (packed >> 16) & 0xff;
-	naddr->addr[2] = (packed >> 8) & 0xff;
-	naddr->addr[3] = packed & 0xff;
+	naddr->addr = v4;
 	naddr->prefix = prefix;
 }
 
-int inet_addr_sockaddr_in(inet_addr_t *addr, sockaddr_in_t *sockaddr_in)
-{
-	uint32_t packed;
-	int rc = inet_addr_pack(addr, &packed);
-	if (rc != EOK)
-		return rc;
-	
-	sockaddr_in->sin_family = AF_INET;
-	sockaddr_in->sin_addr.s_addr = host2uint32_t_be(packed);
-	return EOK;
-}
-
-void inet_naddr_addr(inet_naddr_t *naddr, inet_addr_t *addr)
-{
-	addr->family = naddr->family;
-	memcpy(addr->addr, naddr->addr, INET_ADDR_SIZE);
-}
-
-void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
 {
 	addr->family = AF_INET;
-	addr->addr[0] = a;
-	addr->addr[1] = b;
-	addr->addr[2] = c;
-	addr->addr[3] = d;
-}
-
-void inet_naddr(inet_naddr_t *naddr, uint8_t a, uint8_t b, uint8_t c, uint8_t d,
-    uint8_t prefix)
-{
-	naddr->family = AF_INET;
-	naddr->addr[0] = a;
-	naddr->addr[1] = b;
-	naddr->addr[2] = c;
-	naddr->addr[3] = d;
+	addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
+}
+
+void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
+{
+	addr->family = AF_INET6;
+	memcpy(addr->addr6, v6, 16);
+}
+
+void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
+{
+	naddr->family = AF_INET6;
+	memcpy(naddr->addr6, v6, 16);
 	naddr->prefix = prefix;
 }
 
-void inet_addr_any(inet_addr_t *addr)
-{
-	addr->family = 0;
-	memset(addr->addr, 0, INET_ADDR_SIZE);
-}
-
-void inet_naddr_any(inet_naddr_t *naddr)
-{
-	naddr->family = 0;
-	memset(naddr->addr, 0, INET_ADDR_SIZE);
-	naddr->prefix = 0;
-}
-
-int inet_addr_compare(inet_addr_t *a, inet_addr_t *b)
-{
-	if (a->family != b->family)
-		return 0;
-	
-	switch (a->family) {
-	case AF_INET:
-		return ((a->addr[0] == b->addr[0]) && (a->addr[1] == b->addr[1]) &&
-		    (a->addr[2] == b->addr[2]) && (a->addr[3] == b->addr[3]));
-	case AF_INET6:
-		// FIXME TODO
-		return 0;
-	default:
-		return 0;
-	}
-}
-
-int inet_addr_is_any(inet_addr_t *addr)
-{
-	return ((addr->family == 0) ||
-	    (inet_addr_compare(addr, &inet_addr_any_addr)) ||
-	    (inet_addr_compare(addr, &inet_addr_any_addr6)));
+void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,
+    inet_addr_t *addr)
+{
+	addr->family = AF_INET6;
+	addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
+}
+
+uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,
+    sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
+{
+	switch (addr->family) {
+	case AF_INET:
+		if (sockaddr_in != NULL) {
+			sockaddr_in->sin_family = AF_INET;
+			sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);
+		}
+		
+		break;
+	case AF_INET6:
+		if (sockaddr_in6 != NULL) {
+			sockaddr_in6->sin6_family = AF_INET6;
+			host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);
+		}
+		
+		break;
+	}
+	
+	return addr->family;
 }
 
