From 9cfdc6e9ff4ecd8423e397bb3f70a95667b6414a Mon Sep 17 00:00:00 2001 From: Wolfgang Wiedmeyer Date: Mon, 4 Sep 2017 00:44:06 +0200 Subject: net: usb: qmi_wwan: assume raw IP mode So far, the driver has assumed that the modem operates in ethernet mode. While this is true for MDM9x15 in its default mode, it's not what we want. Android expects RIL data connections to use point-to-point protocol and integrating dhcp client operations into the RIL is troublesome. So assume raw IP mode and expect that it's set in userspace. Some additional adaptions were necessary to ensure that packets don't get dropped. They were taken from the rmnet driver while using the mainline qmi_wwan driver as a reference. It would be better if it would be possible to switch between the modes with a sysfs property. This functionality could still be added. Signed-off-by: Wolfgang Wiedmeyer --- drivers/net/usb/qmi_wwan.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 58c83d0..bed34e3 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -57,9 +58,36 @@ static const char qmi_pm_dev[] = "mdm_hsic_pm0"; * corresponding management interface */ +static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + __be16 protocol = 0; + + skb->dev = dev->net; + + /* assumes RAW IP mode! */ + + switch (skb->data[0] & 0xf0) { + case 0x40: + protocol = htons(ETH_P_IP); + break; + case 0x60: + protocol = htons(ETH_P_IPV6); + break; + default: + pr_err("[%s] qmi_wwan L3 protocol decode error: 0x%02x", + dev->net->name, skb->data[0] & 0xf0); + } + + skb->protocol = protocol; + + return 1; +} + int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) { struct usb_device *udev; + struct usbnet *unet; + struct net_device *net_dev; int status; udev = interface_to_usbdev(intf); @@ -70,6 +98,19 @@ int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) return -1; } + unet = usb_get_intfdata(intf); + net_dev = unet->net; + /* set RAWIP protocol */ + net_dev->header_ops = 0; /* No header */ + net_dev->type = ARPHRD_RAWIP; + net_dev->hard_header_len = 0; + net_dev->addr_len = 0; + net_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + /* recalculate buffers after changing hard_header_len */ + usbnet_change_mtu(net_dev, net_dev->mtu); + + /* give margin before send DTR high */ + msleep(20); pr_info("%s: send DTR high to modem\n", __func__); status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_CDC_REQ_SET_CONTROL_LINE_STATE, @@ -382,6 +423,7 @@ static const struct driver_info qmi_wwan_info = { .flags = FLAG_WWAN, .bind = qmi_wwan_bind, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, }; static const struct driver_info qmi_wwan_shared = { @@ -398,6 +440,7 @@ static const struct driver_info qmi_wwan_gobi = { .bind = qmi_wwan_bind_gobi, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, }; /* ZTE suck at making USB descriptors */ @@ -407,6 +450,7 @@ static const struct driver_info qmi_wwan_force_int4 = { .bind = qmi_wwan_bind_gobi, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, .data = BIT(4), /* interface whitelist bitmap */ }; @@ -491,7 +535,7 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ - {QMI_GOBI_DEVICE(0x05c6, 0x904c)}, /* MDM9x15 */ + {QMI_GOBI_DEVICE(0x05c6, 0x904c)}, /* MDM9x15 */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); -- cgit v1.1