Commit 6b5eeb7f authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller

net: cdc_mbim: handle unaccelerated VLAN tagged frames

This driver maps 802.1q VLANs to MBIM sessions. The mapping is based on
a bogus assumption that all tagged frames will use the acceleration API
because we enable NETIF_F_HW_VLAN_CTAG_TX. This fails for e.g. frames
tagged in userspace using packet sockets. Such frames will erroneously
be considered as untagged and silently dropped based on not being IP.

Fix by falling back to looking into the ethernet header for a tag if no
accelerated tag was found.

Fixes: a82c7ce5 ("net: cdc_ncm: map MBIM IPS SessionID to VLAN ID")
Cc: Greg Suarez <gsuarez@smithmicro.com>
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b3d40566
...@@ -120,6 +120,16 @@ static void cdc_mbim_unbind(struct usbnet *dev, struct usb_interface *intf) ...@@ -120,6 +120,16 @@ static void cdc_mbim_unbind(struct usbnet *dev, struct usb_interface *intf)
cdc_ncm_unbind(dev, intf); cdc_ncm_unbind(dev, intf);
} }
/* verify that the ethernet protocol is IPv4 or IPv6 */
static bool is_ip_proto(__be16 proto)
{
switch (proto) {
case htons(ETH_P_IP):
case htons(ETH_P_IPV6):
return true;
}
return false;
}
static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{ {
...@@ -128,6 +138,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb ...@@ -128,6 +138,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
struct cdc_ncm_ctx *ctx = info->ctx; struct cdc_ncm_ctx *ctx = info->ctx;
__le32 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN); __le32 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN);
u16 tci = 0; u16 tci = 0;
bool is_ip;
u8 *c; u8 *c;
if (!ctx) if (!ctx)
...@@ -137,25 +148,32 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb ...@@ -137,25 +148,32 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
if (skb->len <= ETH_HLEN) if (skb->len <= ETH_HLEN)
goto error; goto error;
/* Some applications using e.g. packet sockets will
* bypass the VLAN acceleration and create tagged
* ethernet frames directly. We primarily look for
* the accelerated out-of-band tag, but fall back if
* required
*/
skb_reset_mac_header(skb);
if (vlan_get_tag(skb, &tci) < 0 && skb->len > VLAN_ETH_HLEN &&
__vlan_get_tag(skb, &tci) == 0) {
is_ip = is_ip_proto(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto);
skb_pull(skb, VLAN_ETH_HLEN);
} else {
is_ip = is_ip_proto(eth_hdr(skb)->h_proto);
skb_pull(skb, ETH_HLEN);
}
/* mapping VLANs to MBIM sessions: /* mapping VLANs to MBIM sessions:
* no tag => IPS session <0> * no tag => IPS session <0>
* 1 - 255 => IPS session <vlanid> * 1 - 255 => IPS session <vlanid>
* 256 - 511 => DSS session <vlanid - 256> * 256 - 511 => DSS session <vlanid - 256>
* 512 - 4095 => unsupported, drop * 512 - 4095 => unsupported, drop
*/ */
vlan_get_tag(skb, &tci);
switch (tci & 0x0f00) { switch (tci & 0x0f00) {
case 0x0000: /* VLAN ID 0 - 255 */ case 0x0000: /* VLAN ID 0 - 255 */
/* verify that datagram is IPv4 or IPv6 */ if (!is_ip)
skb_reset_mac_header(skb);
switch (eth_hdr(skb)->h_proto) {
case htons(ETH_P_IP):
case htons(ETH_P_IPV6):
break;
default:
goto error; goto error;
}
c = (u8 *)&sign; c = (u8 *)&sign;
c[3] = tci; c[3] = tci;
break; break;
...@@ -169,7 +187,6 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb ...@@ -169,7 +187,6 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
"unsupported tci=0x%04x\n", tci); "unsupported tci=0x%04x\n", tci);
goto error; goto error;
} }
skb_pull(skb, ETH_HLEN);
} }
spin_lock_bh(&ctx->mtx); spin_lock_bh(&ctx->mtx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment