Hi Viacheslav, On Tue, 30 Aug 2022 at 07:01, Viacheslav Mitrofanov <[email protected]> wrote: > > This functions is used as a converter from IPv6 address string notation > to struct ip6_addr that is used everywhere in IPv6 implementation. For > example it is used to parse and convert IPv6 address from tftpboot > command. Conversion algorithm uses two passes, first to verify syntax and > locate colons and second pass to read the address. In case of valid IPv6 > address it returns 0. > > 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) > > Signed-off-by: Viacheslav Mitrofanov <[email protected]> > --- > include/net6.h | 5 ++ > lib/net_utils.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 127 insertions(+) > > diff --git a/include/net6.h b/include/net6.h > index 71072d1416..68fa38adbb 100644 > --- a/include/net6.h > +++ b/include/net6.h > @@ -177,10 +177,15 @@ 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) > +/* Convert a string to an ipv6 address */ > +int string_to_ip6(const char *s, struct in6_addr *addr); > +#else > static inline int string_to_ip6(const char *s, struct in6_addr *addr) > { > return -1; > } > +#endif > > static inline int ip6_is_unspecified_addr(struct in6_addr *addr) > { > diff --git a/lib/net_utils.c b/lib/net_utils.c > index 72a3b098a7..09554c520b 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,127 @@ struct in_addr string_to_ip(const char *s) > return addr; > } > > +/** > + * Parses an struct in6_addr 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) > + */ > +#if IS_ENABLED(CONFIG_IPV6) > +int string_to_ip6(const char *strpt, struct in6_addr *addrpt) > +{ > + int colon_count = 0; > + int found_double_colon = 0; > + int xstart = 0; /* first zero (double colon) */ > + int len = 7; /* num words the double colon represents */ > + int i; > + const char *s = strpt; > + struct in_addr zero_ip = {.s_addr = 0}; > + > + if (!strpt) > + return -1; > + > + /* 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) { > + struct in_addr v4; > + > + while (s != strpt && *(s - 1) != ':') > + --s; > + v4 = string_to_ip(s); > + if (memcmp(&zero_ip, &v4, > + sizeof(struct in_addr) != 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) > + 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->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 */ > + addrpt->s6_addr32[3] = v4.s_addr; > + break; > + } > + } > + > + val = simple_strtoul(s, &end, 16); > + if (*end != '\0' && *end != ':') > + goto out_err; > + addrpt->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; > -- > 2.25.1 >
I won't mention the function/struct comments again, but please check this for the whole series. Regards, Simon

