From: Chris Packham <chris.pack...@alliedtelesis.co.nz> string_to_ip6 parses an IPv6 address from a string. Parsing v6 addresses is a bit more complicated than parsing v4 because there are a number of different formats that can be used.
Signed-off-by: Chris Packham <chris.pack...@alliedtelesis.co.nz> --- I'm sure the parsing can be better and done in less code with only a single pass but I haven't yet figured it out. The main problem is that "::" can represent a variable number of contiguous "0000:" so when parsing "::" we can't tell how many half words to skip. Changes in v2: None include/net6.h | 3 ++ lib/net_utils.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/include/net6.h b/include/net6.h index bdb4326..55ab187 100644 --- a/include/net6.h +++ b/include/net6.h @@ -53,4 +53,7 @@ static inline int ipv6_addr_is_isatap(const IP6addr_t *a) return (a->u6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); } +/* Convert a string to an ipv6 address */ +extern int string_to_ip6(const char *s, IP6addr_t *addr); + #endif /* __NET6_H__ */ diff --git a/lib/net_utils.c b/lib/net_utils.c index 2b20ccb..a8de103 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -27,6 +27,8 @@ */ #include <common.h> +#include <net6.h> +#include <linux/ctype.h> IPaddr_t string_to_ip(const char *s) { @@ -49,3 +51,116 @@ IPaddr_t string_to_ip(const char *s) return (htonl(addr)); } + +/** + * Parses an IP6addr_t from the given string. IPv6 address parsing is a bit + * more complicated than v4 due to the flexible format and some of the special + * cases (e.g. v4 mapped). + * + * Examples of valid strings: + * 2001:db8::0:1234:1 + * 2001:0db8:0000:0000:0000:0000:1234:0001 + * ::1 + * ::ffff:192.168.1.1 + * + * Examples of invalid strings + * 2001:db8::0::0 (:: can only appear once) + * 2001:db8:192.168.1.1::1 (v4 part can only appear at the end) + * 192.168.1.1 (we don't implicity map v4) + */ +int string_to_ip6(const char *strpt, IP6addr_t *addrpt) +{ + IP6addr_t *in6_val = addrpt; + int colon_count = 0; + int found_double_colon = 0; + int xstart = 0; /* first zero (double colon) */ + int len = 7; /* numbers of zero words the double colon represents */ + int i; + const char *s = strpt; + + if (strpt == NULL) + return 0; + + /* First pass, verify the syntax and locate the double colon */ + for (;;) { + while (isxdigit((int)*s)) + s++; + if (*s == '\0') + break; + if (*s != ':') { + if (*s == '.' && len >= 2) { + while (s != strpt && *(s-1) != ':') + --s; + if (string_to_ip(s) != 0) { + len -= 2; + break; + } + } + /* This could be a valid address */ + break; + } + if (s == strpt) { + /* The address begins with a colon */ + if (*++s != ':') + /* Must start with a double colon or a number */ + goto out_err; + } else { + s++; + if (found_double_colon) + len--; + else + xstart++; + } + + if (*s == ':') { + if (found_double_colon) + /* Two double colons are not allowed */ + goto out_err; + found_double_colon = 1; + len -= xstart; + s++; + } + + if (++colon_count == 7) + /* Found all colons */ + break; + } + + if (colon_count == 0 || colon_count > 7) + goto out_err; + if (*--s == ':') + len++; + + /* Second pass, read the address */ + s = strpt; + for (i = 0; i < 8; i++) { + int val = 0; + char *end; + + if (found_double_colon && i >= xstart && i < xstart + len) { + addrpt->u6_addr16[i] = 0; + continue; + } + while (*s == ':') + s++; + + if (i == 6 && isdigit((int)*s)) { + IPaddr_t v4 = string_to_ip(s); + if (v4 != 0) { + /* Ending with :IPv4-address */ + addrpt->u6_addr32[3] = v4; + break; + } + } + + val = simple_strtoul(s, &end, 16); + if (*end != '\0' && *end != ':') + goto out_err; + addrpt->u6_addr16[i] = htons(val); + s = end; + } + return 0; + +out_err: + return -1; +} -- 1.7.12.rc2.16.g034161a _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot