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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1e75701175
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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,8 +186,7 @@ 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);
|
||||
rmnet_map_ingress_handler(skb, port);
|
||||
break;
|
||||
case RMNET_EPMODE_BRIDGE:
|
||||
rmnet_bridge_handler(skb, port->bridge_ep);
|
||||
|
@ -212,19 +219,8 @@ 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:
|
||||
return;
|
||||
|
||||
case RMNET_MAP_SUCCESS:
|
||||
break;
|
||||
|
||||
default:
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
|
||||
return;
|
||||
|
||||
rmnet_vnd_tx_fixup(skb, orig_dev);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -185,6 +185,9 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
|
|||
if (ep->egress_dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (rmnet_get_endpoint(port, id))
|
||||
return -EBUSY;
|
||||
|
||||
rc = register_netdevice(rmnet_dev);
|
||||
if (!rc) {
|
||||
ep->egress_dev = rmnet_dev;
|
||||
|
|
Loading…
Reference in New Issue