|
@@ -120,6 +120,16 @@ static void cdc_mbim_unbind(struct usbnet *dev, struct usb_interface *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)
|
|
|
{
|
|
@@ -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;
|
|
|
__le32 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN);
|
|
|
u16 tci = 0;
|
|
|
+ bool is_ip;
|
|
|
u8 *c;
|
|
|
|
|
|
if (!ctx)
|
|
@@ -137,25 +148,32 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
|
|
|
if (skb->len <= ETH_HLEN)
|
|
|
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:
|
|
|
* no tag => IPS session <0>
|
|
|
* 1 - 255 => IPS session <vlanid>
|
|
|
* 256 - 511 => DSS session <vlanid - 256>
|
|
|
* 512 - 4095 => unsupported, drop
|
|
|
*/
|
|
|
- vlan_get_tag(skb, &tci);
|
|
|
-
|
|
|
switch (tci & 0x0f00) {
|
|
|
case 0x0000: /* VLAN ID 0 - 255 */
|
|
|
- /* verify that datagram is IPv4 or IPv6 */
|
|
|
- skb_reset_mac_header(skb);
|
|
|
- switch (eth_hdr(skb)->h_proto) {
|
|
|
- case htons(ETH_P_IP):
|
|
|
- case htons(ETH_P_IPV6):
|
|
|
- break;
|
|
|
- default:
|
|
|
+ if (!is_ip)
|
|
|
goto error;
|
|
|
- }
|
|
|
c = (u8 *)&sign;
|
|
|
c[3] = tci;
|
|
|
break;
|
|
@@ -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);
|
|
|
goto error;
|
|
|
}
|
|
|
- skb_pull(skb, ETH_HLEN);
|
|
|
}
|
|
|
|
|
|
spin_lock_bh(&ctx->mtx);
|