diff options
Diffstat (limited to 'lib/net_utils.c')
-rw-r--r-- | lib/net_utils.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/lib/net_utils.c b/lib/net_utils.c index 72a3b098a70..4283c13a31d 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -11,6 +11,7 @@ #include <common.h> #include <net.h> +#include <net6.h> struct in_addr string_to_ip(const char *s) { @@ -43,6 +44,114 @@ struct in_addr string_to_ip(const char *s) return addr; } +#if IS_ENABLED(CONFIG_IPV6) +int string_to_ip6(const char *str, size_t len, struct in6_addr *addr) +{ + int colon_count = 0; + int found_double_colon = 0; + int xstart = 0; /* first zero (double colon) */ + int section_num = 7; /* num words the double colon represents */ + int i; + const char *s = str; + const char *const e = s + len; + struct in_addr zero_ip = {.s_addr = 0}; + + if (!str) + return -1; + + /* First pass, verify the syntax and locate the double colon */ + while (s < e) { + while (s < e && isxdigit((int)*s)) + s++; + if (*s == '\0') + break; + if (*s != ':') { + if (*s == '.' && section_num >= 2) { + struct in_addr v4; + + while (s != str && *(s - 1) != ':') + --s; + v4 = string_to_ip(s); + if (memcmp(&zero_ip, &v4, + sizeof(struct in_addr)) != 0) { + section_num -= 2; + break; + } + } + /* This could be a valid address */ + break; + } + if (s == str) { + /* 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) + section_num--; + else + xstart++; + } + + if (*s == ':') { + if (found_double_colon) + /* Two double colons are not allowed */ + goto out_err; + found_double_colon = 1; + section_num -= xstart; + s++; + } + + if (++colon_count == 7) + /* Found all colons */ + break; + ++s; + } + + if (colon_count == 0) + goto out_err; + if (*--s == ':') + section_num++; + + /* Second pass, read the address */ + s = str; + for (i = 0; i < 8; i++) { + int val = 0; + char *end; + + if (found_double_colon && + i >= xstart && i < xstart + section_num) { + addr->s6_addr16[i] = 0; + continue; + } + while (*s == ':') + s++; + + if (i == 6 && isdigit((int)*s)) { + struct in_addr v4 = string_to_ip(s); + + if (memcmp(&zero_ip, &v4, + sizeof(struct in_addr)) != 0) { + /* Ending with :IPv4-address */ + addr->s6_addr32[3] = v4.s_addr; + break; + } + } + + val = simple_strtoul(s, &end, 16); + if (end != e && *end != '\0' && *end != ':') + goto out_err; + addr->s6_addr16[i] = htons(val); + s = end; + } + return 0; + +out_err: + return -1; +} +#endif + void string_to_enetaddr(const char *addr, uint8_t *enetaddr) { char *end; |