Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b79d4a8

Browse files
committed
Merge branch 'qmi_wwan'
Bjørn Mork says: ==================== This series adds workarounds for 3 different firmware bugs, each preventing the affected devices from working at all. I therefore humbly request that these fixes go to stable-3.8 (if still maintained) and 3.9 (either via net if still possible, or via stable if not). All 3 workarounds are applied to all devices supported by the driver. Adding quirks for specific devices was considered as an alternative, but was rejected because we have too little information about the exact distribution of the buggy firmwares. All we know is that the same bug shows up in devices from at least 3 different, and presumably independent, vendors. The workarounds have instead been designed to automatically apply when necessary, and to have as little impact as possible on unaffected devices. The series has been tested on a number of devices both with and without these bugs. The series should apply cleanly to net/master, net-next/master and stable/linux-3.8.y ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 0cb670e + cc6ba5f commit b79d4a8

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

drivers/net/usb/qmi_wwan.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/module.h>
1414
#include <linux/netdevice.h>
1515
#include <linux/ethtool.h>
16+
#include <linux/etherdevice.h>
1617
#include <linux/mii.h>
1718
#include <linux/usb.h>
1819
#include <linux/usb/cdc.h>
@@ -52,6 +53,96 @@ struct qmi_wwan_state {
5253
struct usb_interface *data;
5354
};
5455

56+
/* default ethernet address used by the modem */
57+
static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
58+
59+
/* Make up an ethernet header if the packet doesn't have one.
60+
*
61+
* A firmware bug common among several devices cause them to send raw
62+
* IP packets under some circumstances. There is no way for the
63+
* driver/host to know when this will happen. And even when the bug
64+
* hits, some packets will still arrive with an intact header.
65+
*
66+
* The supported devices are only capably of sending IPv4, IPv6 and
67+
* ARP packets on a point-to-point link. Any packet with an ethernet
68+
* header will have either our address or a broadcast/multicast
69+
* address as destination. ARP packets will always have a header.
70+
*
71+
* This means that this function will reliably add the appropriate
72+
* header iff necessary, provided our hardware address does not start
73+
* with 4 or 6.
74+
*
75+
* Another common firmware bug results in all packets being addressed
76+
* to 00:a0:c6:00:00:00 despite the host address being different.
77+
* This function will also fixup such packets.
78+
*/
79+
static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
80+
{
81+
__be16 proto;
82+
83+
/* usbnet rx_complete guarantees that skb->len is at least
84+
* hard_header_len, so we can inspect the dest address without
85+
* checking skb->len
86+
*/
87+
switch (skb->data[0] & 0xf0) {
88+
case 0x40:
89+
proto = htons(ETH_P_IP);
90+
break;
91+
case 0x60:
92+
proto = htons(ETH_P_IPV6);
93+
break;
94+
case 0x00:
95+
if (is_multicast_ether_addr(skb->data))
96+
return 1;
97+
/* possibly bogus destination - rewrite just in case */
98+
skb_reset_mac_header(skb);
99+
goto fix_dest;
100+
default:
101+
/* pass along other packets without modifications */
102+
return 1;
103+
}
104+
if (skb_headroom(skb) < ETH_HLEN)
105+
return 0;
106+
skb_push(skb, ETH_HLEN);
107+
skb_reset_mac_header(skb);
108+
eth_hdr(skb)->h_proto = proto;
109+
memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
110+
fix_dest:
111+
memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
112+
return 1;
113+
}
114+
115+
/* very simplistic detection of IPv4 or IPv6 headers */
116+
static bool possibly_iphdr(const char *data)
117+
{
118+
return (data[0] & 0xd0) == 0x40;
119+
}
120+
121+
/* disallow addresses which may be confused with IP headers */
122+
static int qmi_wwan_mac_addr(struct net_device *dev, void *p)
123+
{
124+
int ret;
125+
struct sockaddr *addr = p;
126+
127+
ret = eth_prepare_mac_addr_change(dev, p);
128+
if (ret < 0)
129+
return ret;
130+
if (possibly_iphdr(addr->sa_data))
131+
return -EADDRNOTAVAIL;
132+
eth_commit_mac_addr_change(dev, p);
133+
return 0;
134+
}
135+
136+
static const struct net_device_ops qmi_wwan_netdev_ops = {
137+
.ndo_open = usbnet_open,
138+
.ndo_stop = usbnet_stop,
139+
.ndo_start_xmit = usbnet_start_xmit,
140+
.ndo_tx_timeout = usbnet_tx_timeout,
141+
.ndo_change_mtu = usbnet_change_mtu,
142+
.ndo_set_mac_address = qmi_wwan_mac_addr,
143+
.ndo_validate_addr = eth_validate_addr,
144+
};
145+
55146
/* using a counter to merge subdriver requests with our own into a combined state */
56147
static int qmi_wwan_manage_power(struct usbnet *dev, int on)
57148
{
@@ -229,6 +320,18 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
229320
usb_driver_release_interface(driver, info->data);
230321
}
231322

323+
/* Never use the same address on both ends of the link, even
324+
* if the buggy firmware told us to.
325+
*/
326+
if (!compare_ether_addr(dev->net->dev_addr, default_modem_addr))
327+
eth_hw_addr_random(dev->net);
328+
329+
/* make MAC addr easily distinguishable from an IP header */
330+
if (possibly_iphdr(dev->net->dev_addr)) {
331+
dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
332+
dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
333+
}
334+
dev->net->netdev_ops = &qmi_wwan_netdev_ops;
232335
err:
233336
return status;
234337
}
@@ -307,6 +410,7 @@ static const struct driver_info qmi_wwan_info = {
307410
.bind = qmi_wwan_bind,
308411
.unbind = qmi_wwan_unbind,
309412
.manage_power = qmi_wwan_manage_power,
413+
.rx_fixup = qmi_wwan_rx_fixup,
310414
};
311415

312416
#define HUAWEI_VENDOR_ID 0x12D1

0 commit comments

Comments
 (0)