From ceed73a2cf4aff2921802aa3d21d45280677547d Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Tue, 29 Aug 2017 22:44:18 -0600 Subject: drivers: net: ethernet: qualcomm: rmnet: Initial implementation RmNet driver provides a transport agnostic MAP (multiplexing and aggregation protocol) support in embedded module. Module provides virtual network devices which can be attached to any IP-mode physical device. This will be used to provide all MAP functionality on future hardware in a single consistent location. Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/Kconfig | 12 + drivers/net/ethernet/qualcomm/rmnet/Makefile | 10 + drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 419 +++++++++++++++++++++ drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 56 +++ .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 271 +++++++++++++ .../net/ethernet/qualcomm/rmnet/rmnet_handlers.h | 26 ++ drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 88 +++++ .../ethernet/qualcomm/rmnet/rmnet_map_command.c | 107 ++++++ .../net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 105 ++++++ .../net/ethernet/qualcomm/rmnet/rmnet_private.h | 45 +++ drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 170 +++++++++ drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 29 ++ 12 files changed, 1338 insertions(+) create mode 100644 drivers/net/ethernet/qualcomm/rmnet/Kconfig create mode 100644 drivers/net/ethernet/qualcomm/rmnet/Makefile create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c create mode 100644 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/Kconfig b/drivers/net/ethernet/qualcomm/rmnet/Kconfig new file mode 100644 index 000000000000..6e2587af47a4 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/Kconfig @@ -0,0 +1,12 @@ +# +# RMNET MAP driver +# + +menuconfig RMNET + tristate "RmNet MAP driver" + default n + ---help--- + If you select this, you will enable the RMNET module which is used + for handling data in the multiplexing and aggregation protocol (MAP) + format in the embedded data path. RMNET devices can be attached to + any IP mode physical device. diff --git a/drivers/net/ethernet/qualcomm/rmnet/Makefile b/drivers/net/ethernet/qualcomm/rmnet/Makefile new file mode 100644 index 000000000000..01bddf207cac --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the RMNET module +# + +rmnet-y := rmnet_config.o +rmnet-y += rmnet_vnd.o +rmnet-y += rmnet_handlers.o +rmnet-y += rmnet_map_data.o +rmnet-y += rmnet_map_command.o +obj-$(CONFIG_RMNET) += rmnet.o diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c new file mode 100644 index 000000000000..e836d267d5cc --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -0,0 +1,419 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET configuration engine + * + */ + +#include +#include +#include +#include +#include "rmnet_config.h" +#include "rmnet_handlers.h" +#include "rmnet_vnd.h" +#include "rmnet_private.h" + +/* Locking scheme - + * The shared resource which needs to be protected is realdev->rx_handler_data. + * For the writer path, this is using rtnl_lock(). The writer paths are + * rmnet_newlink(), rmnet_dellink() and rmnet_force_unassociate_device(). These + * paths are already called with rtnl_lock() acquired in. There is also an + * ASSERT_RTNL() to ensure that we are calling with rtnl acquired. For + * dereference here, we will need to use rtnl_dereference(). Dev list writing + * needs to happen with rtnl_lock() acquired for netdev_master_upper_dev_link(). + * For the reader path, the real_dev->rx_handler_data is called in the TX / RX + * path. We only need rcu_read_lock() for these scenarios. In these cases, + * the rcu_read_lock() is held in __dev_queue_xmit() and + * netif_receive_skb_internal(), so readers need to use rcu_dereference_rtnl() + * to get the relevant information. For dev list reading, we again acquire + * rcu_read_lock() in rmnet_dellink() for netdev_master_upper_dev_get_rcu(). + * We also use unregister_netdevice_many() to free all rmnet devices in + * rmnet_force_unassociate_device() so we dont lose the rtnl_lock() and free in + * same context. + */ + +/* Local Definitions and Declarations */ +#define RMNET_LOCAL_LOGICAL_ENDPOINT -1 + +struct rmnet_walk_data { + struct net_device *real_dev; + struct list_head *head; + struct rmnet_real_dev_info *real_dev_info; +}; + +static int rmnet_is_real_dev_registered(const struct net_device *real_dev) +{ + rx_handler_func_t *rx_handler; + + rx_handler = rcu_dereference(real_dev->rx_handler); + return (rx_handler == rmnet_rx_handler); +} + +/* Needs either rcu_read_lock() or rtnl lock */ +static struct rmnet_real_dev_info* +__rmnet_get_real_dev_info(const struct net_device *real_dev) +{ + if (rmnet_is_real_dev_registered(real_dev)) + return rcu_dereference_rtnl(real_dev->rx_handler_data); + else + return NULL; +} + +/* Needs rtnl lock */ +static struct rmnet_real_dev_info* +rmnet_get_real_dev_info_rtnl(const struct net_device *real_dev) +{ + return rtnl_dereference(real_dev->rx_handler_data); +} + +static struct rmnet_endpoint* +rmnet_get_endpoint(struct net_device *dev, int config_id) +{ + struct rmnet_real_dev_info *r; + struct rmnet_endpoint *ep; + + if (!rmnet_is_real_dev_registered(dev)) { + ep = rmnet_vnd_get_endpoint(dev); + } else { + r = __rmnet_get_real_dev_info(dev); + + if (!r) + return NULL; + + if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) + ep = &r->local_ep; + else + ep = &r->muxed_ep[config_id]; + } + + return ep; +} + +static int rmnet_unregister_real_device(struct net_device *real_dev, + struct rmnet_real_dev_info *r) +{ + if (r->nr_rmnet_devs) + return -EINVAL; + + kfree(r); + + netdev_rx_handler_unregister(real_dev); + + /* release reference on real_dev */ + dev_put(real_dev); + + netdev_dbg(real_dev, "Removed from rmnet\n"); + return 0; +} + +static int rmnet_register_real_device(struct net_device *real_dev) +{ + struct rmnet_real_dev_info *r; + int rc; + + ASSERT_RTNL(); + + if (rmnet_is_real_dev_registered(real_dev)) + return 0; + + r = kzalloc(sizeof(*r), GFP_ATOMIC); + if (!r) + return -ENOMEM; + + r->dev = real_dev; + rc = netdev_rx_handler_register(real_dev, rmnet_rx_handler, r); + if (rc) { + kfree(r); + return -EBUSY; + } + + /* hold on to real dev for MAP data */ + dev_hold(real_dev); + + netdev_dbg(real_dev, "registered with rmnet\n"); + return 0; +} + +static int rmnet_set_ingress_data_format(struct net_device *dev, u32 idf) +{ + struct rmnet_real_dev_info *r; + + netdev_dbg(dev, "Ingress format 0x%08X\n", idf); + + r = __rmnet_get_real_dev_info(dev); + + r->ingress_data_format = idf; + + return 0; +} + +static int rmnet_set_egress_data_format(struct net_device *dev, u32 edf, + u16 agg_size, u16 agg_count) +{ + struct rmnet_real_dev_info *r; + + netdev_dbg(dev, "Egress format 0x%08X agg size %d cnt %d\n", + edf, agg_size, agg_count); + + r = __rmnet_get_real_dev_info(dev); + + r->egress_data_format = edf; + + return 0; +} + +static int __rmnet_set_endpoint_config(struct net_device *dev, int config_id, + struct rmnet_endpoint *ep) +{ + struct rmnet_endpoint *dev_ep; + + dev_ep = rmnet_get_endpoint(dev, config_id); + + if (!dev_ep) + return -EINVAL; + + memcpy(dev_ep, ep, sizeof(struct rmnet_endpoint)); + if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) + dev_ep->mux_id = 0; + else + dev_ep->mux_id = config_id; + + return 0; +} + +static int rmnet_set_endpoint_config(struct net_device *dev, + int config_id, u8 rmnet_mode, + struct net_device *egress_dev) +{ + struct rmnet_endpoint ep; + + netdev_dbg(dev, "id %d mode %d dev %s\n", + config_id, rmnet_mode, egress_dev->name); + + if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT || + config_id >= RMNET_MAX_LOGICAL_EP) + return -EINVAL; + + /* This config is cleared on every set, so its ok to not + * clear it on a device delete. + */ + memset(&ep, 0, sizeof(struct rmnet_endpoint)); + ep.rmnet_mode = rmnet_mode; + ep.egress_dev = egress_dev; + + return __rmnet_set_endpoint_config(dev, config_id, &ep); +} + +static int rmnet_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + int ingress_format = RMNET_INGRESS_FORMAT_DEMUXING | + RMNET_INGRESS_FORMAT_DEAGGREGATION | + RMNET_INGRESS_FORMAT_MAP; + int egress_format = RMNET_EGRESS_FORMAT_MUXING | + RMNET_EGRESS_FORMAT_MAP; + struct rmnet_real_dev_info *r; + struct net_device *real_dev; + int mode = RMNET_EPMODE_VND; + int err = 0; + u16 mux_id; + + real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); + if (!real_dev || !dev) + return -ENODEV; + + if (!data[IFLA_VLAN_ID]) + return -EINVAL; + + mux_id = nla_get_u16(data[IFLA_VLAN_ID]); + + err = rmnet_register_real_device(real_dev); + if (err) + goto err0; + + r = rmnet_get_real_dev_info_rtnl(real_dev); + err = rmnet_vnd_newlink(mux_id, dev, r); + if (err) + goto err1; + + err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL); + if (err) + goto err2; + + rmnet_vnd_set_mux(dev, mux_id); + rmnet_set_egress_data_format(real_dev, egress_format, 0, 0); + rmnet_set_ingress_data_format(real_dev, ingress_format); + rmnet_set_endpoint_config(real_dev, mux_id, mode, dev); + rmnet_set_endpoint_config(dev, mux_id, mode, real_dev); + return 0; + +err2: + rmnet_vnd_dellink(mux_id, r); +err1: + rmnet_unregister_real_device(real_dev, r); +err0: + return err; +} + +static void rmnet_dellink(struct net_device *dev, struct list_head *head) +{ + struct rmnet_real_dev_info *r; + struct net_device *real_dev; + u8 mux_id; + + rcu_read_lock(); + real_dev = netdev_master_upper_dev_get_rcu(dev); + rcu_read_unlock(); + + if (!real_dev || !rmnet_is_real_dev_registered(real_dev)) + return; + + r = rmnet_get_real_dev_info_rtnl(real_dev); + + mux_id = rmnet_vnd_get_mux(dev); + rmnet_vnd_dellink(mux_id, r); + netdev_upper_dev_unlink(dev, real_dev); + rmnet_unregister_real_device(real_dev, r); + + unregister_netdevice_queue(dev, head); +} + +static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data) +{ + struct rmnet_walk_data *d = data; + u8 mux_id; + + mux_id = rmnet_vnd_get_mux(rmnet_dev); + + rmnet_vnd_dellink(mux_id, d->real_dev_info); + netdev_upper_dev_unlink(rmnet_dev, d->real_dev); + unregister_netdevice_queue(rmnet_dev, d->head); + + return 0; +} + +static void rmnet_force_unassociate_device(struct net_device *dev) +{ + struct net_device *real_dev = dev; + struct rmnet_real_dev_info *r; + struct rmnet_walk_data d; + LIST_HEAD(list); + + if (!rmnet_is_real_dev_registered(real_dev)) + return; + + ASSERT_RTNL(); + + d.real_dev = real_dev; + d.head = &list; + + r = rmnet_get_real_dev_info_rtnl(dev); + d.real_dev_info = r; + + rcu_read_lock(); + netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d); + rcu_read_unlock(); + unregister_netdevice_many(&list); + + rmnet_unregister_real_device(real_dev, r); +} + +static int rmnet_config_notify_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct net_device *dev = netdev_notifier_info_to_dev(data); + + if (!dev) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UNREGISTER: + netdev_dbg(dev, "Kernel unregister\n"); + rmnet_force_unassociate_device(dev); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block rmnet_dev_notifier __read_mostly = { + .notifier_call = rmnet_config_notify_cb, +}; + +static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + u16 mux_id; + + if (!data || !data[IFLA_VLAN_ID]) + return -EINVAL; + + mux_id = nla_get_u16(data[IFLA_VLAN_ID]); + if (mux_id > (RMNET_MAX_LOGICAL_EP - 1)) + return -ERANGE; + + return 0; +} + +static size_t rmnet_get_size(const struct net_device *dev) +{ + return nla_total_size(2); /* IFLA_VLAN_ID */ +} + +struct rtnl_link_ops rmnet_link_ops __read_mostly = { + .kind = "rmnet", + .maxtype = __IFLA_VLAN_MAX, + .priv_size = sizeof(struct rmnet_priv), + .setup = rmnet_vnd_setup, + .validate = rmnet_rtnl_validate, + .newlink = rmnet_newlink, + .dellink = rmnet_dellink, + .get_size = rmnet_get_size, +}; + +struct rmnet_real_dev_info* +rmnet_get_real_dev_info(struct net_device *real_dev) +{ + return __rmnet_get_real_dev_info(real_dev); +} + +/* Startup/Shutdown */ + +static int __init rmnet_init(void) +{ + int rc; + + rc = register_netdevice_notifier(&rmnet_dev_notifier); + if (rc != 0) + return rc; + + rc = rtnl_link_register(&rmnet_link_ops); + if (rc != 0) { + unregister_netdevice_notifier(&rmnet_dev_notifier); + return rc; + } + return rc; +} + +static void __exit rmnet_exit(void) +{ + unregister_netdevice_notifier(&rmnet_dev_notifier); + rtnl_link_unregister(&rmnet_link_ops); +} + +module_init(rmnet_init) +module_exit(rmnet_exit) +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h new file mode 100644 index 000000000000..985d372e0d8d --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data configuration engine + * + */ + +#include + +#ifndef _RMNET_CONFIG_H_ +#define _RMNET_CONFIG_H_ + +#define RMNET_MAX_LOGICAL_EP 255 +#define RMNET_MAX_VND 32 + +/* Information about the next device to deliver the packet to. + * Exact usage of this parameter depends on the rmnet_mode. + */ +struct rmnet_endpoint { + u8 rmnet_mode; + u8 mux_id; + struct net_device *egress_dev; +}; + +/* One instance of this structure is instantiated for each real_dev associated + * with rmnet. + */ +struct rmnet_real_dev_info { + struct net_device *dev; + struct rmnet_endpoint local_ep; + struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP]; + u32 ingress_data_format; + u32 egress_data_format; + struct net_device *rmnet_devices[RMNET_MAX_VND]; + u8 nr_rmnet_devs; +}; + +extern struct rtnl_link_ops rmnet_link_ops; + +struct rmnet_priv { + struct rmnet_endpoint local_ep; + u8 mux_id; +}; + +struct rmnet_real_dev_info* +rmnet_get_real_dev_info(struct net_device *real_dev); + +#endif /* _RMNET_CONFIG_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c new file mode 100644 index 000000000000..7dab3bbfeda5 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -0,0 +1,271 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data ingress/egress handler + * + */ + +#include +#include +#include "rmnet_private.h" +#include "rmnet_config.h" +#include "rmnet_vnd.h" +#include "rmnet_map.h" +#include "rmnet_handlers.h" + +#define RMNET_IP_VERSION_4 0x40 +#define RMNET_IP_VERSION_6 0x60 + +/* Helper Functions */ + +static void rmnet_set_skb_proto(struct sk_buff *skb) +{ + switch (skb->data[0] & 0xF0) { + case RMNET_IP_VERSION_4: + skb->protocol = htons(ETH_P_IP); + break; + case RMNET_IP_VERSION_6: + skb->protocol = htons(ETH_P_IPV6); + break; + default: + skb->protocol = htons(ETH_P_MAP); + break; + } +} + +/* Generic handler */ + +static rx_handler_result_t +rmnet_bridge_handler(struct sk_buff *skb, struct rmnet_endpoint *ep) +{ + if (!ep->egress_dev) + kfree_skb(skb); + else + rmnet_egress_handler(skb, ep); + + return RX_HANDLER_CONSUMED; +} + +static rx_handler_result_t +rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_endpoint *ep) +{ + switch (ep->rmnet_mode) { + case RMNET_EPMODE_NONE: + return RX_HANDLER_PASS; + + case RMNET_EPMODE_BRIDGE: + return rmnet_bridge_handler(skb, ep); + + case RMNET_EPMODE_VND: + skb_reset_transport_header(skb); + skb_reset_network_header(skb); + rmnet_vnd_rx_fixup(skb, skb->dev); + + skb->pkt_type = PACKET_HOST; + skb_set_mac_header(skb, 0); + netif_receive_skb(skb); + return RX_HANDLER_CONSUMED; + + default: + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } +} + +static rx_handler_result_t +rmnet_ingress_deliver_packet(struct sk_buff *skb, + struct rmnet_real_dev_info *r) +{ + if (!r) { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + skb->dev = r->local_ep.egress_dev; + + return rmnet_deliver_skb(skb, &r->local_ep); +} + +/* MAP handler */ + +static rx_handler_result_t +__rmnet_map_ingress_handler(struct sk_buff *skb, + struct rmnet_real_dev_info *r) +{ + struct rmnet_endpoint *ep; + u8 mux_id; + u16 len; + + if (RMNET_MAP_GET_CD_BIT(skb)) { + if (r->ingress_data_format + & RMNET_INGRESS_FORMAT_MAP_COMMANDS) + return rmnet_map_command(skb, r); + + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + mux_id = RMNET_MAP_GET_MUX_ID(skb); + len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb); + + if (mux_id >= RMNET_MAX_LOGICAL_EP) { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + ep = &r->muxed_ep[mux_id]; + + if (r->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING) + skb->dev = ep->egress_dev; + + /* Subtract MAP header */ + skb_pull(skb, sizeof(struct rmnet_map_header)); + skb_trim(skb, len); + rmnet_set_skb_proto(skb); + return rmnet_deliver_skb(skb, ep); +} + +static rx_handler_result_t +rmnet_map_ingress_handler(struct sk_buff *skb, + struct rmnet_real_dev_info *r) +{ + struct sk_buff *skbn; + int rc; + + if (r->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { + while ((skbn = rmnet_map_deaggregate(skb, r)) != NULL) + __rmnet_map_ingress_handler(skbn, r); + + consume_skb(skb); + rc = RX_HANDLER_CONSUMED; + } else { + rc = __rmnet_map_ingress_handler(skb, r); + } + + return rc; +} + +static int rmnet_map_egress_handler(struct sk_buff *skb, + struct rmnet_real_dev_info *r, + struct rmnet_endpoint *ep, + struct net_device *orig_dev) +{ + int required_headroom, additional_header_len; + struct rmnet_map_header *map_header; + + additional_header_len = 0; + required_headroom = sizeof(struct rmnet_map_header); + + if (skb_headroom(skb) < required_headroom) { + if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) + return RMNET_MAP_CONSUMED; + } + + map_header = rmnet_map_add_map_header(skb, additional_header_len, 0); + if (!map_header) + return RMNET_MAP_CONSUMED; + + if (r->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) { + if (ep->mux_id == 0xff) + map_header->mux_id = 0; + else + map_header->mux_id = ep->mux_id; + } + + skb->protocol = htons(ETH_P_MAP); + + return RMNET_MAP_SUCCESS; +} + +/* Ingress / Egress Entry Points */ + +/* Processes packet as per ingress data format for receiving device. Logical + * endpoint is determined from packet inspection. Packet is then sent to the + * egress device listed in the logical endpoint configuration. + */ +rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) +{ + struct rmnet_real_dev_info *r; + struct sk_buff *skb = *pskb; + struct net_device *dev; + int rc; + + if (!skb) + return RX_HANDLER_CONSUMED; + + dev = skb->dev; + r = rmnet_get_real_dev_info(dev); + + if (r->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) { + rc = rmnet_map_ingress_handler(skb, r); + } else { + switch (ntohs(skb->protocol)) { + case ETH_P_MAP: + if (r->local_ep.rmnet_mode == + RMNET_EPMODE_BRIDGE) { + rc = rmnet_ingress_deliver_packet(skb, r); + } else { + kfree_skb(skb); + rc = RX_HANDLER_CONSUMED; + } + break; + + case ETH_P_IP: + case ETH_P_IPV6: + rc = rmnet_ingress_deliver_packet(skb, r); + break; + + default: + rc = RX_HANDLER_PASS; + } + } + + return rc; +} + +/* Modifies packet as per logical endpoint configuration and egress data format + * for egress device configured in logical endpoint. Packet is then transmitted + * on the egress device. + */ +void rmnet_egress_handler(struct sk_buff *skb, + struct rmnet_endpoint *ep) +{ + struct rmnet_real_dev_info *r; + struct net_device *orig_dev; + + orig_dev = skb->dev; + skb->dev = ep->egress_dev; + + r = rmnet_get_real_dev_info(skb->dev); + if (!r) { + kfree_skb(skb); + return; + } + + if (r->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { + switch (rmnet_map_egress_handler(skb, r, ep, orig_dev)) { + case RMNET_MAP_CONSUMED: + return; + + case RMNET_MAP_SUCCESS: + break; + + default: + kfree_skb(skb); + return; + } + } + + if (ep->rmnet_mode == RMNET_EPMODE_VND) + rmnet_vnd_tx_fixup(skb, orig_dev); + + dev_queue_xmit(skb); +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h new file mode 100644 index 000000000000..f2638cf5693c --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2013, 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data ingress/egress handler + * + */ + +#ifndef _RMNET_HANDLERS_H_ +#define _RMNET_HANDLERS_H_ + +#include "rmnet_config.h" + +void rmnet_egress_handler(struct sk_buff *skb, + struct rmnet_endpoint *ep); + +rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb); + +#endif /* _RMNET_HANDLERS_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h new file mode 100644 index 000000000000..2aabad289b10 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _RMNET_MAP_H_ +#define _RMNET_MAP_H_ + +struct rmnet_map_control_command { + u8 command_name; + u8 cmd_type:2; + u8 reserved:6; + u16 reserved2; + u32 transaction_id; + union { + struct { + u16 ip_family:2; + u16 reserved:14; + u16 flow_control_seq_num; + u32 qos_id; + } flow_control; + u8 data[0]; + }; +} __aligned(1); + +enum rmnet_map_results { + RMNET_MAP_SUCCESS, + RMNET_MAP_CONSUMED, + RMNET_MAP_GENERAL_FAILURE, + RMNET_MAP_NOT_ENABLED, + RMNET_MAP_FAILED_AGGREGATION, + RMNET_MAP_FAILED_MUX +}; + +enum rmnet_map_commands { + RMNET_MAP_COMMAND_NONE, + RMNET_MAP_COMMAND_FLOW_DISABLE, + RMNET_MAP_COMMAND_FLOW_ENABLE, + /* These should always be the last 2 elements */ + RMNET_MAP_COMMAND_UNKNOWN, + RMNET_MAP_COMMAND_ENUM_LENGTH +}; + +struct rmnet_map_header { + u8 pad_len:6; + u8 reserved_bit:1; + u8 cd_bit:1; + u8 mux_id; + u16 pkt_len; +} __aligned(1); + +#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header *) \ + (Y)->data)->mux_id) +#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header *) \ + (Y)->data)->cd_bit) +#define RMNET_MAP_GET_PAD(Y) (((struct rmnet_map_header *) \ + (Y)->data)->pad_len) +#define RMNET_MAP_GET_CMD_START(Y) ((struct rmnet_map_control_command *) \ + ((Y)->data + \ + sizeof(struct rmnet_map_header))) +#define RMNET_MAP_GET_LENGTH(Y) (ntohs(((struct rmnet_map_header *) \ + (Y)->data)->pkt_len)) + +#define RMNET_MAP_COMMAND_REQUEST 0 +#define RMNET_MAP_COMMAND_ACK 1 +#define RMNET_MAP_COMMAND_UNSUPPORTED 2 +#define RMNET_MAP_COMMAND_INVALID 3 + +#define RMNET_MAP_NO_PAD_BYTES 0 +#define RMNET_MAP_ADD_PAD_BYTES 1 + +u8 rmnet_map_demultiplex(struct sk_buff *skb); +struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, + struct rmnet_real_dev_info *rdinfo); + +struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb, + int hdrlen, int pad); +rx_handler_result_t rmnet_map_command(struct sk_buff *skb, + struct rmnet_real_dev_info *rdinfo); + +#endif /* _RMNET_MAP_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c new file mode 100644 index 000000000000..ccded40ee551 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "rmnet_config.h" +#include "rmnet_map.h" +#include "rmnet_private.h" +#include "rmnet_vnd.h" + +static u8 rmnet_map_do_flow_control(struct sk_buff *skb, + struct rmnet_real_dev_info *rdinfo, + int enable) +{ + struct rmnet_map_control_command *cmd; + struct rmnet_endpoint *ep; + struct net_device *vnd; + u16 ip_family; + u16 fc_seq; + u32 qos_id; + u8 mux_id; + int r; + + mux_id = RMNET_MAP_GET_MUX_ID(skb); + cmd = RMNET_MAP_GET_CMD_START(skb); + + if (mux_id >= RMNET_MAX_LOGICAL_EP) { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + ep = &rdinfo->muxed_ep[mux_id]; + vnd = ep->egress_dev; + + ip_family = cmd->flow_control.ip_family; + fc_seq = ntohs(cmd->flow_control.flow_control_seq_num); + qos_id = ntohl(cmd->flow_control.qos_id); + + /* Ignore the ip family and pass the sequence number for both v4 and v6 + * sequence. User space does not support creating dedicated flows for + * the 2 protocols + */ + r = rmnet_vnd_do_flow_control(vnd, enable); + if (r) { + kfree_skb(skb); + return RMNET_MAP_COMMAND_UNSUPPORTED; + } else { + return RMNET_MAP_COMMAND_ACK; + } +} + +static void rmnet_map_send_ack(struct sk_buff *skb, + unsigned char type, + struct rmnet_real_dev_info *rdinfo) +{ + struct rmnet_map_control_command *cmd; + int xmit_status; + + skb->protocol = htons(ETH_P_MAP); + + cmd = RMNET_MAP_GET_CMD_START(skb); + cmd->cmd_type = type & 0x03; + + netif_tx_lock(skb->dev); + xmit_status = skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev); + netif_tx_unlock(skb->dev); +} + +/* Process MAP command frame and send N/ACK message as appropriate. Message cmd + * name is decoded here and appropriate handler is called. + */ +rx_handler_result_t rmnet_map_command(struct sk_buff *skb, + struct rmnet_real_dev_info *rdinfo) +{ + struct rmnet_map_control_command *cmd; + unsigned char command_name; + unsigned char rc = 0; + + cmd = RMNET_MAP_GET_CMD_START(skb); + command_name = cmd->command_name; + + switch (command_name) { + case RMNET_MAP_COMMAND_FLOW_ENABLE: + rc = rmnet_map_do_flow_control(skb, rdinfo, 1); + break; + + case RMNET_MAP_COMMAND_FLOW_DISABLE: + rc = rmnet_map_do_flow_control(skb, rdinfo, 0); + break; + + default: + rc = RMNET_MAP_COMMAND_UNSUPPORTED; + kfree_skb(skb); + break; + } + if (rc == RMNET_MAP_COMMAND_ACK) + rmnet_map_send_ack(skb, rc, rdinfo); + return RX_HANDLER_CONSUMED; +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c new file mode 100644 index 000000000000..a29c476a4755 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -0,0 +1,105 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data MAP protocol + * + */ + +#include +#include "rmnet_config.h" +#include "rmnet_map.h" +#include "rmnet_private.h" + +#define RMNET_MAP_DEAGGR_SPACING 64 +#define RMNET_MAP_DEAGGR_HEADROOM (RMNET_MAP_DEAGGR_SPACING / 2) + +/* Adds MAP header to front of skb->data + * Padding is calculated and set appropriately in MAP header. Mux ID is + * initialized to 0. + */ +struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb, + int hdrlen, int pad) +{ + struct rmnet_map_header *map_header; + u32 padding, map_datalen; + u8 *padbytes; + + if (skb_headroom(skb) < sizeof(struct rmnet_map_header)) + return NULL; + + map_datalen = skb->len - hdrlen; + map_header = (struct rmnet_map_header *) + skb_push(skb, sizeof(struct rmnet_map_header)); + memset(map_header, 0, sizeof(struct rmnet_map_header)); + + if (pad == RMNET_MAP_NO_PAD_BYTES) { + map_header->pkt_len = htons(map_datalen); + return map_header; + } + + padding = ALIGN(map_datalen, 4) - map_datalen; + + if (padding == 0) + goto done; + + if (skb_tailroom(skb) < padding) + return NULL; + + padbytes = (u8 *)skb_put(skb, padding); + memset(padbytes, 0, padding); + +done: + map_header->pkt_len = htons(map_datalen + padding); + map_header->pad_len = padding & 0x3F; + + return map_header; +} + +/* Deaggregates a single packet + * A whole new buffer is allocated for each portion of an aggregated frame. + * Caller should keep calling deaggregate() on the source skb until 0 is + * returned, indicating that there are no more packets to deaggregate. Caller + * is responsible for freeing the original skb. + */ +struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, + struct rmnet_real_dev_info *rdinfo) +{ + struct rmnet_map_header *maph; + struct sk_buff *skbn; + u32 packet_len; + + if (skb->len == 0) + return NULL; + + maph = (struct rmnet_map_header *)skb->data; + packet_len = ntohs(maph->pkt_len) + sizeof(struct rmnet_map_header); + + if (((int)skb->len - (int)packet_len) < 0) + return NULL; + + skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC); + if (!skbn) + return NULL; + + skbn->dev = skb->dev; + skb_reserve(skbn, RMNET_MAP_DEAGGR_HEADROOM); + skb_put(skbn, packet_len); + memcpy(skbn->data, skb->data, packet_len); + skb_pull(skb, packet_len); + + /* Some hardware can send us empty frames. Catch them */ + if (ntohs(maph->pkt_len) == 0) { + kfree_skb(skb); + return NULL; + } + + return skbn; +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h new file mode 100644 index 000000000000..ed820b5522f5 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _RMNET_PRIVATE_H_ +#define _RMNET_PRIVATE_H_ + +#define RMNET_MAX_VND 32 +#define RMNET_MAX_PACKET_SIZE 16384 +#define RMNET_DFLT_PACKET_SIZE 1500 +#define RMNET_NEEDED_HEADROOM 16 +#define RMNET_TX_QUEUE_LEN 1000 + +/* Constants */ +#define RMNET_EGRESS_FORMAT__RESERVED__ BIT(0) +#define RMNET_EGRESS_FORMAT_MAP BIT(1) +#define RMNET_EGRESS_FORMAT_AGGREGATION BIT(2) +#define RMNET_EGRESS_FORMAT_MUXING BIT(3) +#define RMNET_EGRESS_FORMAT_MAP_CKSUMV3 BIT(4) +#define RMNET_EGRESS_FORMAT_MAP_CKSUMV4 BIT(5) + +#define RMNET_INGRESS_FIX_ETHERNET BIT(0) +#define RMNET_INGRESS_FORMAT_MAP BIT(1) +#define RMNET_INGRESS_FORMAT_DEAGGREGATION BIT(2) +#define RMNET_INGRESS_FORMAT_DEMUXING BIT(3) +#define RMNET_INGRESS_FORMAT_MAP_COMMANDS BIT(4) +#define RMNET_INGRESS_FORMAT_MAP_CKSUMV3 BIT(5) +#define RMNET_INGRESS_FORMAT_MAP_CKSUMV4 BIT(6) + +/* Pass the frame up the stack with no modifications to skb->dev */ +#define RMNET_EPMODE_NONE (0) +/* Replace skb->dev to a virtual rmnet device and pass up the stack */ +#define RMNET_EPMODE_VND (1) +/* Pass the frame directly to another device with dev_queue_xmit() */ +#define RMNET_EPMODE_BRIDGE (2) + +#endif /* _RMNET_PRIVATE_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c new file mode 100644 index 000000000000..c8b573d28dcf --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -0,0 +1,170 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * RMNET Data virtual network driver + * + */ + +#include +#include +#include +#include "rmnet_config.h" +#include "rmnet_handlers.h" +#include "rmnet_private.h" +#include "rmnet_map.h" +#include "rmnet_vnd.h" + +/* RX/TX Fixup */ + +void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; +} + +void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; +} + +/* Network Device Operations */ + +static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct rmnet_priv *priv; + + priv = netdev_priv(dev); + if (priv->local_ep.egress_dev) { + rmnet_egress_handler(skb, &priv->local_ep); + } else { + dev->stats.tx_dropped++; + kfree_skb(skb); + } + return NETDEV_TX_OK; +} + +static int rmnet_vnd_change_mtu(struct net_device *rmnet_dev, int new_mtu) +{ + if (new_mtu < 0 || new_mtu > RMNET_MAX_PACKET_SIZE) + return -EINVAL; + + rmnet_dev->mtu = new_mtu; + return 0; +} + +static const struct net_device_ops rmnet_vnd_ops = { + .ndo_start_xmit = rmnet_vnd_start_xmit, + .ndo_change_mtu = rmnet_vnd_change_mtu, +}; + +/* Called by kernel whenever a new rmnet device is created. Sets MTU, + * flags, ARP type, needed headroom, etc... + */ +void rmnet_vnd_setup(struct net_device *rmnet_dev) +{ + struct rmnet_priv *priv; + + priv = netdev_priv(rmnet_dev); + netdev_dbg(rmnet_dev, "Setting up device %s\n", rmnet_dev->name); + + rmnet_dev->netdev_ops = &rmnet_vnd_ops; + rmnet_dev->mtu = RMNET_DFLT_PACKET_SIZE; + rmnet_dev->needed_headroom = RMNET_NEEDED_HEADROOM; + random_ether_addr(rmnet_dev->dev_addr); + rmnet_dev->tx_queue_len = RMNET_TX_QUEUE_LEN; + + /* Raw IP mode */ + rmnet_dev->header_ops = NULL; /* No header */ + rmnet_dev->type = ARPHRD_RAWIP; + rmnet_dev->hard_header_len = 0; + rmnet_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + + rmnet_dev->needs_free_netdev = true; +} + +/* Exposed API */ + +int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, + struct rmnet_real_dev_info *r) +{ + int rc; + + if (r->rmnet_devices[id]) + return -EINVAL; + + rc = register_netdevice(rmnet_dev); + if (!rc) { + r->rmnet_devices[id] = rmnet_dev; + r->nr_rmnet_devs++; + rmnet_dev->rtnl_link_ops = &rmnet_link_ops; + } + + return rc; +} + +int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r) +{ + if (id >= RMNET_MAX_VND || !r->rmnet_devices[id]) + return -EINVAL; + + r->rmnet_devices[id] = NULL; + r->nr_rmnet_devs--; + return 0; +} + +u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev) +{ + struct rmnet_priv *priv; + + priv = netdev_priv(rmnet_dev); + return priv->mux_id; +} + +void rmnet_vnd_set_mux(struct net_device *rmnet_dev, u8 mux_id) +{ + struct rmnet_priv *priv; + + priv = netdev_priv(rmnet_dev); + priv->mux_id = mux_id; +} + +/* Gets the logical endpoint configuration for a RmNet virtual network device + * node. Caller should confirm that devices is a RmNet VND before calling. + */ +struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *rmnet_dev) +{ + struct rmnet_priv *priv; + + if (!rmnet_dev) + return NULL; + + priv = netdev_priv(rmnet_dev); + + return &priv->local_ep; +} + +int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable) +{ + netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable); + /* Although we expect similar number of enable/disable + * commands, optimize for the disable. That is more + * latency sensitive than enable + */ + if (unlikely(enable)) + netif_wake_queue(rmnet_dev); + else + netif_stop_queue(rmnet_dev); + + return 0; +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h new file mode 100644 index 000000000000..b102b4269be1 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * RMNET Data Virtual Network Device APIs + * + */ + +#ifndef _RMNET_VND_H_ +#define _RMNET_VND_H_ + +int rmnet_vnd_do_flow_control(struct net_device *dev, int enable); +struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *dev); +int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, + struct rmnet_real_dev_info *r); +int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r); +void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev); +void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev); +u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev); +void rmnet_vnd_set_mux(struct net_device *rmnet_dev, u8 mux_id); +void rmnet_vnd_setup(struct net_device *dev); +#endif /* _RMNET_VND_H_ */ -- cgit From 5debc53ffecf79ca1c2d6fc194764cb6a8fa91a9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 31 Aug 2017 15:07:27 +0100 Subject: net: qualcomm: rmnet: remove unused variable priv priv is being assigned but is never used, so remove it. Cleans up clang build warning: "warning: Value stored to 'priv' is never read" Fixes: ceed73a2cf4a ("drivers: net: ethernet: qualcomm: rmnet: Initial implementation") Signed-off-by: Colin Ian King Acked-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index c8b573d28dcf..bf7455fdafcc 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -73,9 +73,6 @@ static const struct net_device_ops rmnet_vnd_ops = { */ void rmnet_vnd_setup(struct net_device *rmnet_dev) { - struct rmnet_priv *priv; - - priv = netdev_priv(rmnet_dev); netdev_dbg(rmnet_dev, "Setting up device %s\n", rmnet_dev->name); rmnet_dev->netdev_ops = &rmnet_vnd_ops; -- cgit From 009e1b2b7a302219562999f3b273bd4cbf4d9b40 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:41 -0600 Subject: net: qualcomm: rmnet: Fix memory corruption if mux_id is greater than 32 rmnet_rtnl_validate() was checking for upto mux_id 254, however the rmnet_devices devices could hold upto 32 entries only. Fix this by increasing the size of the rmnet_devices. Fixes: ceed73a2cf4a ("drivers: net: ethernet: qualcomm: rmnet: Initial implementation") Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Dan Williams Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 3 +-- drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h | 1 - drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 985d372e0d8d..40b6b32216b6 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -19,7 +19,6 @@ #define _RMNET_CONFIG_H_ #define RMNET_MAX_LOGICAL_EP 255 -#define RMNET_MAX_VND 32 /* Information about the next device to deliver the packet to. * Exact usage of this parameter depends on the rmnet_mode. @@ -39,7 +38,7 @@ struct rmnet_real_dev_info { struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP]; u32 ingress_data_format; u32 egress_data_format; - struct net_device *rmnet_devices[RMNET_MAX_VND]; + struct net_device *rmnet_devices[RMNET_MAX_LOGICAL_EP]; u8 nr_rmnet_devs; }; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h index ed820b5522f5..7967198fdd90 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h @@ -13,7 +13,6 @@ #ifndef _RMNET_PRIVATE_H_ #define _RMNET_PRIVATE_H_ -#define RMNET_MAX_VND 32 #define RMNET_MAX_PACKET_SIZE 16384 #define RMNET_DFLT_PACKET_SIZE 1500 #define RMNET_NEEDED_HEADROOM 16 diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index bf7455fdafcc..0e0001becb61 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -112,7 +112,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r) { - if (id >= RMNET_MAX_VND || !r->rmnet_devices[id]) + if (id >= RMNET_MAX_LOGICAL_EP || !r->rmnet_devices[id]) return -EINVAL; r->rmnet_devices[id] = NULL; -- cgit From 61bf5490ec47f61b522ecf24958c835aefa38812 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:42 -0600 Subject: net: qualcomm: rmnet: Remove the unused endpoint -1 This was used only in the original patch series where the IOCTLs were present and is no longer in use. Fixes: ceed73a2cf4a ("drivers: net: ethernet: qualcomm: rmnet: Initial implementation") Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Dan Williams Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index e836d267d5cc..3ca98ecda02b 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -42,7 +42,6 @@ */ /* Local Definitions and Declarations */ -#define RMNET_LOCAL_LOGICAL_ENDPOINT -1 struct rmnet_walk_data { struct net_device *real_dev; @@ -89,10 +88,7 @@ rmnet_get_endpoint(struct net_device *dev, int config_id) if (!r) return NULL; - if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) - ep = &r->local_ep; - else - ep = &r->muxed_ep[config_id]; + ep = &r->muxed_ep[config_id]; } return ep; @@ -182,10 +178,7 @@ static int __rmnet_set_endpoint_config(struct net_device *dev, int config_id, return -EINVAL; memcpy(dev_ep, ep, sizeof(struct rmnet_endpoint)); - if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) - dev_ep->mux_id = 0; - else - dev_ep->mux_id = config_id; + dev_ep->mux_id = config_id; return 0; } @@ -199,8 +192,7 @@ static int rmnet_set_endpoint_config(struct net_device *dev, netdev_dbg(dev, "id %d mode %d dev %s\n", config_id, rmnet_mode, egress_dev->name); - if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT || - config_id >= RMNET_MAX_LOGICAL_EP) + if (config_id >= RMNET_MAX_LOGICAL_EP) return -EINVAL; /* This config is cleared on every set, so its ok to not -- cgit From 2d516c0d904af52967bb974ee58aa74819d8d05f Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:43 -0600 Subject: net: qualcomm: rmnet: Move the device creation log The current log is not very useful as it does not log the device name since it it is prior to registration - (unnamed net_device) (uninitialized): Setting up device Modify to log after the device registration - rmnet1: rmnet dev created Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 0e0001becb61..7c7305208498 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -73,8 +73,6 @@ static const struct net_device_ops rmnet_vnd_ops = { */ void rmnet_vnd_setup(struct net_device *rmnet_dev) { - netdev_dbg(rmnet_dev, "Setting up device %s\n", rmnet_dev->name); - rmnet_dev->netdev_ops = &rmnet_vnd_ops; rmnet_dev->mtu = RMNET_DFLT_PACKET_SIZE; rmnet_dev->needed_headroom = RMNET_NEEDED_HEADROOM; @@ -105,6 +103,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, r->rmnet_devices[id] = rmnet_dev; r->nr_rmnet_devs++; rmnet_dev->rtnl_link_ops = &rmnet_link_ops; + netdev_dbg(rmnet_dev, "rmnet dev created\n"); } return rc; -- cgit From 032ee46828e7a2531c77bf80052fa1237820ec9c Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:44 -0600 Subject: net: qualcomm: rmnet: Refactor the new rmnet dev creation Data format can be directly set from rmnet_newlink() since the rmnet real dev info is already available. Since __rmnet_get_real_dev_info() is no longer used in rmnet_config.c after removal of those functions, move content to rmnet_get_real_dev_info(). __rmnet_set_endpoint_config() is collapsed into rmnet_set_endpoint_config() since only mux_id was being set additionally within it. Remove an unnecessary mux_id check. Set the mux_id for the rmnet_dev within rmnet_vnd_newlink() itself. Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Dan Williams Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 96 +++++----------------- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 13 ++- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 1 - 3 files changed, 26 insertions(+), 84 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 3ca98ecda02b..c0aed7cd0b88 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -57,16 +57,6 @@ static int rmnet_is_real_dev_registered(const struct net_device *real_dev) return (rx_handler == rmnet_rx_handler); } -/* Needs either rcu_read_lock() or rtnl lock */ -static struct rmnet_real_dev_info* -__rmnet_get_real_dev_info(const struct net_device *real_dev) -{ - if (rmnet_is_real_dev_registered(real_dev)) - return rcu_dereference_rtnl(real_dev->rx_handler_data); - else - return NULL; -} - /* Needs rtnl lock */ static struct rmnet_real_dev_info* rmnet_get_real_dev_info_rtnl(const struct net_device *real_dev) @@ -83,10 +73,7 @@ rmnet_get_endpoint(struct net_device *dev, int config_id) if (!rmnet_is_real_dev_registered(dev)) { ep = rmnet_vnd_get_endpoint(dev); } else { - r = __rmnet_get_real_dev_info(dev); - - if (!r) - return NULL; + r = rmnet_get_real_dev_info_rtnl(dev); ep = &r->muxed_ep[config_id]; } @@ -139,70 +126,23 @@ static int rmnet_register_real_device(struct net_device *real_dev) return 0; } -static int rmnet_set_ingress_data_format(struct net_device *dev, u32 idf) -{ - struct rmnet_real_dev_info *r; - - netdev_dbg(dev, "Ingress format 0x%08X\n", idf); - - r = __rmnet_get_real_dev_info(dev); - - r->ingress_data_format = idf; - - return 0; -} - -static int rmnet_set_egress_data_format(struct net_device *dev, u32 edf, - u16 agg_size, u16 agg_count) +static void rmnet_set_endpoint_config(struct net_device *dev, + u8 mux_id, u8 rmnet_mode, + struct net_device *egress_dev) { - struct rmnet_real_dev_info *r; - - netdev_dbg(dev, "Egress format 0x%08X agg size %d cnt %d\n", - edf, agg_size, agg_count); - - r = __rmnet_get_real_dev_info(dev); - - r->egress_data_format = edf; - - return 0; -} - -static int __rmnet_set_endpoint_config(struct net_device *dev, int config_id, - struct rmnet_endpoint *ep) -{ - struct rmnet_endpoint *dev_ep; - - dev_ep = rmnet_get_endpoint(dev, config_id); - - if (!dev_ep) - return -EINVAL; - - memcpy(dev_ep, ep, sizeof(struct rmnet_endpoint)); - dev_ep->mux_id = config_id; - - return 0; -} - -static int rmnet_set_endpoint_config(struct net_device *dev, - int config_id, u8 rmnet_mode, - struct net_device *egress_dev) -{ - struct rmnet_endpoint ep; + struct rmnet_endpoint *ep; netdev_dbg(dev, "id %d mode %d dev %s\n", - config_id, rmnet_mode, egress_dev->name); - - if (config_id >= RMNET_MAX_LOGICAL_EP) - return -EINVAL; + mux_id, rmnet_mode, egress_dev->name); + ep = rmnet_get_endpoint(dev, mux_id); /* This config is cleared on every set, so its ok to not * clear it on a device delete. */ - memset(&ep, 0, sizeof(struct rmnet_endpoint)); - ep.rmnet_mode = rmnet_mode; - ep.egress_dev = egress_dev; - - return __rmnet_set_endpoint_config(dev, config_id, &ep); + memset(ep, 0, sizeof(struct rmnet_endpoint)); + ep->rmnet_mode = rmnet_mode; + ep->egress_dev = egress_dev; + ep->mux_id = mux_id; } static int rmnet_newlink(struct net *src_net, struct net_device *dev, @@ -242,9 +182,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, if (err) goto err2; - rmnet_vnd_set_mux(dev, mux_id); - rmnet_set_egress_data_format(real_dev, egress_format, 0, 0); - rmnet_set_ingress_data_format(real_dev, ingress_format); + netdev_dbg(dev, "data format [ingress 0x%08X] [egress 0x%08X]\n", + ingress_format, egress_format); + r->egress_data_format = egress_format; + r->ingress_data_format = ingress_format; + rmnet_set_endpoint_config(real_dev, mux_id, mode, dev); rmnet_set_endpoint_config(dev, mux_id, mode, real_dev); return 0; @@ -376,10 +318,14 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = { .get_size = rmnet_get_size, }; +/* Needs either rcu_read_lock() or rtnl lock */ struct rmnet_real_dev_info* rmnet_get_real_dev_info(struct net_device *real_dev) { - return __rmnet_get_real_dev_info(real_dev); + if (rmnet_is_real_dev_registered(real_dev)) + return rcu_dereference_rtnl(real_dev->rx_handler_data); + else + return NULL; } /* Startup/Shutdown */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 7c7305208498..a6de0419d68b 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -93,6 +93,7 @@ void rmnet_vnd_setup(struct net_device *rmnet_dev) int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, struct rmnet_real_dev_info *r) { + struct rmnet_priv *priv; int rc; if (r->rmnet_devices[id]) @@ -103,6 +104,10 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, r->rmnet_devices[id] = rmnet_dev; r->nr_rmnet_devs++; rmnet_dev->rtnl_link_ops = &rmnet_link_ops; + + priv = netdev_priv(rmnet_dev); + priv->mux_id = id; + netdev_dbg(rmnet_dev, "rmnet dev created\n"); } @@ -127,14 +132,6 @@ u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev) return priv->mux_id; } -void rmnet_vnd_set_mux(struct net_device *rmnet_dev, u8 mux_id) -{ - struct rmnet_priv *priv; - - priv = netdev_priv(rmnet_dev); - priv->mux_id = mux_id; -} - /* Gets the logical endpoint configuration for a RmNet virtual network device * node. Caller should confirm that devices is a RmNet VND before calling. */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h index b102b4269be1..4823f38bc563 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h @@ -24,6 +24,5 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r); void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev); void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev); u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev); -void rmnet_vnd_set_mux(struct net_device *rmnet_dev, u8 mux_id); void rmnet_vnd_setup(struct net_device *dev); #endif /* _RMNET_VND_H_ */ -- cgit From b752eff5be24ec146393944848d2ffbef92b43a7 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:45 -0600 Subject: net: qualcomm: rmnet: Implement ndo_get_iflink This makes it easier to find out the parent dev. Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Dan Williams Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 2 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 + drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 12 +++++++++++- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 3 ++- 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index c0aed7cd0b88..6f21cd018a79 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -174,7 +174,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, goto err0; r = rmnet_get_real_dev_info_rtnl(real_dev); - err = rmnet_vnd_newlink(mux_id, dev, r); + err = rmnet_vnd_newlink(mux_id, dev, r, real_dev); if (err) goto err1; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 40b6b32216b6..3212b25ad2bc 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -47,6 +47,7 @@ extern struct rtnl_link_ops rmnet_link_ops; struct rmnet_priv { struct rmnet_endpoint local_ep; u8 mux_id; + struct net_device *real_dev; }; struct rmnet_real_dev_info* diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index a6de0419d68b..f5c63b78338b 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -63,9 +63,17 @@ static int rmnet_vnd_change_mtu(struct net_device *rmnet_dev, int new_mtu) return 0; } +static int rmnet_vnd_get_iflink(const struct net_device *dev) +{ + struct rmnet_priv *priv = netdev_priv(dev); + + return priv->real_dev->ifindex; +} + static const struct net_device_ops rmnet_vnd_ops = { .ndo_start_xmit = rmnet_vnd_start_xmit, .ndo_change_mtu = rmnet_vnd_change_mtu, + .ndo_get_iflink = rmnet_vnd_get_iflink, }; /* Called by kernel whenever a new rmnet device is created. Sets MTU, @@ -91,7 +99,8 @@ void rmnet_vnd_setup(struct net_device *rmnet_dev) /* Exposed API */ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, - struct rmnet_real_dev_info *r) + struct rmnet_real_dev_info *r, + struct net_device *real_dev) { struct rmnet_priv *priv; int rc; @@ -107,6 +116,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, priv = netdev_priv(rmnet_dev); priv->mux_id = id; + priv->real_dev = real_dev; netdev_dbg(rmnet_dev, "rmnet dev created\n"); } diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h index 4823f38bc563..9084e447eba8 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h @@ -19,7 +19,8 @@ int rmnet_vnd_do_flow_control(struct net_device *dev, int enable); struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *dev); int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, - struct rmnet_real_dev_info *r); + struct rmnet_real_dev_info *r, + struct net_device *real_dev); int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r); void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev); void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev); -- cgit From b665f4f82d31c17926df3ac7c4a59bbff7af463b Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Sat, 2 Sep 2017 23:30:46 -0600 Subject: net: qualcomm: rmnet: Rename real_dev_info to port Make it similar to drivers like ipvlan / macvlan so it is easier to read. Signed-off-by: Subash Abhinov Kasiviswanathan Cc: Dan Williams Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 65 +++++++++++----------- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 5 +- .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 56 +++++++++---------- drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 6 +- .../ethernet/qualcomm/rmnet/rmnet_map_command.c | 13 ++--- .../net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 3 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 17 +++--- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 4 +- 8 files changed, 82 insertions(+), 87 deletions(-) (limited to 'drivers/net/ethernet/qualcomm/rmnet') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 6f21cd018a79..98f22551eb45 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -46,7 +46,7 @@ struct rmnet_walk_data { struct net_device *real_dev; struct list_head *head; - struct rmnet_real_dev_info *real_dev_info; + struct rmnet_port *port; }; static int rmnet_is_real_dev_registered(const struct net_device *real_dev) @@ -58,8 +58,8 @@ static int rmnet_is_real_dev_registered(const struct net_device *real_dev) } /* Needs rtnl lock */ -static struct rmnet_real_dev_info* -rmnet_get_real_dev_info_rtnl(const struct net_device *real_dev) +static struct rmnet_port* +rmnet_get_port_rtnl(const struct net_device *real_dev) { return rtnl_dereference(real_dev->rx_handler_data); } @@ -67,27 +67,27 @@ rmnet_get_real_dev_info_rtnl(const struct net_device *real_dev) static struct rmnet_endpoint* rmnet_get_endpoint(struct net_device *dev, int config_id) { - struct rmnet_real_dev_info *r; struct rmnet_endpoint *ep; + struct rmnet_port *port; if (!rmnet_is_real_dev_registered(dev)) { ep = rmnet_vnd_get_endpoint(dev); } else { - r = rmnet_get_real_dev_info_rtnl(dev); + port = rmnet_get_port_rtnl(dev); - ep = &r->muxed_ep[config_id]; + ep = &port->muxed_ep[config_id]; } return ep; } static int rmnet_unregister_real_device(struct net_device *real_dev, - struct rmnet_real_dev_info *r) + struct rmnet_port *port) { - if (r->nr_rmnet_devs) + if (port->nr_rmnet_devs) return -EINVAL; - kfree(r); + kfree(port); netdev_rx_handler_unregister(real_dev); @@ -100,7 +100,7 @@ static int rmnet_unregister_real_device(struct net_device *real_dev, static int rmnet_register_real_device(struct net_device *real_dev) { - struct rmnet_real_dev_info *r; + struct rmnet_port *port; int rc; ASSERT_RTNL(); @@ -108,14 +108,14 @@ static int rmnet_register_real_device(struct net_device *real_dev) if (rmnet_is_real_dev_registered(real_dev)) return 0; - r = kzalloc(sizeof(*r), GFP_ATOMIC); - if (!r) + port = kzalloc(sizeof(*port), GFP_ATOMIC); + if (!port) return -ENOMEM; - r->dev = real_dev; - rc = netdev_rx_handler_register(real_dev, rmnet_rx_handler, r); + port->dev = real_dev; + rc = netdev_rx_handler_register(real_dev, rmnet_rx_handler, port); if (rc) { - kfree(r); + kfree(port); return -EBUSY; } @@ -154,9 +154,9 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, RMNET_INGRESS_FORMAT_MAP; int egress_format = RMNET_EGRESS_FORMAT_MUXING | RMNET_EGRESS_FORMAT_MAP; - struct rmnet_real_dev_info *r; struct net_device *real_dev; int mode = RMNET_EPMODE_VND; + struct rmnet_port *port; int err = 0; u16 mux_id; @@ -173,8 +173,8 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, if (err) goto err0; - r = rmnet_get_real_dev_info_rtnl(real_dev); - err = rmnet_vnd_newlink(mux_id, dev, r, real_dev); + port = rmnet_get_port_rtnl(real_dev); + err = rmnet_vnd_newlink(mux_id, dev, port, real_dev); if (err) goto err1; @@ -184,25 +184,25 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, netdev_dbg(dev, "data format [ingress 0x%08X] [egress 0x%08X]\n", ingress_format, egress_format); - r->egress_data_format = egress_format; - r->ingress_data_format = ingress_format; + port->egress_data_format = egress_format; + port->ingress_data_format = ingress_format; rmnet_set_endpoint_config(real_dev, mux_id, mode, dev); rmnet_set_endpoint_config(dev, mux_id, mode, real_dev); return 0; err2: - rmnet_vnd_dellink(mux_id, r); + rmnet_vnd_dellink(mux_id, port); err1: - rmnet_unregister_real_device(real_dev, r); + rmnet_unregister_real_device(real_dev, port); err0: return err; } static void rmnet_dellink(struct net_device *dev, struct list_head *head) { - struct rmnet_real_dev_info *r; struct net_device *real_dev; + struct rmnet_port *port; u8 mux_id; rcu_read_lock(); @@ -212,12 +212,12 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head) if (!real_dev || !rmnet_is_real_dev_registered(real_dev)) return; - r = rmnet_get_real_dev_info_rtnl(real_dev); + port = rmnet_get_port_rtnl(real_dev); mux_id = rmnet_vnd_get_mux(dev); - rmnet_vnd_dellink(mux_id, r); + rmnet_vnd_dellink(mux_id, port); netdev_upper_dev_unlink(dev, real_dev); - rmnet_unregister_real_device(real_dev, r); + rmnet_unregister_real_device(real_dev, port); unregister_netdevice_queue(dev, head); } @@ -229,7 +229,7 @@ static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data) mux_id = rmnet_vnd_get_mux(rmnet_dev); - rmnet_vnd_dellink(mux_id, d->real_dev_info); + rmnet_vnd_dellink(mux_id, d->port); netdev_upper_dev_unlink(rmnet_dev, d->real_dev); unregister_netdevice_queue(rmnet_dev, d->head); @@ -239,8 +239,8 @@ static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data) static void rmnet_force_unassociate_device(struct net_device *dev) { struct net_device *real_dev = dev; - struct rmnet_real_dev_info *r; struct rmnet_walk_data d; + struct rmnet_port *port; LIST_HEAD(list); if (!rmnet_is_real_dev_registered(real_dev)) @@ -251,15 +251,15 @@ static void rmnet_force_unassociate_device(struct net_device *dev) d.real_dev = real_dev; d.head = &list; - r = rmnet_get_real_dev_info_rtnl(dev); - d.real_dev_info = r; + port = rmnet_get_port_rtnl(dev); + d.port = port; rcu_read_lock(); netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d); rcu_read_unlock(); unregister_netdevice_many(&list); - rmnet_unregister_real_device(real_dev, r); + rmnet_unregister_real_device(real_dev, port); } static int rmnet_config_notify_cb(struct notifier_block *nb, @@ -319,8 +319,7 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = { }; /* Needs either rcu_read_lock() or rtnl lock */ -struct rmnet_real_dev_info* -rmnet_get_real_dev_info(struct net_device *real_dev) +struct rmnet_port *rmnet_get_port(struct net_device *real_dev) { if (rmnet_is_real_dev_registered(real_dev)) return rcu_dereference_rtnl(real_dev->rx_handler_data); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 3212b25ad2bc..dde4e9f14f4a 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -32,7 +32,7 @@ struct rmnet_endpoint { /* One instance of this structure is instantiated for each real_dev associated * with rmnet. */ -struct rmnet_real_dev_info { +struct rmnet_port { struct net_device *dev; struct rmnet_endpoint local_ep; struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP]; @@ -50,7 +50,6 @@ struct rmnet_priv { struct net_device *real_dev; }; -struct rmnet_real_dev_info* -rmnet_get_real_dev_info(struct net_device *real_dev); +struct rmnet_port *rmnet_get_port(struct net_device *real_dev); #endif /* _RMNET_CONFIG_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 7dab3bbfeda5..540c7622dcb1 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -82,32 +82,32 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_endpoint *ep) static rx_handler_result_t rmnet_ingress_deliver_packet(struct sk_buff *skb, - struct rmnet_real_dev_info *r) + struct rmnet_port *port) { - if (!r) { + if (!port) { kfree_skb(skb); return RX_HANDLER_CONSUMED; } - skb->dev = r->local_ep.egress_dev; + skb->dev = port->local_ep.egress_dev; - return rmnet_deliver_skb(skb, &r->local_ep); + return rmnet_deliver_skb(skb, &port->local_ep); } /* MAP handler */ static rx_handler_result_t __rmnet_map_ingress_handler(struct sk_buff *skb, - struct rmnet_real_dev_info *r) + struct rmnet_port *port) { struct rmnet_endpoint *ep; u8 mux_id; u16 len; if (RMNET_MAP_GET_CD_BIT(skb)) { - if (r->ingress_data_format + if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_COMMANDS) - return rmnet_map_command(skb, r); + return rmnet_map_command(skb, port); kfree_skb(skb); return RX_HANDLER_CONSUMED; @@ -121,9 +121,9 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, return RX_HANDLER_CONSUMED; } - ep = &r->muxed_ep[mux_id]; + ep = &port->muxed_ep[mux_id]; - if (r->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING) + if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING) skb->dev = ep->egress_dev; /* Subtract MAP header */ @@ -135,26 +135,26 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, static rx_handler_result_t rmnet_map_ingress_handler(struct sk_buff *skb, - struct rmnet_real_dev_info *r) + struct rmnet_port *port) { struct sk_buff *skbn; int rc; - if (r->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { - while ((skbn = rmnet_map_deaggregate(skb, r)) != NULL) - __rmnet_map_ingress_handler(skbn, r); + if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { + while ((skbn = rmnet_map_deaggregate(skb)) != NULL) + __rmnet_map_ingress_handler(skbn, port); consume_skb(skb); rc = RX_HANDLER_CONSUMED; } else { - rc = __rmnet_map_ingress_handler(skb, r); + rc = __rmnet_map_ingress_handler(skb, port); } return rc; } static int rmnet_map_egress_handler(struct sk_buff *skb, - struct rmnet_real_dev_info *r, + struct rmnet_port *port, struct rmnet_endpoint *ep, struct net_device *orig_dev) { @@ -173,7 +173,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, if (!map_header) return RMNET_MAP_CONSUMED; - if (r->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) { + if (port->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) { if (ep->mux_id == 0xff) map_header->mux_id = 0; else @@ -193,7 +193,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, */ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) { - struct rmnet_real_dev_info *r; + struct rmnet_port *port; struct sk_buff *skb = *pskb; struct net_device *dev; int rc; @@ -202,16 +202,16 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) return RX_HANDLER_CONSUMED; dev = skb->dev; - r = rmnet_get_real_dev_info(dev); + port = rmnet_get_port(dev); - if (r->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) { - rc = rmnet_map_ingress_handler(skb, r); + if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) { + rc = rmnet_map_ingress_handler(skb, port); } else { switch (ntohs(skb->protocol)) { case ETH_P_MAP: - if (r->local_ep.rmnet_mode == + if (port->local_ep.rmnet_mode == RMNET_EPMODE_BRIDGE) { - rc = rmnet_ingress_deliver_packet(skb, r); + rc = rmnet_ingress_deliver_packet(skb, port); } else { kfree_skb(skb); rc = RX_HANDLER_CONSUMED; @@ -220,7 +220,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) case ETH_P_IP: case ETH_P_IPV6: - rc = rmnet_ingress_deliver_packet(skb, r); + rc = rmnet_ingress_deliver_packet(skb, port); break; default: @@ -238,20 +238,20 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb) void rmnet_egress_handler(struct sk_buff *skb, struct rmnet_endpoint *ep) { - struct rmnet_real_dev_info *r; struct net_device *orig_dev; + struct rmnet_port *port; orig_dev = skb->dev; skb->dev = ep->egress_dev; - r = rmnet_get_real_dev_info(skb->dev); - if (!r) { + port = rmnet_get_port(skb->dev); + if (!port) { kfree_skb(skb); return; } - if (r->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { - switch (rmnet_map_egress_handler(skb, r, ep, orig_dev)) { + if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { + switch (rmnet_map_egress_handler(skb, port, ep, orig_dev)) { case RMNET_MAP_CONSUMED: return; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index 2aabad289b10..ce2302c25b12 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -77,12 +77,10 @@ struct rmnet_map_header { #define RMNET_MAP_ADD_PAD_BYTES 1 u8 rmnet_map_demultiplex(struct sk_buff *skb); -struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, - struct rmnet_real_dev_info *rdinfo); - +struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb); struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb, int hdrlen, int pad); rx_handler_result_t rmnet_map_command(struct sk_buff *skb, - struct rmnet_real_dev_info *rdinfo); + struct rmnet_port *port); #endif /* _RMNET_MAP_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index ccded40ee551..d1ea5e21b982 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -17,7 +17,7 @@ #include "rmnet_vnd.h" static u8 rmnet_map_do_flow_control(struct sk_buff *skb, - struct rmnet_real_dev_info *rdinfo, + struct rmnet_port *rdinfo, int enable) { struct rmnet_map_control_command *cmd; @@ -58,8 +58,7 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb, } static void rmnet_map_send_ack(struct sk_buff *skb, - unsigned char type, - struct rmnet_real_dev_info *rdinfo) + unsigned char type) { struct rmnet_map_control_command *cmd; int xmit_status; @@ -78,7 +77,7 @@ static void rmnet_map_send_ack(struct sk_buff *skb, * name is decoded here and appropriate handler is called. */ rx_handler_result_t rmnet_map_command(struct sk_buff *skb, - struct rmnet_real_dev_info *rdinfo) + struct rmnet_port *port) { struct rmnet_map_control_command *cmd; unsigned char command_name; @@ -89,11 +88,11 @@ rx_handler_result_t rmnet_map_command(struct sk_buff *skb, switch (command_name) { case RMNET_MAP_COMMAND_FLOW_ENABLE: - rc = rmnet_map_do_flow_control(skb, rdinfo, 1); + rc = rmnet_map_do_flow_control(skb, port, 1); break; case RMNET_MAP_COMMAND_FLOW_DISABLE: - rc = rmnet_map_do_flow_control(skb, rdinfo, 0); + rc = rmnet_map_do_flow_control(skb, port, 0); break; default: @@ -102,6 +101,6 @@ rx_handler_result_t rmnet_map_command(struct sk_buff *skb, break; } if (rc == RMNET_MAP_COMMAND_ACK) - rmnet_map_send_ack(skb, rc, rdinfo); + rmnet_map_send_ack(skb, rc); return RX_HANDLER_CONSUMED; } diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index a29c476a4755..557c9bf1a469 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -69,8 +69,7 @@ done: * returned, indicating that there are no more packets to deaggregate. Caller * is responsible for freeing the original skb. */ -struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, - struct rmnet_real_dev_info *rdinfo) +struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb) { struct rmnet_map_header *maph; struct sk_buff *skbn; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index f5c63b78338b..7f90d5587653 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -99,19 +99,20 @@ void rmnet_vnd_setup(struct net_device *rmnet_dev) /* Exposed API */ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, - struct rmnet_real_dev_info *r, + struct rmnet_port *port, struct net_device *real_dev) { struct rmnet_priv *priv; int rc; - if (r->rmnet_devices[id]) + if (port->rmnet_devices[id]) return -EINVAL; rc = register_netdevice(rmnet_dev); if (!rc) { - r->rmnet_devices[id] = rmnet_dev; - r->nr_rmnet_devs++; + port->rmnet_devices[id] = rmnet_dev; + port->nr_rmnet_devs++; + rmnet_dev->rtnl_link_ops = &rmnet_link_ops; priv = netdev_priv(rmnet_dev); @@ -124,13 +125,13 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, return rc; } -int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r) +int rmnet_vnd_dellink(u8 id, struct rmnet_port *port) { - if (id >= RMNET_MAX_LOGICAL_EP || !r->rmnet_devices[id]) + if (id >= RMNET_MAX_LOGICAL_EP || !port->rmnet_devices[id]) return -EINVAL; - r->rmnet_devices[id] = NULL; - r->nr_rmnet_devs--; + port->rmnet_devices[id] = NULL; + port->nr_rmnet_devs--; return 0; } diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h index 9084e447eba8..8a4042f0f6bf 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h @@ -19,9 +19,9 @@ int rmnet_vnd_do_flow_control(struct net_device *dev, int enable); struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *dev); int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, - struct rmnet_real_dev_info *r, + struct rmnet_port *port, struct net_device *real_dev); -int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r); +int rmnet_vnd_dellink(u8 id, struct rmnet_port *port); void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev); void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev); u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev); -- cgit