From patchwork Tue Mar 14 11:25:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Schultz X-Patchwork-Id: 738656 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3vjCC15tZHz9s1y for ; Tue, 14 Mar 2017 22:27:41 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750886AbdCNL10 (ORCPT ); Tue, 14 Mar 2017 07:27:26 -0400 Received: from mail.tpip.net ([92.43.49.48]:43967 "EHLO mail.tpip.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750849AbdCNL1Y (ORCPT ); Tue, 14 Mar 2017 07:27:24 -0400 Received: from office.tpip.net (unknown [153.92.65.89]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.tpip.net (Postfix) with ESMTPS id 6D1154F406; Tue, 14 Mar 2017 11:27:22 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id 3F659A2D08; Tue, 14 Mar 2017 12:27:22 +0100 (CET) Received: from office.tpip.net ([127.0.0.1]) by localhost (office.tpip.net [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id Pzr8zvwiEa0W; Tue, 14 Mar 2017 12:27:21 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by office.tpip.net (Postfix) with ESMTP id CA48BA2D0B; Tue, 14 Mar 2017 12:27:21 +0100 (CET) X-Virus-Scanned: amavisd-new at tpip.net Received: from office.tpip.net ([127.0.0.1]) by localhost (office.tpip.net [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 54-Zr5uCSUUD; Tue, 14 Mar 2017 12:27:21 +0100 (CET) Received: from localhost.localdomain (x55b235d1.dyn.telefonica.de [85.178.53.209]) by office.tpip.net (Postfix) with ESMTPSA id 67AC1A2D08; Tue, 14 Mar 2017 12:27:21 +0100 (CET) From: Andreas Schultz To: Harald Welte , Pablo Neira Ayuso Cc: osmocom-net-gprs@lists.osmocom.org, netdev , Lionel Gauthier Subject: [PATCH net-next 3/4] gtp: add support to select a GTP socket during PDP context creation Date: Tue, 14 Mar 2017 12:25:47 +0100 Message-Id: <20170314112548.24027-4-aschultz@tpip.net> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170314112548.24027-1-aschultz@tpip.net> References: <20170314112548.24027-1-aschultz@tpip.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org For each new PDP a separate socket can be selected. The per netdevice default sockets are no longer mandatory. This means also that multiple gtp netdevices can share the same default socket and that therefore the destruction of a gtp netdevice can no longer automatically disable the gtp encapsulation on it's sockets. Signed-off-by: Andreas Schultz --- drivers/net/gtp.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index c4cf1b9..afa043d 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -381,9 +381,6 @@ static int gtp_dev_init(struct net_device *dev) static void gtp_dev_uninit(struct net_device *dev) { - struct gtp_dev *gtp = netdev_priv(dev); - - gtp_encap_disable(gtp); free_percpu(dev->tstats); } @@ -647,9 +644,6 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, struct gtp_net *gn; int hashsize, err; - if (!data[IFLA_GTP_FD0] && !data[IFLA_GTP_FD1]) - return -EINVAL; - gtp = netdev_priv(dev); if (!data[IFLA_GTP_PDP_HASHSIZE]) @@ -689,8 +683,11 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head) { struct gtp_dev *gtp = netdev_priv(dev); - gtp_encap_disable(gtp); gtp_hashtable_free(gtp); + if (gtp->sk0) + sock_put(gtp->sk0); + if (gtp->sk1u) + sock_put(gtp->sk1u); list_del_rcu(>p->list); unregister_netdevice_queue(dev, head); } @@ -1008,9 +1005,10 @@ static void pdp_context_delete(struct pdp_ctx *pctx) static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) { + struct socket *sock = NULL; + struct sock *sk = NULL; unsigned int version; struct gtp_dev *gtp; - struct sock *sk; int err; if (!info->attrs[GTPA_VERSION] || @@ -1045,12 +1043,14 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } - if (version == GTP_V0) + if (info->attrs[GTPA_FD]) { + sock = sockfd_lookup(nla_get_u32(info->attrs[GTPA_FD]), &err); + if (sock) + sk = sock->sk; + } else if (version == GTP_V0) sk = gtp->sk0; else if (version == GTP_V1) sk = gtp->sk1u; - else - sk = NULL; if (!sk) { err = -ENODEV; @@ -1059,6 +1059,9 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) err = ipv4_pdp_add(gtp, sk, info); + if (sock) + sockfd_put(sock); + out_unlock: rcu_read_unlock(); return err; @@ -1079,12 +1082,66 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, return ipv4_pdp_find(gtp, nla_get_be32(nla[GTPA_MS_ADDRESS])); } +static struct pdp_ctx *gtp_genl_find_pdp_by_socket(struct net *net, + struct nlattr *nla[]) +{ + struct socket *sock; + struct gtp_sock *gsk; + struct pdp_ctx *pctx; + int fd, err = 0; + + if (!nla[GTPA_FD]) + return ERR_PTR(-EINVAL); + + fd = nla_get_u32(nla[GTPA_FD]); + sock = sockfd_lookup(fd, &err); + if (!sock) { + pr_debug("gtp socket fd=%d not found\n", fd); + return ERR_PTR(-EBADF); + } + + gsk = rcu_dereference_sk_user_data(sock->sk); + if (!gsk) { + pctx = ERR_PTR(-EINVAL); + goto out_sock; + } + + switch (nla_get_u32(nla[GTPA_VERSION])) { + case GTP_V0: + if (!nla[GTPA_TID]) { + pctx = ERR_PTR(-EINVAL); + break; + } + pctx = gtp0_pdp_find(gsk, nla_get_u64(nla[GTPA_TID])); + break; + + case GTP_V1: + if (!nla[GTPA_I_TEI]) { + pctx = ERR_PTR(-EINVAL); + break; + } + pctx = gtp1_pdp_find(gsk, nla_get_u64(nla[GTPA_I_TEI])); + break; + + default: + pctx = ERR_PTR(-EINVAL); + break; + } + +out_sock: + sockfd_put(sock); + return pctx; +} + static struct pdp_ctx *gtp_find_pdp(struct net *net, struct nlattr *nla[]) { struct pdp_ctx *pctx; if (nla[GTPA_LINK]) pctx = gtp_find_pdp_by_link(net, nla); + else if (nla[GTPA_FD]) + pctx = gtp_genl_find_pdp_by_socket(net, nla); + else pctx = ERR_PTR(-EINVAL);