From patchwork Mon Nov 9 07:38:49 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Packham X-Patchwork-Id: 541626 X-Patchwork-Delegate: joe.hershberger@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C610C1402CC for ; Mon, 9 Nov 2015 18:40:25 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=Ai9Esi15; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8C0904BD4C; Mon, 9 Nov 2015 08:39:59 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DdlVvjYn1dx8; Mon, 9 Nov 2015 08:39:59 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AA3A24BB51; Mon, 9 Nov 2015 08:39:53 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 702F04BD3B for ; Mon, 9 Nov 2015 08:39:48 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id tA75FYJwLtBy for ; Mon, 9 Nov 2015 08:39:48 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f49.google.com (mail-pa0-f49.google.com [209.85.220.49]) by theia.denx.de (Postfix) with ESMTPS id 172C54BCBC for ; Mon, 9 Nov 2015 08:39:34 +0100 (CET) Received: by pacdm15 with SMTP id dm15so166647945pac.3 for ; Sun, 08 Nov 2015 23:39:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=N9+h1XN12rHjOtECXnHeWM/60ilfIYGc+y835wky8mE=; b=Ai9Esi15JdeMvBuC5hWdt6/s/1OZXIDhTQfv+96/nAf8XL59RKGV3bntnIDs0geayn 6O2eeOioXYciTs1o09QG9lJ4ojT+HLZfoP/wO8npmXe0NzQ0nuTrvB3uLqJXoGNQ/9T8 ENKMBHlIaAH4+spaRNtjzPcUzViKoaiH+a2UZmjXMYp4hYcUoGHdozGFp30DDGU0Sb2d ubD+F/JaYToWhQiajvlFierZY74qCAERvl4GIyUxDgEebhbzikTRBjbpZnKPdzNyrwyr EIZEEnhDGAA6GrzB3P4eriHA8AXA/Rzr1gCDyFu48xA8WSCT00RSrJQmUqQEQ5Qqcasw LglQ== X-Received: by 10.68.57.169 with SMTP id j9mr29491429pbq.2.1447054773559; Sun, 08 Nov 2015 23:39:33 -0800 (PST) Received: from chrisp-dl.ws.atlnz.lc (2-163-36-202-static.alliedtelesis.co.nz. [202.36.163.2]) by smtp.gmail.com with ESMTPSA id so4sm14434198pbc.72.2015.11.08.23.39.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 08 Nov 2015 23:39:33 -0800 (PST) From: Chris Packham To: u-boot@lists.denx.de, Joe Hershberger Date: Mon, 9 Nov 2015 20:38:49 +1300 Message-Id: <1447054736-27658-5-git-send-email-judge.packham@gmail.com> X-Mailer: git-send-email 2.5.3 In-Reply-To: <1447054736-27658-1-git-send-email-judge.packham@gmail.com> References: <1447054736-27658-1-git-send-email-judge.packham@gmail.com> Cc: Tom Rini , Angga , hannah@marvell.com, jp.tosoni@acksys.fr, Chris Packham Subject: [U-Boot] [RFC PATCH v2 04/11] lib: net_utils: add string_to_ip6 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 --- 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: - Wrap code in CONFIG_NET6 include/net6.h | 3 ++ lib/net_utils.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/include/net6.h b/include/net6.h index 1b82c25..a41eb87 100644 --- a/include/net6.h +++ b/include/net6.h @@ -58,4 +58,7 @@ static inline int ipv6_addr_is_isatap(const struct in6_addr *a) return (a->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); } +/* Convert a string to an ipv6 address */ +int string_to_ip6(const char *s, struct in6_addr *addr); + #endif /* __NET6_H__ */ diff --git a/lib/net_utils.c b/lib/net_utils.c index f148b8a..7422c27 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -11,6 +11,8 @@ */ #include +#include +#include struct in_addr string_to_ip(const char *s) { @@ -39,3 +41,122 @@ struct in_addr string_to_ip(const char *s) addr.s_addr = htonl(addr.s_addr); return addr; } + +#ifdef CONFIG_NET6 +/** + * 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) + */ +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 == NULL) + 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