Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e757011 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'rmnet-Configuration-options'



Subash Abhinov Kasiviswanathan says:

====================
net: qualcomm: rmnet: Configuration options

This series adds support for configuring features on rmnet devices.
The rmnet specific features to be configured here are aggregation and
control commands.

Patch 1 is a cleanup of return codes in the transmit path.
Patch 2 removes some redundant ingress and egress macros.
Patch 3 restricts the creation of rmnet dev to one dev per mux id for a
given real dev.
Patch 4 adds ethernet data path support.
Patches 5-6 add support for configuring features on new and existing
rmnet devices.

v1->v2:
The memory leak fixed as part of patch 1 is merged seperately as
a896d94abd2c ("net: qualcomm: rmnet: Fix leak on transmit failure").
Fix a use after free in patch 4 if a packet with headroom lesser than ethernet
header length is received.

v2->v3:
Fix formatting problem in patch 5 in the return statement.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b4f70c3d 23790ef1
Loading
Loading
Loading
Loading
+54 −10
Original line number Diff line number Diff line
@@ -143,11 +143,7 @@ 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;
	int ingress_format = RMNET_INGRESS_FORMAT_DEAGGREGATION;
	struct net_device *real_dev;
	int mode = RMNET_EPMODE_VND;
	struct rmnet_endpoint *ep;
@@ -181,13 +177,20 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
	if (err)
		goto err2;

	netdev_dbg(dev, "data format [ingress 0x%08X] [egress 0x%08X]\n",
		   ingress_format, egress_format);
	port->egress_data_format = egress_format;
	port->ingress_data_format = ingress_format;
	port->rmnet_mode = mode;

	hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);

	if (data[IFLA_VLAN_FLAGS]) {
		struct ifla_vlan_flags *flags;

		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		ingress_format = flags->flags & flags->mask;
	}

	netdev_dbg(dev, "data format [ingress 0x%08X]\n", ingress_format);
	port->ingress_data_format = ingress_format;

	return 0;

err2:
@@ -317,9 +320,49 @@ static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
	return 0;
}

static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
			    struct nlattr *data[],
			    struct netlink_ext_ack *extack)
{
	struct rmnet_priv *priv = netdev_priv(dev);
	struct net_device *real_dev;
	struct rmnet_endpoint *ep;
	struct rmnet_port *port;
	u16 mux_id;

	real_dev = __dev_get_by_index(dev_net(dev),
				      nla_get_u32(tb[IFLA_LINK]));

	if (!real_dev || !dev || !rmnet_is_real_dev_registered(real_dev))
		return -ENODEV;

	port = rmnet_get_port_rtnl(real_dev);

	if (data[IFLA_VLAN_ID]) {
		mux_id = nla_get_u16(data[IFLA_VLAN_ID]);
		ep = rmnet_get_endpoint(port, priv->mux_id);

		hlist_del_init_rcu(&ep->hlnode);
		hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);

		ep->mux_id = mux_id;
		priv->mux_id = mux_id;
	}

	if (data[IFLA_VLAN_FLAGS]) {
		struct ifla_vlan_flags *flags;

		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		port->ingress_data_format = flags->flags & flags->mask;
	}

	return 0;
}

static size_t rmnet_get_size(const struct net_device *dev)
{
	return nla_total_size(2); /* IFLA_VLAN_ID */
	return nla_total_size(2) /* IFLA_VLAN_ID */ +
	       nla_total_size(sizeof(struct ifla_vlan_flags)); /* IFLA_VLAN_FLAGS */
}

struct rtnl_link_ops rmnet_link_ops __read_mostly = {
@@ -331,6 +374,7 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = {
	.newlink	= rmnet_newlink,
	.dellink	= rmnet_dellink,
	.get_size	= rmnet_get_size,
	.changelink     = rmnet_changelink,
};

/* Needs either rcu_read_lock() or rtnl lock */
+0 −1
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ struct rmnet_endpoint {
struct rmnet_port {
	struct net_device *dev;
	u32 ingress_data_format;
	u32 egress_data_format;
	u8 nr_rmnet_devs;
	u8 rmnet_mode;
	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
+19 −23
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

#include <linux/netdevice.h>
#include <linux/netdev_features.h>
#include <linux/if_arp.h>
#include "rmnet_private.h"
#include "rmnet_config.h"
#include "rmnet_vnd.h"
@@ -104,6 +105,15 @@ rmnet_map_ingress_handler(struct sk_buff *skb,
{
	struct sk_buff *skbn;

	if (skb->dev->type == ARPHRD_ETHER) {
		if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_KERNEL)) {
			kfree_skb(skb);
			return;
		}

		skb_push(skb, ETH_HLEN);
	}

	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
		while ((skbn = rmnet_map_deaggregate(skb)) != NULL)
			__rmnet_map_ingress_handler(skbn, port);
@@ -133,20 +143,18 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
	if (!map_header)
		goto fail;

	if (port->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) {
	if (mux_id == 0xff)
		map_header->mux_id = 0;
	else
		map_header->mux_id = mux_id;
	}

	skb->protocol = htons(ETH_P_MAP);

	return RMNET_MAP_SUCCESS;
	return 0;

fail:
	kfree_skb(skb);
	return RMNET_MAP_CONSUMED;
	return -ENOMEM;
}

static void
@@ -178,7 +186,6 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)

	switch (port->rmnet_mode) {
	case RMNET_EPMODE_VND:
		if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP)
		rmnet_map_ingress_handler(skb, port);
		break;
	case RMNET_EPMODE_BRIDGE:
@@ -212,20 +219,9 @@ void rmnet_egress_handler(struct sk_buff *skb)
		return;
	}

	if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
		switch (rmnet_map_egress_handler(skb, port, mux_id, orig_dev)) {
		case RMNET_MAP_CONSUMED:
	if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
		return;

		case RMNET_MAP_SUCCESS:
			break;

		default:
			kfree_skb(skb);
			return;
		}
	}

	rmnet_vnd_tx_fixup(skb, orig_dev);

	dev_queue_xmit(skb);
+0 −9
Original line number Diff line number Diff line
@@ -30,15 +30,6 @@ struct rmnet_map_control_command {
	};
}  __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,
+2 −8
Original line number Diff line number Diff line
@@ -19,14 +19,8 @@
#define RMNET_TX_QUEUE_LEN         1000

/* Constants */
#define RMNET_EGRESS_FORMAT_MAP                 BIT(1)
#define RMNET_EGRESS_FORMAT_AGGREGATION         BIT(2)
#define RMNET_EGRESS_FORMAT_MUXING              BIT(3)

#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_DEAGGREGATION      BIT(0)
#define RMNET_INGRESS_FORMAT_MAP_COMMANDS       BIT(1)

/* Replace skb->dev to a virtual rmnet device and pass up the stack */
#define RMNET_EPMODE_VND (1)
Loading