All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chris Packham <judge.packham@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [RFC PATCH v2 02/11] lib: vsprintf: add IPv6 compressed format %pI6c
Date: Mon,  9 Nov 2015 20:38:47 +1300	[thread overview]
Message-ID: <1447054736-27658-3-git-send-email-judge.packham@gmail.com> (raw)
In-Reply-To: <1447054736-27658-1-git-send-email-judge.packham@gmail.com>

Add support for "human friendly" IPv6 address representations as
specified in
http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00

This code has been adapted from Linux kernel with minimal modification.

Signed-off-by: Chris Packham <judge.packham@gmail.com>
---

Changes in v2: None

 include/net6.h |  13 +++++
 lib/vsprintf.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 144 insertions(+), 23 deletions(-)

diff --git a/include/net6.h b/include/net6.h
index b622951..1b82c25 100644
--- a/include/net6.h
+++ b/include/net6.h
@@ -45,4 +45,17 @@ struct ip6_hdr {
 	struct in6_addr	daddr;
 };
 
+/* ::ffff:0:0/96 is reserved for v4 mapped addresses */
+static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
+{
+	return (a->s6_addr32[0] | a->s6_addr32[1] |
+		(a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
+}
+
+/* Intra-Site Automatic Tunnel Addressing Protocol Address */
+static inline int ipv6_addr_is_isatap(const struct in6_addr *a)
+{
+	return (a->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
+}
+
 #endif /* __NET6_H__ */
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 4c82837..2baac47 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -23,6 +23,7 @@
 #endif
 
 #include <div64.h>
+#include <net6.h>
 #define noinline __attribute__((noinline))
 
 unsigned long simple_strtoul(const char *cp, char **endp,
@@ -304,6 +305,7 @@ static noinline char *put_dec(char *buf, uint64_t num)
 #define LEFT	16		/* left justified */
 #define SMALL	32		/* Must be 32 == 0x20 */
 #define SPECIAL	64		/* 0x */
+#define COMPRESSED 128		/* use compressed format */
 
 #ifdef CONFIG_SYS_VSNPRINTF
 /*
@@ -469,12 +471,121 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
 		      flags & ~SPECIAL);
 }
 
-static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
+static char *ip4_string(char *p, u8 *addr)
+{
+	char temp[3];	/* hold each IP quad in reverse order */
+	int i, digits;
+
+	for (i = 0; i < 4; i++) {
+		digits = put_dec_trunc(temp, addr[i]) - temp;
+		/* reverse the digits in the quad */
+		while (digits--)
+			*p++ = temp[digits];
+		if (i != 3)
+			*p++ = '.';
+	}
+	*p = '\0';
+
+	return p;
+}
+
+static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
 			 int precision, int flags)
 {
-	/* (8 * 4 hex digits), 7 colons and trailing zero */
-	char ip6_addr[8 * 5];
-	char *p = ip6_addr;
+	char ip4_addr[sizeof("255.255.255.255")];
+
+	ip4_string(ip4_addr, addr);
+
+	return string(buf, end, ip4_addr, field_width, precision,
+		      flags & ~SPECIAL);
+}
+#endif
+
+#ifdef CONFIG_NET6
+static char *ip6_compressed_string(char *p, u8 *addr)
+{
+	int i, j, range;
+	unsigned char zerolength[8];
+	int longest = 1;
+	int colonpos = -1;
+	u16 word;
+	u8 hi, lo;
+	int needcolon = 0;
+	int useIPv4;
+	struct in6_addr in6;
+
+	memcpy(&in6, addr, sizeof(struct in6_addr));
+
+	useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
+
+	memset(zerolength, 0, sizeof(zerolength));
+
+	if (useIPv4)
+		range = 6;
+	else
+		range = 8;
+
+	/* find position of longest 0 run */
+	for (i = 0; i < range; i++) {
+		for (j = i; j < range; j++) {
+			if (in6.s6_addr16[j] != 0)
+				break;
+			zerolength[i]++;
+		}
+	}
+	for (i = 0; i < range; i++) {
+		if (zerolength[i] > longest) {
+			longest = zerolength[i];
+			colonpos = i;
+		}
+	}
+	if (longest == 1)		/* don't compress a single 0 */
+		colonpos = -1;
+
+	/* emit address */
+	for (i = 0; i < range; i++) {
+		if (i == colonpos) {
+			if (needcolon || i == 0)
+				*p++ = ':';
+			*p++ = ':';
+			needcolon = 0;
+			i += longest - 1;
+			continue;
+		}
+		if (needcolon) {
+			*p++ = ':';
+			needcolon = 0;
+		}
+		/* hex u16 without leading 0s */
+		word = ntohs(in6.s6_addr16[i]);
+		hi = word >> 8;
+		lo = word & 0xff;
+		if (hi) {
+			if (hi > 0x0f)
+				p = pack_hex_byte(p, hi);
+			else
+				*p++ = hex_asc_lo(hi);
+			p = pack_hex_byte(p, lo);
+		} else if (lo > 0x0f) {
+			p = pack_hex_byte(p, lo);
+		} else {
+			*p++ = hex_asc_lo(lo);
+		}
+		needcolon = 1;
+	}
+
+	if (useIPv4) {
+		if (needcolon)
+			*p++ = ':';
+		p = ip4_string(p, &in6.s6_addr[12]);
+	}
+	*p = '\0';
+
+	return p;
+}
+
+static char *ip6_string(char *p, u8 *addr, int flags)
+{
 	int i;
 
 	for (i = 0; i < 8; i++) {
@@ -485,30 +596,20 @@ static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
 	}
 	*p = '\0';
 
-	return string(buf, end, ip6_addr, field_width, precision,
-		      flags & ~SPECIAL);
+	return p;
 }
 
-static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
+static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
 			 int precision, int flags)
 {
-	/* (4 * 3 decimal digits), 3 dots and trailing zero */
-	char ip4_addr[4 * 4];
-	char temp[3];	/* hold each IP quad in reverse order */
-	char *p = ip4_addr;
-	int i, digits;
+	char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
 
-	for (i = 0; i < 4; i++) {
-		digits = put_dec_trunc(temp, addr[i]) - temp;
-		/* reverse the digits in the quad */
-		while (digits--)
-			*p++ = temp[digits];
-		if (i != 3)
-			*p++ = '.';
-	}
-	*p = '\0';
+	if (flags & COMPRESSED)
+		ip6_compressed_string(ip6_addr, addr);
+	else
+		ip6_string(ip6_addr, addr, flags);
 
-	return string(buf, end, ip4_addr, field_width, precision,
+	return string(buf, end, ip6_addr, field_width, precision,
 		      flags & ~SPECIAL);
 }
 #endif
@@ -526,6 +627,8 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
  *       decimal for v4 and colon separated network-order 16 bit hex for v6)
  * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
  *       currently the same
+ * - 'I6c' for IPv6 addresses printed as specified by
+ *       http://tools.ietf.org/html/rfc5952
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -569,9 +672,14 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 		flags |= SPECIAL;
 		/* Fallthrough */
 	case 'I':
-		if (fmt[1] == '6')
+#ifdef CONFIG_NET6
+		if (fmt[1] == '6') {
+			if (fmt[2] == 'c')
+				flags |= COMPRESSED;
 			return ip6_addr_string(buf, end, ptr, field_width,
 					       precision, flags);
+		}
+#endif
 		if (fmt[1] == '4')
 			return ip4_addr_string(buf, end, ptr, field_width,
 					       precision, flags);
-- 
2.5.3

  parent reply	other threads:[~2015-11-09  7:38 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-09  7:38 [U-Boot] [RFC PATCH v2 00/11] IPv6 support Chris Packham
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 01/11] Initial net6.h Chris Packham
2015-11-24  1:05   ` Joe Hershberger
2015-11-09  7:38 ` Chris Packham [this message]
2015-11-24  1:06   ` [U-Boot] [RFC PATCH v2 02/11] lib: vsprintf: add IPv6 compressed format %pI6c Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 03/11] lib: net_utils: make string_to_ip stricter Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-24  9:37     ` Chris Packham
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 04/11] lib: net_utils: add string_to_ip6 Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 05/11] net: add definition of udp_hdr Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 06/11] net: IPv6 skeleton and environment variables Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-24  9:47     ` Chris Packham
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 07/11] net: IPv6 support Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 08/11] net: Add ping6 command and implementation Chris Packham
2015-11-24  1:06   ` Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 09/11] net: TFTP over IPv6 Chris Packham
2015-11-24  1:07   ` Joe Hershberger
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 10/11] net: IPv6 documentation Chris Packham
2015-11-09  7:38 ` [U-Boot] [RFC PATCH v2 11/11] net: e1000 enable multicast reception Chris Packham
2015-11-24  1:07   ` Joe Hershberger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1447054736-27658-3-git-send-email-judge.packham@gmail.com \
    --to=judge.packham@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.