aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-04-19 17:51:26 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-19 17:51:26 -0400
commitb79d4a8dfd1b3a8387788b070ac2f856fb3a0877 (patch)
treec9a0a487312539688bcac21db127bcbbef842764
parent0cb670eef554652d0aa40bf09bd850e62598fc6c (diff)
parentcc6ba5fdaabea7a7b28de3ba1e0fe54d92232fe5 (diff)
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 <davem@davemloft.net>
-rw-r--r--drivers/net/usb/qmi_wwan.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 968d5d50751d..2a3579f67910 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/ethtool.h> 15#include <linux/ethtool.h>
16#include <linux/etherdevice.h>
16#include <linux/mii.h> 17#include <linux/mii.h>
17#include <linux/usb.h> 18#include <linux/usb.h>
18#include <linux/usb/cdc.h> 19#include <linux/usb/cdc.h>
@@ -52,6 +53,96 @@ struct qmi_wwan_state {
52 struct usb_interface *data; 53 struct usb_interface *data;
53}; 54};
54 55
56/* default ethernet address used by the modem */
57static 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 */
79static 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);
110fix_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 */
116static 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 */
122static 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
136static 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
55/* using a counter to merge subdriver requests with our own into a combined state */ 146/* using a counter to merge subdriver requests with our own into a combined state */
56static int qmi_wwan_manage_power(struct usbnet *dev, int on) 147static int qmi_wwan_manage_power(struct usbnet *dev, int on)
57{ 148{
@@ -229,6 +320,18 @@ next_desc:
229 usb_driver_release_interface(driver, info->data); 320 usb_driver_release_interface(driver, info->data);
230 } 321 }
231 322
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;
232err: 335err:
233 return status; 336 return status;
234} 337}
@@ -307,6 +410,7 @@ static const struct driver_info qmi_wwan_info = {
307 .bind = qmi_wwan_bind, 410 .bind = qmi_wwan_bind,
308 .unbind = qmi_wwan_unbind, 411 .unbind = qmi_wwan_unbind,
309 .manage_power = qmi_wwan_manage_power, 412 .manage_power = qmi_wwan_manage_power,
413 .rx_fixup = qmi_wwan_rx_fixup,
310}; 414};
311 415
312#define HUAWEI_VENDOR_ID 0x12D1 416#define HUAWEI_VENDOR_ID 0x12D1