diff options
-rw-r--r-- | include/net6.h | 4 | ||||
-rw-r--r-- | lib/net_utils.c | 109 |
2 files changed, 113 insertions, 0 deletions
diff --git a/include/net6.h b/include/net6.h index 78981877ce3..50b7120ca34 100644 --- a/include/net6.h +++ b/include/net6.h @@ -174,6 +174,7 @@ extern u32 net_prefix_length; /* Our prefixlength (0 = unknown) */ extern struct in6_addr net_server_ip6; /* Server IPv6 addr (0 = unknown) */ extern bool use_ip6; +#if IS_ENABLED(CONFIG_IPV6) /** * string_to_ip6() - Convert IPv6 string addr to inner IPV6 addr format * @@ -193,11 +194,14 @@ extern bool use_ip6; * @addr: converted IPv6 addr * Return: 0 if conversion successful, -EINVAL if fail */ +int string_to_ip6(const char *s, size_t len, struct in6_addr *addr); +#else static inline int string_to_ip6(const char *s, size_t len, struct in6_addr *addr) { return -EINVAL; } +#endif /** * ip6_is_unspecified_addr() - Check if IPv6 addr is not set i.e. is zero 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; |