From patchwork Thu Feb 16 17:43:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Grimberg X-Patchwork-Id: 9577811 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4BDF26049F for ; Thu, 16 Feb 2017 17:44:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3F3092862C for ; Thu, 16 Feb 2017 17:44:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 33D2128636; Thu, 16 Feb 2017 17:44:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 364A82863A for ; Thu, 16 Feb 2017 17:44:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932291AbdBPRns (ORCPT ); Thu, 16 Feb 2017 12:43:48 -0500 Received: from merlin.infradead.org ([205.233.59.134]:44752 "EHLO merlin.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754753AbdBPRnq (ORCPT ); Thu, 16 Feb 2017 12:43:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:To:From:Sender:Reply-To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=o9KZEduZapdpwY1XMwxlcsCP27vBZ6DkysMNRRTk1z0=; b=gpGOm45C5dx7e53pAvLLBSoNw a1lV0JJOjwquUvu1S8p6Mklp08F1Aa+Mox4VX+0rtPLGMIhoOppX6vSuk90K41x96/EFY7m3foy44 xFUd/lxpgUMkBA1Kjbfg2Pr+t3Rv4iFo23su/FTvj2urQGajvfxUf2G4p/ccPUZYYmsB4CKoHnPkU bVFWhol00dortfkCyU1OF1vca0/ut/GqVssZIb7XUnyBoydKwflHP4f1KD2l9vNr3xCIIpW9UhaaW 7lMEmgkfK9niUHENlp2+IXaxaU9U74qUPPp3jcgs3y8VyexNCcULzvtv9J6Mh4ESa1sXcFEZn3OKx 4G1C5YpDA==; Received: from bzq-82-81-101-184.red.bezeqint.net ([82.81.101.184] helo=bombadil.infradead.org) by merlin.infradead.org with esmtpsa (Exim 4.87 #1 (Red Hat Linux)) id 1ceQ5o-0006X1-WB; Thu, 16 Feb 2017 17:43:45 +0000 From: Sagi Grimberg To: linux-nvme@lists.infradead.org, linux-rdma@vger.kernel.org, target-devel@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH rfc 1/4] net/utils: generic inet_pton_with_scope helper Date: Thu, 16 Feb 2017 19:43:34 +0200 Message-Id: <1487267017-29904-2-git-send-email-sagi@grimberg.me> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1487267017-29904-1-git-send-email-sagi@grimberg.me> References: <1487267017-29904-1-git-send-email-sagi@grimberg.me> Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Several locations in the stack need to handle ipv4/ipv6 (with scope) and port strings conversion to sockaddr. Add a helper that takes either AF_INET, AF_INET6 or AF_UNSPEC (for wildcard) to centralize this handling. Suggested-by: Christoph Hellwig Signed-off-by: Sagi Grimberg --- include/linux/inet.h | 6 ++++ net/core/utils.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/include/linux/inet.h b/include/linux/inet.h index 4cca05c9678e..636ebe87e6f8 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h @@ -43,6 +43,8 @@ #define _LINUX_INET_H #include +#include +#include /* * These mimic similar macros defined in user-space for inet_ntop(3). @@ -54,4 +56,8 @@ extern __be32 in_aton(const char *str); extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); + +extern int inet_pton_with_scope(struct net *net, unsigned short af, + const char *src, const char *port, struct sockaddr_storage *addr); + #endif /* _LINUX_INET_H */ diff --git a/net/core/utils.c b/net/core/utils.c index 6592d7bbed39..8f15d016c64a 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -26,9 +26,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -300,6 +302,95 @@ int in6_pton(const char *src, int srclen, } EXPORT_SYMBOL(in6_pton); +/** + * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address + * @net: net namespace (used for scope handling) + * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either + * @src: the start of the address string + * @port: the start of the port string (or NULL for none) + * @addr: output socket address + * + * Return zero on success, return errno when any error occurs. + */ +int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af, + const char *src, const char *port, struct sockaddr_storage *addr) +{ + struct sockaddr_in *addr4; + struct sockaddr_in6 *addr6; + const char *scope_delim; + bool unspec = false; + int srclen = strlen(src); + u16 port_num; + + if (port) { + if (kstrtou16(port, 0, &port_num)) { + pr_err("failed port_num %s\n", port); + return -EINVAL; + } + } else { + port_num = 0; + } + + switch (af) { + case AF_UNSPEC: + unspec = true; + /* FALLTHRU */ + case AF_INET: + if (srclen <= INET_ADDRSTRLEN) { + addr4 = (struct sockaddr_in *)addr; + if (in4_pton(src, srclen, (u8 *) &addr4->sin_addr.s_addr, + '\n', NULL) > 0) { + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port_num); + return 0; + } + pr_err("failed in4_pton %s\n", src); + } + if (!unspec) + break; + case AF_INET6: + if (srclen <= INET6_ADDRSTRLEN) { + addr6 = (struct sockaddr_in6 *)addr; + if (in6_pton(src, srclen, (u8 *) &addr6->sin6_addr.s6_addr, + '%', &scope_delim) == 0) { + pr_err("failed in6_pton %s\n", src); + return -EINVAL; + } + + if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL && + src + srclen != scope_delim && *scope_delim == '%') { + struct net_device *dev; + char scope_id[16]; + size_t scope_len = min_t(size_t, sizeof scope_id, + src + srclen - scope_delim - 1); + + memcpy(scope_id, scope_delim + 1, scope_len); + scope_id[scope_len] = '\0'; + + dev = dev_get_by_name(net, scope_id); + if (dev) { + addr6->sin6_scope_id = dev->ifindex; + dev_put(dev); + } else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) { + pr_err("failed dev_get_by_name %s\n", scope_id); + return -EINVAL; + } + } + + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(port_num); + + return 0; + } + break; + default: + pr_err("unexpected address family %d\n", af); + }; + + return -EINVAL; +} +EXPORT_SYMBOL(inet_pton_with_scope); + void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, __be32 from, __be32 to, bool pseudohdr) {