From patchwork Tue Jun 1 08:05:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 12290665 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9F753C47093 for ; Tue, 1 Jun 2021 08:05:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 75417600CD for ; Tue, 1 Jun 2021 08:05:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233305AbhFAIHb (ORCPT ); Tue, 1 Jun 2021 04:07:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233056AbhFAIH1 (ORCPT ); Tue, 1 Jun 2021 04:07:27 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D5ECC06174A; Tue, 1 Jun 2021 01:05:45 -0700 (PDT) Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1lnzPD-000V6C-GZ; Tue, 01 Jun 2021 10:05:43 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: m.chetan.kumar@intel.com, loic.poulain@linaro.org, Johannes Berg Subject: [RFC 1/4] iosm: fix stats and RCU bugs in RX Date: Tue, 1 Jun 2021 10:05:35 +0200 Message-Id: <20210601100320.48d067d87f3e.I53608f5de5828db7066d29e5774bcf8a19e0f642@changeid> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210601080538.71036-1-johannes@sipsolutions.net> References: <20210601080538.71036-1-johannes@sipsolutions.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC From: Johannes Berg Signed-off-by: Johannes Berg --- drivers/net/wwan/iosm/iosm_ipc_wwan.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c index 02c35bc86674..719c88d9b2e9 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c +++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c @@ -312,7 +312,8 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, bool dss, int if_id) { struct sk_buff *skb = skb_arg; - struct net_device_stats stats; + struct net_device_stats *stats; + struct iosm_net_link *priv; int ret; if ((skb->data[0] & IOSM_IP_TYPE_MASK) == IOSM_IP_TYPE_IPV4) @@ -325,19 +326,27 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, if (if_id < (IP_MUX_SESSION_START - 1) || if_id > (IP_MUX_SESSION_END - 1)) { - dev_kfree_skb(skb); - return -EINVAL; + ret = -EINVAL; + goto free; } rcu_read_lock(); - skb->dev = rcu_dereference(ipc_wwan->sub_netlist[if_id])->netdev; - stats = rcu_dereference(ipc_wwan->sub_netlist[if_id])->netdev->stats; - stats.rx_packets++; - stats.rx_bytes += skb->len; + priv = rcu_dereference(ipc_wwan->sub_netlist[if_id]); + if (!priv) { + ret = -EINVAL; + goto unlock; + } + skb->dev = priv->netdev; + stats = &priv->netdev->stats; + stats->rx_packets++; + stats->rx_bytes += skb->len; ret = netif_rx(skb); + skb = NULL; +unlock: rcu_read_unlock(); - +free: + dev_kfree_skb(skb); return ret; } From patchwork Tue Jun 1 08:05:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 12290667 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28724C4708F for ; Tue, 1 Jun 2021 08:05:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0D000600CD for ; Tue, 1 Jun 2021 08:05:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233325AbhFAIHc (ORCPT ); Tue, 1 Jun 2021 04:07:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51186 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233194AbhFAIH1 (ORCPT ); Tue, 1 Jun 2021 04:07:27 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C09C7C061756; Tue, 1 Jun 2021 01:05:45 -0700 (PDT) Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1lnzPD-000V6C-SC; Tue, 01 Jun 2021 10:05:44 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: m.chetan.kumar@intel.com, loic.poulain@linaro.org, Johannes Berg Subject: [RFC 2/4] rtnetlink: add alloc() method to rtnl_link_ops Date: Tue, 1 Jun 2021 10:05:36 +0200 Message-Id: <20210601100320.d72771182b79.Iadd04d389e9e8500e7de5e02081ab212c673d143@changeid> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210601080538.71036-1-johannes@sipsolutions.net> References: <20210601080538.71036-1-johannes@sipsolutions.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC From: Johannes Berg In order to make rtnetlink ops that can create different kinds of devices, like what we want to add to the WWAN framework, the priv_size and setup parameters aren't quite sufficient. Make this easier to manage by allowing ops to allocate their own netdev via an @alloc method that gets both the tb and data. Signed-off-by: Johannes Berg --- drivers/net/bareudp.c | 2 +- drivers/net/can/vxcan.c | 2 +- drivers/net/geneve.c | 2 +- drivers/net/veth.c | 2 +- drivers/net/vxlan.c | 2 +- include/net/rtnetlink.h | 10 ++++++++++ net/core/rtnetlink.c | 17 ++++++++++++++--- net/ipv4/ip_gre.c | 2 +- 8 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index edfad93e7b68..a694f6d8eb21 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -727,7 +727,7 @@ struct net_device *bareudp_dev_create(struct net *net, const char *name, memset(tb, 0, sizeof(tb)); dev = rtnl_create_link(net, name, name_assign_type, - &bareudp_link_ops, tb, NULL); + &bareudp_link_ops, tb, NULL, NULL); if (IS_ERR(dev)) return dev; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 8861a7d875e7..f904c78b4c23 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -204,7 +204,7 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, return PTR_ERR(peer_net); peer = rtnl_create_link(peer_net, ifname, name_assign_type, - &vxcan_link_ops, tbp, extack); + &vxcan_link_ops, tbp, NULL, extack); if (IS_ERR(peer)) { put_net(peer_net); return PTR_ERR(peer); diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 1ab94b5f9bbf..130397110623 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1840,7 +1840,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name, memset(tb, 0, sizeof(tb)); dev = rtnl_create_link(net, name, name_assign_type, - &geneve_link_ops, tb, NULL); + &geneve_link_ops, tb, NULL, NULL); if (IS_ERR(dev)) return dev; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index bdb7ce3cb054..788faa8faa98 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1498,7 +1498,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, return PTR_ERR(net); peer = rtnl_create_link(net, ifname, name_assign_type, - &veth_link_ops, tbp, extack); + &veth_link_ops, tbp, NULL, extack); if (IS_ERR(peer)) { put_net(net); return PTR_ERR(peer); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 02a14f1b938a..b8a63a8bcb73 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -4483,7 +4483,7 @@ struct net_device *vxlan_dev_create(struct net *net, const char *name, memset(&tb, 0, sizeof(tb)); dev = rtnl_create_link(net, name, name_assign_type, - &vxlan_link_ops, tb, NULL); + &vxlan_link_ops, tb, NULL, NULL); if (IS_ERR(dev)) return dev; diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 479f60ef54c0..75426ad5a05b 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -37,6 +37,9 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh) * @maxtype: Highest device specific netlink attribute number * @policy: Netlink policy for device specific attribute validation * @validate: Optional validation function for netlink/changelink parameters + * @alloc: netdev allocation function, can be %NULL and is then used + * in place of alloc_netdev_mqs(), in this case @priv_size + * and @setup are unused. Returns a netdev or ERR_PTR(). * @priv_size: sizeof net_device private space * @setup: net_device setup function * @newlink: Function for configuring and registering a new device @@ -63,6 +66,12 @@ struct rtnl_link_ops { const char *kind; size_t priv_size; + struct net_device *(*alloc)(struct nlattr *tb[], + struct nlattr *data[], + const char *ifname, + unsigned char name_assign_type, + unsigned int num_tx_queues, + unsigned int num_rx_queues); void (*setup)(struct net_device *dev); bool netns_refund; @@ -162,6 +171,7 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, unsigned char name_assign_type, const struct rtnl_link_ops *ops, struct nlattr *tb[], + struct nlattr *data[], struct netlink_ext_ack *extack); int rtnl_delete_link(struct net_device *dev); int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 714d5fa38546..9da38639f088 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3151,6 +3151,7 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, unsigned char name_assign_type, const struct rtnl_link_ops *ops, struct nlattr *tb[], + struct nlattr *data[], struct netlink_ext_ack *extack) { struct net_device *dev; @@ -3177,8 +3178,17 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, return ERR_PTR(-EINVAL); } - dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, - ops->setup, num_tx_queues, num_rx_queues); + if (ops->alloc) { + dev = ops->alloc(tb, data, ifname, name_assign_type, + num_tx_queues, num_rx_queues); + if (IS_ERR(dev)) + return dev; + } else { + dev = alloc_netdev_mqs(ops->priv_size, ifname, + name_assign_type, ops->setup, + num_tx_queues, num_rx_queues); + } + if (!dev) return ERR_PTR(-ENOMEM); @@ -3440,7 +3450,8 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, } dev = rtnl_create_link(link_net ? : dest_net, ifname, - name_assign_type, ops, tb, extack); + name_assign_type, ops, tb, data, + extack); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index a68bf4c6fe9b..7680f5b87f61 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1637,7 +1637,7 @@ struct net_device *gretap_fb_dev_create(struct net *net, const char *name, memset(&tb, 0, sizeof(tb)); dev = rtnl_create_link(net, name, name_assign_type, - &ipgre_tap_ops, tb, NULL); + &ipgre_tap_ops, tb, NULL, NULL); if (IS_ERR(dev)) return dev; From patchwork Tue Jun 1 08:05:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 12290671 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22015C47098 for ; Tue, 1 Jun 2021 08:05:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 06A8161378 for ; Tue, 1 Jun 2021 08:05:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233354AbhFAIHf (ORCPT ); Tue, 1 Jun 2021 04:07:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233195AbhFAIH1 (ORCPT ); Tue, 1 Jun 2021 04:07:27 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3ECE8C06175F; Tue, 1 Jun 2021 01:05:46 -0700 (PDT) Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1lnzPE-000V6C-7j; Tue, 01 Jun 2021 10:05:44 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: m.chetan.kumar@intel.com, loic.poulain@linaro.org, Johannes Berg Subject: [RFC 3/4] wwan: add interface creation support Date: Tue, 1 Jun 2021 10:05:37 +0200 Message-Id: <20210601100320.7d39e9c33a18.I0474861dad426152ac7e7afddfd7fe3ce70870e4@changeid> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210601080538.71036-1-johannes@sipsolutions.net> References: <20210601080538.71036-1-johannes@sipsolutions.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC From: Johannes Berg Add support to create (and destroy) interfaces via a new rtnetlink kind "wwan". The responsible driver has to use the new wwan_register_ops() to make this possible. Signed-off-by: Johannes Berg --- drivers/net/wwan/wwan_core.c | 219 ++++++++++++++++++++++++++++++++++- include/linux/wwan.h | 36 ++++++ include/uapi/linux/wwan.h | 17 +++ 3 files changed, 267 insertions(+), 5 deletions(-) create mode 100644 include/uapi/linux/wwan.h diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index cff04e532c1e..b1ad78f386bc 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #define WWAN_MAX_MINORS 256 /* 256 minors allowed with register_chrdev() */ @@ -524,24 +526,231 @@ static const struct file_operations wwan_port_fops = { .llseek = noop_llseek, }; +struct wwan_dev_reg { + struct list_head list; + struct device *dev; + const struct wwan_ops *ops; + void *ctxt; +}; + +static DEFINE_MUTEX(wwan_mtx); +static LIST_HEAD(wwan_devs); + +int wwan_register_ops(struct device *parent, const struct wwan_ops *ops, + void *ctxt) +{ + struct wwan_dev_reg *reg; + int ret; + + if (WARN_ON(!parent || !ops)) + return -EINVAL; + + mutex_lock(&wwan_mtx); + list_for_each_entry(reg, &wwan_devs, list) { + if (WARN_ON(reg->dev == parent)) { + ret = -EBUSY; + goto out; + } + } + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) { + ret = -ENOMEM; + goto out; + } + + reg->dev = parent; + reg->ops = ops; + reg->ctxt = ctxt; + list_add_tail(®->list, &wwan_devs); + + ret = 0; + +out: + mutex_unlock(&wwan_mtx); + return ret; +} +EXPORT_SYMBOL_GPL(wwan_register_ops); + +void wwan_unregister_ops(struct device *parent) +{ + struct wwan_dev_reg *tmp; + + mutex_lock(&wwan_mtx); + list_for_each_entry(tmp, &wwan_devs, list) { + if (tmp->dev == parent) { + list_del(&tmp->list); + break; + } + } + mutex_unlock(&wwan_mtx); +} +EXPORT_SYMBOL_GPL(wwan_unregister_ops); + +static struct wwan_dev_reg *wwan_find_by_name(const char *name) +{ + struct wwan_dev_reg *tmp; + + lockdep_assert_held(&wwan_mtx); + + list_for_each_entry(tmp, &wwan_devs, list) { + if (strcmp(name, dev_name(tmp->dev)) == 0) + return tmp; + } + + return NULL; +} + +static struct wwan_dev_reg *wwan_find_by_dev(struct device *dev) +{ + struct wwan_dev_reg *tmp; + + lockdep_assert_held(&wwan_mtx); + + list_for_each_entry(tmp, &wwan_devs, list) { + if (tmp->dev == dev) + return tmp; + } + + return NULL; +} + +static int wwan_rtnl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + if (!data) + return -EINVAL; + + if (!data[IFLA_WWAN_LINK_ID] || !data[IFLA_WWAN_DEV_NAME]) + return -EINVAL; + + return 0; +} + +static struct device_type wwan_type = { .name = "wwan" }; + +static struct net_device *wwan_rtnl_alloc(struct nlattr *tb[], + struct nlattr *data[], + const char *ifname, + unsigned char name_assign_type, + unsigned int num_tx_queues, + unsigned int num_rx_queues) +{ + const char *devname = nla_data(data[IFLA_WWAN_DEV_NAME]); + struct wwan_dev_reg *reg; + struct net_device *dev; + + mutex_lock(&wwan_mtx); + reg = wwan_find_by_name(devname); + if (!reg) { + mutex_unlock(&wwan_mtx); + return ERR_PTR(-EINVAL); + } + + dev = alloc_netdev_mqs(reg->ops->priv_size, ifname, name_assign_type, + reg->ops->setup, num_tx_queues, num_rx_queues); + + mutex_unlock(&wwan_mtx); + + if (dev) { + SET_NETDEV_DEV(dev, reg->dev); + SET_NETDEV_DEVTYPE(dev, &wwan_type); + } + + return dev; +} + +static int wwan_rtnl_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + struct wwan_dev_reg *reg; + u32 link_id = nla_get_u32(data[IFLA_WWAN_LINK_ID]); + int ret; + + mutex_lock(&wwan_mtx); + reg = wwan_find_by_dev(dev->dev.parent); + if (!reg) { + mutex_unlock(&wwan_mtx); + return -EINVAL; + } + + if (reg->ops->newlink) + ret = reg->ops->newlink(reg->ctxt, dev, link_id, extack); + else + ret = register_netdevice(dev); + + mutex_unlock(&wwan_mtx); + + return ret; +} + +static void wwan_rtnl_dellink(struct net_device *dev, struct list_head *head) +{ + struct wwan_dev_reg *reg; + + mutex_lock(&wwan_mtx); + reg = wwan_find_by_dev(dev->dev.parent); + if (!reg) { + mutex_unlock(&wwan_mtx); + return; + } + + if (reg->ops->dellink) + reg->ops->dellink(reg->ctxt, dev, head); + else + unregister_netdevice(dev); + + mutex_unlock(&wwan_mtx); +} + +static const struct nla_policy wwan_rtnl_policy[IFLA_WWAN_MAX + 1] = { + [IFLA_WWAN_DEV_NAME] = { .type = NLA_NUL_STRING }, + [IFLA_WWAN_LINK_ID] = { .type = NLA_U32 }, +}; + +static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = { + .kind = "wwan", + .maxtype = __IFLA_WWAN_MAX, + .alloc = wwan_rtnl_alloc, + .validate = wwan_rtnl_validate, + .newlink = wwan_rtnl_newlink, + .dellink = wwan_rtnl_dellink, + .policy = wwan_rtnl_policy, +}; + static int __init wwan_init(void) { + int err; + + err = rtnl_link_register(&wwan_rtnl_link_ops); + if (err) + return err; + wwan_class = class_create(THIS_MODULE, "wwan"); - if (IS_ERR(wwan_class)) - return PTR_ERR(wwan_class); + if (IS_ERR(wwan_class)) { + err = PTR_ERR(wwan_class); + goto unregister; + } /* chrdev used for wwan ports */ wwan_major = register_chrdev(0, "wwan_port", &wwan_port_fops); if (wwan_major < 0) { - class_destroy(wwan_class); - return wwan_major; + err = wwan_major; + goto destroy; } - return 0; + err = 0; +destroy: + class_destroy(wwan_class); +unregister: + rtnl_link_unregister(&wwan_rtnl_link_ops); + return err; } static void __exit wwan_exit(void) { + rtnl_link_unregister(&wwan_rtnl_link_ops); unregister_chrdev(wwan_major, "wwan_port"); class_destroy(wwan_class); } diff --git a/include/linux/wwan.h b/include/linux/wwan.h index aa05a253dcf9..d07301962ff7 100644 --- a/include/linux/wwan.h +++ b/include/linux/wwan.h @@ -7,6 +7,7 @@ #include #include #include +#include /** * enum wwan_port_type - WWAN port types @@ -108,4 +109,39 @@ void wwan_port_txon(struct wwan_port *port); */ void *wwan_port_get_drvdata(struct wwan_port *port); +/** + * struct wwan_ops - WWAN device ops + * @priv_size: size of private netdev data area + * @setup: set up a new netdev + * @newlink: register the new netdev + * @dellink: remove the given netdev + */ +struct wwan_ops { + unsigned int priv_size; + void (*setup)(struct net_device *dev); + int (*newlink)(void *ctxt, struct net_device *dev, + u32 if_id, struct netlink_ext_ack *extack); + void (*dellink)(void *ctxt, struct net_device *dev, + struct list_head *head); +}; + +/** + * wwan_register_ops - register WWAN device ops + * @parent: Device to use as parent and shared by all WWAN ports and + * created netdevs + * @ops: operations to register + * @ctxt: context to pass to operations + * + * Returns: 0 on success, a negative error code on failure + */ +int wwan_register_ops(struct device *parent, const struct wwan_ops *ops, + void *ctxt); + +/** + * wwan_unregister_ops - remove WWAN device ops + * @parent: Device to use as parent and shared by all WWAN ports and + * created netdevs + */ +void wwan_unregister_ops(struct device *parent); + #endif /* __WWAN_H */ diff --git a/include/uapi/linux/wwan.h b/include/uapi/linux/wwan.h new file mode 100644 index 000000000000..a134c823cfbd --- /dev/null +++ b/include/uapi/linux/wwan.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (C) 2021 Intel Corporation. + */ +#ifndef _UAPI_WWAN_H_ +#define _UAPI_WWAN_H_ + +enum { + IFLA_WWAN_UNSPEC, + IFLA_WWAN_DEV_NAME, /* nul-string */ + IFLA_WWAN_LINK_ID, /* u32 */ + + __IFLA_WWAN_MAX +}; +#define IFLA_WWAN_MAX (__IFLA_WWAN_MAX - 1) + +#endif /* _UAPI_WWAN_H_ */ From patchwork Tue Jun 1 08:05:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 12290669 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4BEC5C47097 for ; Tue, 1 Jun 2021 08:05:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 294926136E for ; Tue, 1 Jun 2021 08:05:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233351AbhFAIHe (ORCPT ); Tue, 1 Jun 2021 04:07:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51190 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233237AbhFAIH1 (ORCPT ); Tue, 1 Jun 2021 04:07:27 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8B318C061760; Tue, 1 Jun 2021 01:05:46 -0700 (PDT) Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1lnzPE-000V6C-JK; Tue, 01 Jun 2021 10:05:44 +0200 From: Johannes Berg To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: m.chetan.kumar@intel.com, loic.poulain@linaro.org, Johannes Berg Subject: [RFC 4/4] iosm: convert to generic wwan ops Date: Tue, 1 Jun 2021 10:05:38 +0200 Message-Id: <20210601100320.8bbd87f9ca38.I7a6cdc107f55e4d872552a58888424bd5896589a@changeid> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210601080538.71036-1-johannes@sipsolutions.net> References: <20210601080538.71036-1-johannes@sipsolutions.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC From: Johannes Berg Signed-off-by: Johannes Berg --- drivers/net/wwan/iosm/iosm_ipc_imem_ops.h | 1 - drivers/net/wwan/iosm/iosm_ipc_pcie.c | 7 - drivers/net/wwan/iosm/iosm_ipc_pcie.h | 2 - drivers/net/wwan/iosm/iosm_ipc_wwan.c | 310 +++++++--------------- include/uapi/linux/if_link.h | 10 - tools/include/uapi/linux/if_link.h | 10 - 6 files changed, 103 insertions(+), 237 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h index 6677a82be77b..84087cf33329 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h @@ -29,7 +29,6 @@ /* IP MUX channel range */ #define IP_MUX_SESSION_START 1 #define IP_MUX_SESSION_END 8 -#define MAX_IP_MUX_SESSION IP_MUX_SESSION_END /** * ipc_imem_sys_port_open - Open a port link to CP. diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c index 0c26047ebc1c..ac6baddfde61 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.c +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c @@ -567,18 +567,11 @@ static int __init iosm_ipc_driver_init(void) return -1; } - if (rtnl_link_register(&iosm_netlink)) { - pr_err("IOSM RTNL register failed"); - pci_unregister_driver(&iosm_ipc_driver); - return -1; - } - return 0; } static void __exit iosm_ipc_driver_exit(void) { - rtnl_link_unregister(&iosm_netlink); pci_unregister_driver(&iosm_ipc_driver); } diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.h b/drivers/net/wwan/iosm/iosm_ipc_pcie.h index 839809fee3dd..7d1f0cd7364c 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.h +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.h @@ -12,8 +12,6 @@ #include "iosm_ipc_irq.h" -extern struct rtnl_link_ops iosm_netlink; - /* Device ID */ #define INTEL_CP_DEVICE_7560_ID 0x7560 diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c index 719c88d9b2e9..daf3d36edc4e 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c +++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c @@ -6,8 +6,7 @@ #include #include #include -#include - +#include #include "iosm_ipc_chnl_cfg.h" #include "iosm_ipc_imem_ops.h" #include "iosm_ipc_wwan.h" @@ -18,65 +17,52 @@ #define IOSM_IF_ID_PAYLOAD 2 -static struct device_type wwan_type = { .name = "wwan" }; - -static const struct nla_policy ipc_wwan_policy[IFLA_IOSM_MAX + 1] = { - [IFLA_IOSM_IF_ID] = { .type = NLA_U16 }, -}; - /** - * struct iosm_net_link - This structure includes information about interface - * dev. + * struct iosm_netdev_priv - netdev private data * @if_id: Interface id for device. * @ch_id: IPC channel number for which interface device is created. - * @netdev: Pointer to network interface device structure * @ipc_wwan: Pointer to iosm_wwan struct */ - -struct iosm_net_link { +struct iosm_netdev_priv { + struct iosm_wwan *ipc_wwan; + struct net_device *netdev; int if_id; int ch_id; - struct net_device *netdev; - struct iosm_wwan *ipc_wwan; }; /** * struct iosm_wwan - This structure contains information about WWAN root device - * and interface to the IPC layer. - * @netdev: Pointer to network interface device structure. - * @sub_netlist: List of netlink interfaces + * and interface to the IPC layer. * @ipc_imem: Pointer to imem data-struct + * @sub_netlist: List of active netdevs * @dev: Pointer device structure * @if_mutex: Mutex used for add and remove interface id - * @is_registered: Registration status with netdev */ struct iosm_wwan { - struct net_device *netdev; - struct iosm_net_link __rcu *sub_netlist[MAX_IP_MUX_SESSION]; struct iosm_imem *ipc_imem; + struct iosm_netdev_priv __rcu *sub_netlist[IP_MUX_SESSION_END + 1]; struct device *dev; struct mutex if_mutex; /* Mutex used for add and remove interface id */ - u8 is_registered:1; }; /* Bring-up the wwan net link */ static int ipc_wwan_link_open(struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); - struct iosm_wwan *ipc_wwan = netlink->ipc_wwan; - int if_id = netlink->if_id; - int ret = -EINVAL; + struct iosm_netdev_priv *priv = netdev_priv(netdev); + struct iosm_wwan *ipc_wwan = priv->ipc_wwan; + int if_id = priv->if_id; + int ret; - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) - return ret; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; mutex_lock(&ipc_wwan->if_mutex); /* get channel id */ - netlink->ch_id = - ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id); + priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id); - if (netlink->ch_id < 0) { + if (priv->ch_id < 0) { dev_err(ipc_wwan->dev, "cannot connect wwan0 & id %d to the IPC mem layer", if_id); @@ -88,7 +74,7 @@ static int ipc_wwan_link_open(struct net_device *netdev) netif_start_queue(netdev); dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d", - netlink->ch_id, netlink->if_id); + priv->ch_id, priv->if_id); ret = 0; out: @@ -99,14 +85,15 @@ static int ipc_wwan_link_open(struct net_device *netdev) /* Bring-down the wwan net link */ static int ipc_wwan_link_stop(struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); + struct iosm_netdev_priv *priv = netdev_priv(netdev); netif_stop_queue(netdev); - mutex_lock(&netlink->ipc_wwan->if_mutex); - ipc_imem_sys_wwan_close(netlink->ipc_wwan->ipc_imem, netlink->if_id, - netlink->ch_id); - mutex_unlock(&netlink->ipc_wwan->if_mutex); + mutex_lock(&priv->ipc_wwan->if_mutex); + ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id, + priv->ch_id); + priv->ch_id = -1; + mutex_unlock(&priv->ipc_wwan->if_mutex); return 0; } @@ -115,20 +102,21 @@ static int ipc_wwan_link_stop(struct net_device *netdev) static int ipc_wwan_link_transmit(struct sk_buff *skb, struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); - struct iosm_wwan *ipc_wwan = netlink->ipc_wwan; - int if_id = netlink->if_id; - int ret = -EINVAL; + struct iosm_netdev_priv *priv = netdev_priv(netdev); + struct iosm_wwan *ipc_wwan = priv->ipc_wwan; + int if_id = priv->if_id; + int ret; /* Interface IDs from 1 to 8 are for IP data * & from 257 to 261 are for non-IP data */ - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) - goto exit; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; /* Send the SKB to device for transmission */ ret = ipc_imem_sys_wwan_transmit(ipc_wwan->ipc_imem, - if_id, netlink->ch_id, skb); + if_id, priv->ch_id, skb); /* Return code of zero is success */ if (ret == 0) { @@ -175,137 +163,72 @@ static void ipc_wwan_setup(struct net_device *iosm_dev) iosm_dev->netdev_ops = &ipc_inm_ops; } -static struct device_type inm_type = { .name = "iosmdev" }; - /* Create new wwan net link */ -static int ipc_wwan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) +static int ipc_wwan_newlink(void *ctxt, struct net_device *dev, + u32 if_id, struct netlink_ext_ack *extack) { - struct iosm_net_link *netlink = netdev_priv(dev); - struct iosm_wwan *ipc_wwan; - struct net_device *netdev; - int err = -EINVAL; - int index; - - if (!data[IFLA_IOSM_IF_ID]) { - pr_err("Interface ID not specified"); - goto out; - } - - if (!tb[IFLA_LINK]) { - pr_err("Link not specified"); - goto out; - } - - netlink->netdev = dev; - - netdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); - - netlink->ipc_wwan = netdev_priv(netdev); - - ipc_wwan = netlink->ipc_wwan; + struct iosm_wwan *ipc_wwan = ctxt; + struct iosm_netdev_priv *priv; + int err; - if (ipc_wwan->netdev != netdev) - goto out; - - netlink->if_id = nla_get_u16(data[IFLA_IOSM_IF_ID]); - index = netlink->if_id; - - /* Complete all memory stores before this point */ - smp_mb(); - if (index < IP_MUX_SESSION_START || index > IP_MUX_SESSION_END) - goto out; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; - rcu_read_lock(); + priv = netdev_priv(dev); + priv->if_id = if_id; - if (rcu_access_pointer(ipc_wwan->sub_netlist[index - 1])) { - pr_err("IOSM interface ID already in use"); - goto out_free_lock; + mutex_lock(&ipc_wwan->if_mutex); + if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id])) { + err = -EBUSY; + goto out_unlock; } - SET_NETDEV_DEVTYPE(dev, &inm_type); - - eth_hw_addr_random(dev); err = register_netdevice(dev); - if (err) { - dev_err(ipc_wwan->dev, "register netlink failed.\n"); - goto out_free_lock; - } - - err = netdev_upper_dev_link(ipc_wwan->netdev, dev, extack); + if (err) + goto out_unlock; - if (err) { - dev_err(ipc_wwan->dev, "netdev linking with parent failed.\n"); - goto netlink_err; - } + rcu_assign_pointer(ipc_wwan->sub_netlist[if_id], priv); + mutex_unlock(&ipc_wwan->if_mutex); - rcu_assign_pointer(ipc_wwan->sub_netlist[index - 1], netlink); netif_device_attach(dev); - rcu_read_unlock(); return 0; -netlink_err: - unregister_netdevice(dev); -out_free_lock: - rcu_read_unlock(); -out: +out_unlock: + mutex_unlock(&ipc_wwan->if_mutex); return err; } -/* Delete new wwan net link */ -static void ipc_wwan_dellink(struct net_device *dev, struct list_head *head) +static void ipc_wwan_dellink(void *ctxt, struct net_device *dev, + struct list_head *head) { - struct iosm_net_link *netlink = netdev_priv(dev); - u16 index = netlink->if_id; - - netdev_upper_dev_unlink(netlink->ipc_wwan->netdev, dev); - unregister_netdevice(dev); + struct iosm_wwan *ipc_wwan = ctxt; + struct iosm_netdev_priv *priv = netdev_priv(dev); + int if_id = priv->if_id; - mutex_lock(&netlink->ipc_wwan->if_mutex); - rcu_assign_pointer(netlink->ipc_wwan->sub_netlist[index - 1], NULL); - mutex_unlock(&netlink->ipc_wwan->if_mutex); -} + if (WARN_ON(if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))) + return; -/* Get size for iosm net link payload*/ -static size_t ipc_wwan_get_size(const struct net_device *dev) -{ - return nla_total_size(IOSM_IF_ID_PAYLOAD); -} - -/* Validate the input parameters for wwan net link */ -static int ipc_wwan_validate(struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) -{ - u16 if_id; - - if (!data || !data[IFLA_IOSM_IF_ID]) { - NL_SET_ERR_MSG_MOD(extack, "IF ID not specified"); - return -EINVAL; - } + mutex_lock(&ipc_wwan->if_mutex); - if_id = nla_get_u16(data[IFLA_IOSM_IF_ID]); + if (WARN_ON(rcu_access_pointer(ipc_wwan->sub_netlist[if_id]) != priv)) + goto unlock; - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) { - NL_SET_ERR_MSG_MOD(extack, "Invalid Interface"); - return -ERANGE; - } + RCU_INIT_POINTER(ipc_wwan->sub_netlist[if_id], NULL); + /* unregistering includes synchronize_net() */ + unregister_netdevice(dev); - return 0; +unlock: + mutex_unlock(&ipc_wwan->if_mutex); } -/* RT Net link ops structure for new wwan net link */ -struct rtnl_link_ops iosm_netlink __read_mostly = { - .kind = "iosm", - .maxtype = __IFLA_IOSM_MAX, - .priv_size = sizeof(struct iosm_net_link), - .setup = ipc_wwan_setup, - .validate = ipc_wwan_validate, - .newlink = ipc_wwan_newlink, - .dellink = ipc_wwan_dellink, - .get_size = ipc_wwan_get_size, - .policy = ipc_wwan_policy, +static const struct wwan_ops iosm_wwan_ops = { + .priv_size = sizeof(struct iosm_netdev_priv), + .setup = ipc_wwan_setup, + .newlink = ipc_wwan_newlink, + .dellink = ipc_wwan_dellink, }; int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, @@ -313,7 +236,7 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, { struct sk_buff *skb = skb_arg; struct net_device_stats *stats; - struct iosm_net_link *priv; + struct iosm_netdev_priv *priv; int ret; if ((skb->data[0] & IOSM_IP_TYPE_MASK) == IOSM_IP_TYPE_IPV4) @@ -353,10 +276,17 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int if_id, bool on) { struct net_device *netdev; + struct iosm_netdev_priv *priv; bool is_tx_blk; rcu_read_lock(); - netdev = rcu_dereference(ipc_wwan->sub_netlist[if_id])->netdev; + priv = rcu_dereference(ipc_wwan->sub_netlist[if_id]); + if (!priv) { + rcu_read_unlock(); + return; + } + + netdev = priv->netdev; is_tx_blk = netif_queue_stopped(netdev); @@ -371,78 +301,44 @@ void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int if_id, bool on) rcu_read_unlock(); } -static void ipc_netdev_setup(struct net_device *dev) {} - struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev) { - static const struct net_device_ops iosm_wwandev_ops = {}; struct iosm_wwan *ipc_wwan; - struct net_device *netdev; - netdev = alloc_netdev(sizeof(*ipc_wwan), "wwan%d", NET_NAME_ENUM, - ipc_netdev_setup); - - if (!netdev) + ipc_wwan = kzalloc(sizeof(*ipc_wwan), GFP_KERNEL); + if (!ipc_wwan) return NULL; - ipc_wwan = netdev_priv(netdev); - ipc_wwan->dev = dev; - ipc_wwan->netdev = netdev; - ipc_wwan->is_registered = false; - ipc_wwan->ipc_imem = ipc_imem; - mutex_init(&ipc_wwan->if_mutex); - - /* allocate random ethernet address */ - eth_random_addr(netdev->dev_addr); - netdev->addr_assign_type = NET_ADDR_RANDOM; - - netdev->netdev_ops = &iosm_wwandev_ops; - netdev->flags |= IFF_NOARP; - - SET_NETDEV_DEVTYPE(netdev, &wwan_type); - - if (register_netdev(netdev)) { - dev_err(ipc_wwan->dev, "register_netdev failed"); - goto reg_fail; + if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan)) { + kfree(ipc_wwan); + return NULL; } - ipc_wwan->is_registered = true; - - netif_device_attach(netdev); + mutex_init(&ipc_wwan->if_mutex); return ipc_wwan; - -reg_fail: - free_netdev(netdev); - return NULL; } void ipc_wwan_deinit(struct iosm_wwan *ipc_wwan) { - struct iosm_net_link *netlink; - int i; - - if (ipc_wwan->is_registered) { - rcu_read_lock(); - for (i = IP_MUX_SESSION_START; i <= IP_MUX_SESSION_END; i++) { - if (rcu_access_pointer(ipc_wwan->sub_netlist[i - 1])) { - netlink = - rcu_dereference(ipc_wwan->sub_netlist[i - 1]); - rtnl_lock(); - netdev_upper_dev_unlink(ipc_wwan->netdev, - netlink->netdev); - unregister_netdevice(netlink->netdev); - rtnl_unlock(); - rcu_assign_pointer(ipc_wwan->sub_netlist[i - 1], - NULL); - } - } - rcu_read_unlock(); + int if_id; - unregister_netdev(ipc_wwan->netdev); - free_netdev(ipc_wwan->netdev); + wwan_unregister_ops(ipc_wwan->dev); + + for (if_id = 0; if_id < ARRAY_SIZE(ipc_wwan->sub_netlist); if_id++) { + struct iosm_netdev_priv *priv; + + priv = rcu_access_pointer(ipc_wwan->sub_netlist[if_id]); + if (!priv) + continue; + + ipc_wwan_dellink(ipc_wwan, priv->netdev, NULL); } + + mutex_destroy(&ipc_wwan->if_mutex); + + kfree(ipc_wwan); } diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index f7c3beebb074..cd5b382a4138 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1251,14 +1251,4 @@ struct ifla_rmnet_flags { __u32 mask; }; -/* IOSM Section */ - -enum { - IFLA_IOSM_UNSPEC, - IFLA_IOSM_IF_ID, - __IFLA_IOSM_MAX, -}; - -#define IFLA_IOSM_MAX (__IFLA_IOSM_MAX - 1) - #endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cb496d0de39e..d208b2af697f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -1046,14 +1046,4 @@ struct ifla_rmnet_flags { __u32 mask; }; -/* IOSM Section */ - -enum { - IFLA_IOSM_UNSPEC, - IFLA_IOSM_IF_ID, - __IFLA_IOSM_MAX, -}; - -#define IFLA_IOSM_MAX (__IFLA_IOSM_MAX - 1) - #endif /* _UAPI_LINUX_IF_LINK_H */