Skip to content

Commit

Permalink
net: qmi_wwan: Add pass through mode
Browse files Browse the repository at this point in the history
Pass through mode is to allow packets in MAP format to be passed
on to the stack. rmnet driver can be used to process and demultiplex
these packets.

Pass through mode can be enabled when the device is in raw ip mode only.
Conversely, raw ip mode cannot be disabled when pass through mode is
enabled.

Userspace can use pass through mode in conjunction with rmnet driver
through the following steps-

1. Enable raw ip mode on qmi_wwan device
2. Enable pass through mode on qmi_wwan device
3. Create a rmnet device with qmi_wwan device as real device using netlink

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Acked-by: Bjørn Mork <bjorn@mork.no>
Link: https://lore.kernel.org/r/1611560015-20034-1-git-send-email-subashab@codeaurora.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Subash Abhinov Kasiviswanathan authored and Jakub Kicinski committed Jan 29, 2021
1 parent bbe25b7 commit 59e139c
Showing 1 changed file with 58 additions and 0 deletions.
58 changes: 58 additions & 0 deletions drivers/net/usb/qmi_wwan.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct qmi_wwan_state {
enum qmi_wwan_flags {
QMI_WWAN_FLAG_RAWIP = 1 << 0,
QMI_WWAN_FLAG_MUX = 1 << 1,
QMI_WWAN_FLAG_PASS_THROUGH = 1 << 2,
};

enum qmi_wwan_quirks {
Expand Down Expand Up @@ -350,6 +351,13 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co
if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP))
return len;

/* ip mode cannot be cleared when pass through mode is set */
if (!enable && (info->flags & QMI_WWAN_FLAG_PASS_THROUGH)) {
netdev_err(dev->net,
"Cannot clear ip mode on pass through device\n");
return -EINVAL;
}

if (!rtnl_trylock())
return restart_syscall();

Expand Down Expand Up @@ -480,14 +488,59 @@ static ssize_t del_mux_store(struct device *d, struct device_attribute *attr, c
return ret;
}

static ssize_t pass_through_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct qmi_wwan_state *info;

info = (void *)&dev->data;
return sprintf(buf, "%c\n",
info->flags & QMI_WWAN_FLAG_PASS_THROUGH ? 'Y' : 'N');
}

static ssize_t pass_through_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct qmi_wwan_state *info;
bool enable;

if (strtobool(buf, &enable))
return -EINVAL;

info = (void *)&dev->data;

/* no change? */
if (enable == (info->flags & QMI_WWAN_FLAG_PASS_THROUGH))
return len;

/* pass through mode can be set for raw ip devices only */
if (!(info->flags & QMI_WWAN_FLAG_RAWIP)) {
netdev_err(dev->net,
"Cannot set pass through mode on non ip device\n");
return -EINVAL;
}

if (enable)
info->flags |= QMI_WWAN_FLAG_PASS_THROUGH;
else
info->flags &= ~QMI_WWAN_FLAG_PASS_THROUGH;

return len;
}

static DEVICE_ATTR_RW(raw_ip);
static DEVICE_ATTR_RW(add_mux);
static DEVICE_ATTR_RW(del_mux);
static DEVICE_ATTR_RW(pass_through);

static struct attribute *qmi_wwan_sysfs_attrs[] = {
&dev_attr_raw_ip.attr,
&dev_attr_add_mux.attr,
&dev_attr_del_mux.attr,
&dev_attr_pass_through.attr,
NULL,
};

Expand Down Expand Up @@ -534,6 +587,11 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (info->flags & QMI_WWAN_FLAG_MUX)
return qmimux_rx_fixup(dev, skb);

if (info->flags & QMI_WWAN_FLAG_PASS_THROUGH) {
skb->protocol = htons(ETH_P_MAP);
return (netif_rx(skb) == NET_RX_SUCCESS);
}

switch (skb->data[0] & 0xf0) {
case 0x40:
proto = htons(ETH_P_IP);
Expand Down

0 comments on commit 59e139c

Please sign in to comment.