aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElina Pasheva <epasheva@sierrawireless.com>2010-04-27 21:06:41 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-27 21:12:04 -0400
commiteb4fd8cd355c8ec425a12ec6cbdac614e8a4819d (patch)
treef56ccf5063b6c703351880c11694a6fb5ece4590
parent55964d72d63b15df49a5df11ef91dc8601270815 (diff)
net/usb: add sierra_net.c driver
Re-submitted based on comments from netdev community. Summary of the changes: 1. Improved error handling. 2. Added the missing timeout arguments to usb_control_msg(). The following is a new Linux driver which exposes certain models of Sierra Wireless modems to the operating system as Network Interface Cards (NICs). This driver requires a version of the sierra.c driver which supports blacklisting to work properly. The blacklist in sierra.c rejects the interfaces claimed by sierra_net.c. Likewise, the sierra_net.c driver only accepts (i.e. whitelists) the interface(s) used for USB-to-WWAN traffic. The version of sierra.c which supports blacklisting is available from the sierra wireless knowledge base page for older kernels. It is also available in Linux kernel starting from version 2.6.31. This driver works with all Sierra Wireless devices configured with PID=68A3 like USB305, USB306 provided the corresponding firmware version is I2.0 (for USB305) or M3.0 (for USB306) and later. This driver will not work with earlier firmware versions than the ones shown above. In this case the driver will issue an error message indicating incompatibility and will not serve the device's USB-to-WWAN interface. Sierra_net.c sits atop a pre-existing Linux driver called usbnet.c. A series of hook functions are provided in sierra_net.c which are called by usbnet.c in response to a particular condition such as receipt or transmission of a data packet. As such, usbnet.c does most of the work of making a modem appear to the system as a network device and for properly exchanging traffic between the USB subsystem and the Network card interface. Sierra_net.c is concerned with managing the data exchanged between the USB-to-WWAN interface and the upper layers of the operating system. Signed-off-by: Elina Pasheva <epasheva@sierrawireless.com> Signed-off-by: Rory Filer <rfiler@sierrawireless.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/Kconfig10
-rw-r--r--drivers/net/usb/Makefile1
-rw-r--r--drivers/net/usb/sierra_net.c1001
3 files changed, 1012 insertions, 0 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 63be4caec70e..5d58abc224f4 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -397,4 +397,14 @@ config USB_IPHETH
397 397
398 For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver 398 For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
399 399
400config USB_SIERRA_NET
401 tristate "USB-to-WWAN Driver for Sierra Wireless modems"
402 depends on USB_USBNET
403 default y
404 help
405 Choose this option if you have a Sierra Wireless USB-to-WWAN device.
406
407 To compile this driver as a module, choose M here: the
408 module will be called sierra_net.
409
400endmenu 410endmenu
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index edb09c0ddf8e..b13a279663ba 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -24,4 +24,5 @@ obj-$(CONFIG_USB_USBNET) += usbnet.o
24obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o 24obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
25obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o 25obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o
26obj-$(CONFIG_USB_IPHETH) += ipheth.o 26obj-$(CONFIG_USB_IPHETH) += ipheth.o
27obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
27 28
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
new file mode 100644
index 000000000000..a44f9e0ea098
--- /dev/null
+++ b/drivers/net/usb/sierra_net.c
@@ -0,0 +1,1001 @@
1/*
2 * USB-to-WWAN Driver for Sierra Wireless modems
3 *
4 * Copyright (C) 2008, 2009, 2010 Paxton Smith, Matthew Safar, Rory Filer
5 * <linux@sierrawireless.com>
6 *
7 * Portions of this based on the cdc_ether driver by David Brownell (2003-2005)
8 * and Ole Andre Vadla Ravnas (ActiveSync) (2006).
9 *
10 * IMPORTANT DISCLAIMER: This driver is not commercially supported by
11 * Sierra Wireless. Use at your own risk.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#define DRIVER_VERSION "v.2.0"
29#define DRIVER_AUTHOR "Paxton Smith, Matthew Safar, Rory Filer"
30#define DRIVER_DESC "USB-to-WWAN Driver for Sierra Wireless modems"
31static const char driver_name[] = "sierra_net";
32
33/* if defined debug messages enabled */
34/*#define DEBUG*/
35
36#include <linux/module.h>
37#include <linux/etherdevice.h>
38#include <linux/ethtool.h>
39#include <linux/mii.h>
40#include <linux/sched.h>
41#include <linux/timer.h>
42#include <linux/usb.h>
43#include <linux/usb/cdc.h>
44#include <net/ip.h>
45#include <net/udp.h>
46#include <asm/unaligned.h>
47#include <linux/usb/usbnet.h>
48
49#define SWI_USB_REQUEST_GET_FW_ATTR 0x06
50#define SWI_GET_FW_ATTR_MASK 0x08
51
52/* atomic counter partially included in MAC address to make sure 2 devices
53 * do not end up with the same MAC - concept breaks in case of > 255 ifaces
54 */
55static atomic_t iface_counter = ATOMIC_INIT(0);
56
57/*
58 * SYNC Timer Delay definition used to set the expiry time
59 */
60#define SIERRA_NET_SYNCDELAY (2*HZ)
61
62/* Max. MTU supported. The modem buffers are limited to 1500 */
63#define SIERRA_NET_MAX_SUPPORTED_MTU 1500
64
65/* The SIERRA_NET_USBCTL_BUF_LEN defines a buffer size allocated for control
66 * message reception ... and thus the max. received packet.
67 * (May be the cause for parse_hip returning -EINVAL)
68 */
69#define SIERRA_NET_USBCTL_BUF_LEN 1024
70
71/* list of interface numbers - used for constructing interface lists */
72struct sierra_net_iface_info {
73 const u32 infolen; /* number of interface numbers on list */
74 const u8 *ifaceinfo; /* pointer to the array holding the numbers */
75};
76
77struct sierra_net_info_data {
78 u16 rx_urb_size;
79 struct sierra_net_iface_info whitelist;
80};
81
82/* Private data structure */
83struct sierra_net_data {
84
85 u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */
86
87 u16 link_up; /* air link up or down */
88 u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */
89
90 u8 sync_msg[4]; /* SYNC message */
91 u8 shdwn_msg[4]; /* Shutdown message */
92
93 /* Backpointer to the container */
94 struct usbnet *usbnet;
95
96 u8 ifnum; /* interface number */
97
98/* Bit masks, must be a power of 2 */
99#define SIERRA_NET_EVENT_RESP_AVAIL 0x01
100#define SIERRA_NET_TIMER_EXPIRY 0x02
101 unsigned long kevent_flags;
102 struct work_struct sierra_net_kevent;
103 struct timer_list sync_timer; /* For retrying SYNC sequence */
104};
105
106struct param {
107 int is_present;
108 union {
109 void *ptr;
110 u32 dword;
111 u16 word;
112 u8 byte;
113 };
114};
115
116/* HIP message type */
117#define SIERRA_NET_HIP_EXTENDEDID 0x7F
118#define SIERRA_NET_HIP_HSYNC_ID 0x60 /* Modem -> host */
119#define SIERRA_NET_HIP_RESTART_ID 0x62 /* Modem -> host */
120#define SIERRA_NET_HIP_MSYNC_ID 0x20 /* Host -> modem */
121#define SIERRA_NET_HIP_SHUTD_ID 0x26 /* Host -> modem */
122
123#define SIERRA_NET_HIP_EXT_IP_IN_ID 0x0202
124#define SIERRA_NET_HIP_EXT_IP_OUT_ID 0x0002
125
126/* 3G UMTS Link Sense Indication definitions */
127#define SIERRA_NET_HIP_LSI_UMTSID 0x78
128
129/* Reverse Channel Grant Indication HIP message */
130#define SIERRA_NET_HIP_RCGI 0x64
131
132/* LSI Protocol types */
133#define SIERRA_NET_PROTOCOL_UMTS 0x01
134/* LSI Coverage */
135#define SIERRA_NET_COVERAGE_NONE 0x00
136#define SIERRA_NET_COVERAGE_NOPACKET 0x01
137
138/* LSI Session */
139#define SIERRA_NET_SESSION_IDLE 0x00
140/* LSI Link types */
141#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00
142
143struct lsi_umts {
144 u8 protocol;
145 u8 unused1;
146 __be16 length;
147 /* eventually use a union for the rest - assume umts for now */
148 u8 coverage;
149 u8 unused2[41];
150 u8 session_state;
151 u8 unused3[33];
152 u8 link_type;
153 u8 pdp_addr_len; /* NW-supplied PDP address len */
154 u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */
155 u8 unused4[23];
156 u8 dns1_addr_len; /* NW-supplied 1st DNS address len (bigendian) */
157 u8 dns1_addr[16]; /* NW-supplied 1st DNS address */
158 u8 dns2_addr_len; /* NW-supplied 2nd DNS address len */
159 u8 dns2_addr[16]; /* NW-supplied 2nd DNS address (bigendian)*/
160 u8 wins1_addr_len; /* NW-supplied 1st Wins address len */
161 u8 wins1_addr[16]; /* NW-supplied 1st Wins address (bigendian)*/
162 u8 wins2_addr_len; /* NW-supplied 2nd Wins address len */
163 u8 wins2_addr[16]; /* NW-supplied 2nd Wins address (bigendian) */
164 u8 unused5[4];
165 u8 gw_addr_len; /* NW-supplied GW address len */
166 u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */
167 u8 reserved[8];
168} __attribute__ ((packed));
169
170#define SIERRA_NET_LSI_COMMON_LEN 4
171#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts))
172#define SIERRA_NET_LSI_UMTS_STATUS_LEN \
173 (SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
174
175/* Forward definitions */
176static void sierra_sync_timer(unsigned long syncdata);
177static int sierra_net_change_mtu(struct net_device *net, int new_mtu);
178
179/* Our own net device operations structure */
180static const struct net_device_ops sierra_net_device_ops = {
181 .ndo_open = usbnet_open,
182 .ndo_stop = usbnet_stop,
183 .ndo_start_xmit = usbnet_start_xmit,
184 .ndo_tx_timeout = usbnet_tx_timeout,
185 .ndo_change_mtu = sierra_net_change_mtu,
186 .ndo_set_mac_address = eth_mac_addr,
187 .ndo_validate_addr = eth_validate_addr,
188};
189
190/* get private data associated with passed in usbnet device */
191static inline struct sierra_net_data *sierra_net_get_private(struct usbnet *dev)
192{
193 return (struct sierra_net_data *)dev->data[0];
194}
195
196/* set private data associated with passed in usbnet device */
197static inline void sierra_net_set_private(struct usbnet *dev,
198 struct sierra_net_data *priv)
199{
200 dev->data[0] = (unsigned long)priv;
201}
202
203/* is packet IPv4 */
204static inline int is_ip(struct sk_buff *skb)
205{
206 return (skb->protocol == cpu_to_be16(ETH_P_IP));
207}
208
209/*
210 * check passed in packet and make sure that:
211 * - it is linear (no scatter/gather)
212 * - it is ethernet (mac_header properly set)
213 */
214static int check_ethip_packet(struct sk_buff *skb, struct usbnet *dev)
215{
216 skb_reset_mac_header(skb); /* ethernet header */
217
218 if (skb_is_nonlinear(skb)) {
219 netdev_err(dev->net, "Non linear buffer-dropping\n");
220 return 0;
221 }
222
223 if (!pskb_may_pull(skb, ETH_HLEN))
224 return 0;
225 skb->protocol = eth_hdr(skb)->h_proto;
226
227 return 1;
228}
229
230static const u8 *save16bit(struct param *p, const u8 *datap)
231{
232 p->is_present = 1;
233 p->word = get_unaligned_be16(datap);
234 return datap + sizeof(p->word);
235}
236
237static const u8 *save8bit(struct param *p, const u8 *datap)
238{
239 p->is_present = 1;
240 p->byte = *datap;
241 return datap + sizeof(p->byte);
242}
243
244/*----------------------------------------------------------------------------*
245 * BEGIN HIP *
246 *----------------------------------------------------------------------------*/
247/* HIP header */
248#define SIERRA_NET_HIP_HDR_LEN 4
249/* Extended HIP header */
250#define SIERRA_NET_HIP_EXT_HDR_LEN 6
251
252struct hip_hdr {
253 int hdrlen;
254 struct param payload_len;
255 struct param msgid;
256 struct param msgspecific;
257 struct param extmsgid;
258};
259
260static int parse_hip(const u8 *buf, const u32 buflen, struct hip_hdr *hh)
261{
262 const u8 *curp = buf;
263 int padded;
264
265 if (buflen < SIERRA_NET_HIP_HDR_LEN)
266 return -EPROTO;
267
268 curp = save16bit(&hh->payload_len, curp);
269 curp = save8bit(&hh->msgid, curp);
270 curp = save8bit(&hh->msgspecific, curp);
271
272 padded = hh->msgid.byte & 0x80;
273 hh->msgid.byte &= 0x7F; /* 7 bits */
274
275 hh->extmsgid.is_present = (hh->msgid.byte == SIERRA_NET_HIP_EXTENDEDID);
276 if (hh->extmsgid.is_present) {
277 if (buflen < SIERRA_NET_HIP_EXT_HDR_LEN)
278 return -EPROTO;
279
280 hh->payload_len.word &= 0x3FFF; /* 14 bits */
281
282 curp = save16bit(&hh->extmsgid, curp);
283 hh->extmsgid.word &= 0x03FF; /* 10 bits */
284
285 hh->hdrlen = SIERRA_NET_HIP_EXT_HDR_LEN;
286 } else {
287 hh->payload_len.word &= 0x07FF; /* 11 bits */
288 hh->hdrlen = SIERRA_NET_HIP_HDR_LEN;
289 }
290
291 if (padded) {
292 hh->hdrlen++;
293 hh->payload_len.word--;
294 }
295
296 /* if real packet shorter than the claimed length */
297 if (buflen < (hh->hdrlen + hh->payload_len.word))
298 return -EINVAL;
299
300 return 0;
301}
302
303static void build_hip(u8 *buf, const u16 payloadlen,
304 struct sierra_net_data *priv)
305{
306 /* the following doesn't have the full functionality. We
307 * currently build only one kind of header, so it is faster this way
308 */
309 put_unaligned_be16(payloadlen, buf);
310 memcpy(buf+2, priv->tx_hdr_template, sizeof(priv->tx_hdr_template));
311}
312/*----------------------------------------------------------------------------*
313 * END HIP *
314 *----------------------------------------------------------------------------*/
315
316static int sierra_net_send_cmd(struct usbnet *dev,
317 u8 *cmd, int cmdlen, const char * cmd_name)
318{
319 struct sierra_net_data *priv = sierra_net_get_private(dev);
320 int status;
321
322 status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
323 USB_CDC_SEND_ENCAPSULATED_COMMAND,
324 USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE, 0,
325 priv->ifnum, cmd, cmdlen, USB_CTRL_SET_TIMEOUT);
326
327 if (status != cmdlen && status != -ENODEV)
328 netdev_err(dev->net, "Submit %s failed %d\n", cmd_name, status);
329
330 return status;
331}
332
333static int sierra_net_send_sync(struct usbnet *dev)
334{
335 int status;
336 struct sierra_net_data *priv = sierra_net_get_private(dev);
337
338 dev_dbg(&dev->udev->dev, "%s", __func__);
339
340 status = sierra_net_send_cmd(dev, priv->sync_msg,
341 sizeof(priv->sync_msg), "SYNC");
342
343 return status;
344}
345
346static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix)
347{
348 dev_dbg(&(priv->usbnet->udev->dev), "%s %d", __func__, ctx_ix);
349 priv->tx_hdr_template[0] = 0x3F;
350 priv->tx_hdr_template[1] = ctx_ix;
351 *((u16 *)&priv->tx_hdr_template[2]) =
352 cpu_to_be16(SIERRA_NET_HIP_EXT_IP_OUT_ID);
353}
354
355static inline int sierra_net_is_valid_addrlen(u8 len)
356{
357 return (len == sizeof(struct in_addr));
358}
359
360static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
361{
362 struct lsi_umts *lsi = (struct lsi_umts *)data;
363
364 if (datalen < sizeof(struct lsi_umts)) {
365 netdev_err(dev->net, "%s: Data length %d, exp %Zu\n",
366 __func__, datalen,
367 sizeof(struct lsi_umts));
368 return -1;
369 }
370
371 if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) {
372 netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
373 __func__, be16_to_cpu(lsi->length),
374 (u32)SIERRA_NET_LSI_UMTS_STATUS_LEN);
375 return -1;
376 }
377
378 /* Validate the protocol - only support UMTS for now */
379 if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) {
380 netdev_err(dev->net, "Protocol unsupported, 0x%02x\n",
381 lsi->protocol);
382 return -1;
383 }
384
385 /* Validate the link type */
386 if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) {
387 netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
388 lsi->link_type);
389 return -1;
390 }
391
392 /* Validate the coverage */
393 if (lsi->coverage == SIERRA_NET_COVERAGE_NONE
394 || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
395 netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage);
396 return 0;
397 }
398
399 /* Validate the session state */
400 if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
401 netdev_err(dev->net, "Session idle, 0x%02x\n",
402 lsi->session_state);
403 return 0;
404 }
405
406 /* Set link_sense true */
407 return 1;
408}
409
410static void sierra_net_handle_lsi(struct usbnet *dev, char *data,
411 struct hip_hdr *hh)
412{
413 struct sierra_net_data *priv = sierra_net_get_private(dev);
414 int link_up;
415
416 link_up = sierra_net_parse_lsi(dev, data + hh->hdrlen,
417 hh->payload_len.word);
418 if (link_up < 0) {
419 netdev_err(dev->net, "Invalid LSI\n");
420 return;
421 }
422 if (link_up) {
423 sierra_net_set_ctx_index(priv, hh->msgspecific.byte);
424 priv->link_up = 1;
425 netif_carrier_on(dev->net);
426 } else {
427 priv->link_up = 0;
428 netif_carrier_off(dev->net);
429 }
430}
431
432static void sierra_net_dosync(struct usbnet *dev)
433{
434 int status;
435 struct sierra_net_data *priv = sierra_net_get_private(dev);
436
437 dev_dbg(&dev->udev->dev, "%s", __func__);
438
439 /* tell modem we are ready */
440 status = sierra_net_send_sync(dev);
441 if (status < 0)
442 netdev_err(dev->net,
443 "Send SYNC failed, status %d\n", status);
444 status = sierra_net_send_sync(dev);
445 if (status < 0)
446 netdev_err(dev->net,
447 "Send SYNC failed, status %d\n", status);
448
449 /* Now, start a timer and make sure we get the Restart Indication */
450 priv->sync_timer.function = sierra_sync_timer;
451 priv->sync_timer.data = (unsigned long) dev;
452 priv->sync_timer.expires = jiffies + SIERRA_NET_SYNCDELAY;
453 add_timer(&priv->sync_timer);
454}
455
456static void sierra_net_kevent(struct work_struct *work)
457{
458 struct sierra_net_data *priv =
459 container_of(work, struct sierra_net_data, sierra_net_kevent);
460 struct usbnet *dev = priv->usbnet;
461 int len;
462 int err;
463 u8 *buf;
464 u8 ifnum;
465
466 if (test_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags)) {
467 clear_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags);
468
469 /* Query the modem for the LSI message */
470 buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL);
471 if (!buf) {
472 netdev_err(dev->net,
473 "failed to allocate buf for LS msg\n");
474 return;
475 }
476 ifnum = priv->ifnum;
477 len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
478 USB_CDC_GET_ENCAPSULATED_RESPONSE,
479 USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE,
480 0, ifnum, buf, SIERRA_NET_USBCTL_BUF_LEN,
481 USB_CTRL_SET_TIMEOUT);
482
483 if (len < 0) {
484 netdev_err(dev->net,
485 "usb_control_msg failed, status %d\n", len);
486 } else {
487 struct hip_hdr hh;
488
489 dev_dbg(&dev->udev->dev, "%s: Received status message,"
490 " %04x bytes", __func__, len);
491
492 err = parse_hip(buf, len, &hh);
493 if (err) {
494 netdev_err(dev->net, "%s: Bad packet,"
495 " parse result %d\n", __func__, err);
496 kfree(buf);
497 return;
498 }
499
500 /* Validate packet length */
501 if (len != hh.hdrlen + hh.payload_len.word) {
502 netdev_err(dev->net, "%s: Bad packet, received"
503 " %d, expected %d\n", __func__, len,
504 hh.hdrlen + hh.payload_len.word);
505 kfree(buf);
506 return;
507 }
508
509 /* Switch on received message types */
510 switch (hh.msgid.byte) {
511 case SIERRA_NET_HIP_LSI_UMTSID:
512 dev_dbg(&dev->udev->dev, "LSI for ctx:%d",
513 hh.msgspecific.byte);
514 sierra_net_handle_lsi(dev, buf, &hh);
515 break;
516 case SIERRA_NET_HIP_RESTART_ID:
517 dev_dbg(&dev->udev->dev, "Restart reported: %d,"
518 " stopping sync timer",
519 hh.msgspecific.byte);
520 /* Got sync resp - stop timer & clear mask */
521 del_timer_sync(&priv->sync_timer);
522 clear_bit(SIERRA_NET_TIMER_EXPIRY,
523 &priv->kevent_flags);
524 break;
525 case SIERRA_NET_HIP_HSYNC_ID:
526 dev_dbg(&dev->udev->dev, "SYNC received");
527 err = sierra_net_send_sync(dev);
528 if (err < 0)
529 netdev_err(dev->net,
530 "Send SYNC failed %d\n", err);
531 break;
532 case SIERRA_NET_HIP_EXTENDEDID:
533 netdev_err(dev->net, "Unrecognized HIP msg, "
534 "extmsgid 0x%04x\n", hh.extmsgid.word);
535 break;
536 case SIERRA_NET_HIP_RCGI:
537 /* Ignored */
538 break;
539 default:
540 netdev_err(dev->net, "Unrecognized HIP msg, "
541 "msgid 0x%02x\n", hh.msgid.byte);
542 break;
543 }
544 }
545 kfree(buf);
546 }
547 /* The sync timer bit might be set */
548 if (test_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags)) {
549 clear_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags);
550 dev_dbg(&dev->udev->dev, "Deferred sync timer expiry");
551 sierra_net_dosync(priv->usbnet);
552 }
553
554 if (priv->kevent_flags)
555 dev_dbg(&dev->udev->dev, "sierra_net_kevent done, "
556 "kevent_flags = 0x%lx", priv->kevent_flags);
557}
558
559static void sierra_net_defer_kevent(struct usbnet *dev, int work)
560{
561 struct sierra_net_data *priv = sierra_net_get_private(dev);
562
563 set_bit(work, &priv->kevent_flags);
564 schedule_work(&priv->sierra_net_kevent);
565}
566
567/*
568 * Sync Retransmit Timer Handler. On expiry, kick the work queue
569 */
570void sierra_sync_timer(unsigned long syncdata)
571{
572 struct usbnet *dev = (struct usbnet *)syncdata;
573
574 dev_dbg(&dev->udev->dev, "%s", __func__);
575 /* Kick the tasklet */
576 sierra_net_defer_kevent(dev, SIERRA_NET_TIMER_EXPIRY);
577}
578
579static void sierra_net_status(struct usbnet *dev, struct urb *urb)
580{
581 struct usb_cdc_notification *event;
582
583 dev_dbg(&dev->udev->dev, "%s", __func__);
584
585 if (urb->actual_length < sizeof *event)
586 return;
587
588 /* Add cases to handle other standard notifications. */
589 event = urb->transfer_buffer;
590 switch (event->bNotificationType) {
591 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
592 case USB_CDC_NOTIFY_SPEED_CHANGE:
593 /* USB 305 sends those */
594 break;
595 case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
596 sierra_net_defer_kevent(dev, SIERRA_NET_EVENT_RESP_AVAIL);
597 break;
598 default:
599 netdev_err(dev->net, ": unexpected notification %02x!\n",
600 event->bNotificationType);
601 break;
602 }
603}
604
605static void sierra_net_get_drvinfo(struct net_device *net,
606 struct ethtool_drvinfo *info)
607{
608 /* Inherit standard device info */
609 usbnet_get_drvinfo(net, info);
610 strncpy(info->driver, driver_name, sizeof info->driver);
611 strncpy(info->version, DRIVER_VERSION, sizeof info->version);
612}
613
614static u32 sierra_net_get_link(struct net_device *net)
615{
616 struct usbnet *dev = netdev_priv(net);
617 /* Report link is down whenever the interface is down */
618 return sierra_net_get_private(dev)->link_up && netif_running(net);
619}
620
621static struct ethtool_ops sierra_net_ethtool_ops = {
622 .get_drvinfo = sierra_net_get_drvinfo,
623 .get_link = sierra_net_get_link,
624 .get_msglevel = usbnet_get_msglevel,
625 .set_msglevel = usbnet_set_msglevel,
626 .get_settings = usbnet_get_settings,
627 .set_settings = usbnet_set_settings,
628 .nway_reset = usbnet_nway_reset,
629};
630
631/* MTU can not be more than 1500 bytes, enforce it. */
632static int sierra_net_change_mtu(struct net_device *net, int new_mtu)
633{
634 if (new_mtu > SIERRA_NET_MAX_SUPPORTED_MTU)
635 return -EINVAL;
636
637 return usbnet_change_mtu(net, new_mtu);
638}
639
640static int is_whitelisted(const u8 ifnum,
641 const struct sierra_net_iface_info *whitelist)
642{
643 if (whitelist) {
644 const u8 *list = whitelist->ifaceinfo;
645 int i;
646
647 for (i = 0; i < whitelist->infolen; i++) {
648 if (list[i] == ifnum)
649 return 1;
650 }
651 }
652 return 0;
653}
654
655static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
656{
657 int result = 0;
658 u16 *attrdata;
659
660 attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL);
661 if (!attrdata)
662 return -ENOMEM;
663
664 result = usb_control_msg(
665 dev->udev,
666 usb_rcvctrlpipe(dev->udev, 0),
667 /* _u8 vendor specific request */
668 SWI_USB_REQUEST_GET_FW_ATTR,
669 USB_DIR_IN | USB_TYPE_VENDOR, /* __u8 request type */
670 0x0000, /* __u16 value not used */
671 0x0000, /* __u16 index not used */
672 attrdata, /* char *data */
673 sizeof(*attrdata), /* __u16 size */
674 USB_CTRL_SET_TIMEOUT); /* int timeout */
675
676 if (result < 0) {
677 kfree(attrdata);
678 return -EIO;
679 }
680
681 *datap = *attrdata;
682
683 kfree(attrdata);
684 return result;
685}
686
687/*
688 * collects the bulk endpoints, the status endpoint.
689 */
690static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
691{
692 u8 ifacenum;
693 u8 numendpoints;
694 u16 fwattr = 0;
695 int status;
696 struct ethhdr *eth;
697 struct sierra_net_data *priv;
698 static const u8 sync_tmplate[sizeof(priv->sync_msg)] = {
699 0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00};
700 static const u8 shdwn_tmplate[sizeof(priv->shdwn_msg)] = {
701 0x00, 0x00, SIERRA_NET_HIP_SHUTD_ID, 0x00};
702
703 struct sierra_net_info_data *data =
704 (struct sierra_net_info_data *)dev->driver_info->data;
705
706 dev_dbg(&dev->udev->dev, "%s", __func__);
707
708 ifacenum = intf->cur_altsetting->desc.bInterfaceNumber;
709 /* We only accept certain interfaces */
710 if (!is_whitelisted(ifacenum, &data->whitelist)) {
711 dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum);
712 return -ENODEV;
713 }
714 numendpoints = intf->cur_altsetting->desc.bNumEndpoints;
715 /* We have three endpoints, bulk in and out, and a status */
716 if (numendpoints != 3) {
717 dev_err(&dev->udev->dev, "Expected 3 endpoints, found: %d",
718 numendpoints);
719 return -ENODEV;
720 }
721 /* Status endpoint set in usbnet_get_endpoints() */
722 dev->status = NULL;
723 status = usbnet_get_endpoints(dev, intf);
724 if (status < 0) {
725 dev_err(&dev->udev->dev, "Error in usbnet_get_endpoints (%d)",
726 status);
727 return -ENODEV;
728 }
729 /* Initialize sierra private data */
730 priv = kzalloc(sizeof *priv, GFP_KERNEL);
731 if (!priv) {
732 dev_err(&dev->udev->dev, "No memory");
733 return -ENOMEM;
734 }
735
736 priv->usbnet = dev;
737 priv->ifnum = ifacenum;
738 dev->net->netdev_ops = &sierra_net_device_ops;
739
740 /* change MAC addr to include, ifacenum, and to be unique */
741 dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
742 dev->net->dev_addr[ETH_ALEN-1] = ifacenum;
743
744 /* we will have to manufacture ethernet headers, prepare template */
745 eth = (struct ethhdr *)priv->ethr_hdr_tmpl;
746 memcpy(&eth->h_dest, dev->net->dev_addr, ETH_ALEN);
747 eth->h_proto = cpu_to_be16(ETH_P_IP);
748
749 /* prepare shutdown message template */
750 memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg));
751 /* set context index initially to 0 - prepares tx hdr template */
752 sierra_net_set_ctx_index(priv, 0);
753
754 /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */
755 dev->rx_urb_size = data->rx_urb_size;
756 if (dev->udev->speed != USB_SPEED_HIGH)
757 dev->rx_urb_size = min_t(size_t, 4096, data->rx_urb_size);
758
759 dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN;
760 dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
761
762 /* Set up the netdev */
763 dev->net->flags |= IFF_NOARP;
764 dev->net->ethtool_ops = &sierra_net_ethtool_ops;
765 netif_carrier_off(dev->net);
766
767 sierra_net_set_private(dev, priv);
768
769 priv->kevent_flags = 0;
770
771 /* Use the shared workqueue */
772 INIT_WORK(&priv->sierra_net_kevent, sierra_net_kevent);
773
774 /* Only need to do this once */
775 init_timer(&priv->sync_timer);
776
777 /* verify fw attributes */
778 status = sierra_net_get_fw_attr(dev, &fwattr);
779 dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr);
780
781 /* test whether firmware supports DHCP */
782 if (!(status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_MASK))) {
783 /* found incompatible firmware version */
784 dev_err(&dev->udev->dev, "Incompatible driver and firmware"
785 " versions\n");
786 kfree(priv);
787 return -ENODEV;
788 }
789 /* prepare sync message from template */
790 memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg));
791
792 return 0;
793}
794
795static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
796{
797 int status;
798 struct sierra_net_data *priv = sierra_net_get_private(dev);
799
800 dev_dbg(&dev->udev->dev, "%s", __func__);
801
802 /* Kill the timer then flush the work queue */
803 del_timer_sync(&priv->sync_timer);
804
805 flush_scheduled_work();
806
807 /* tell modem we are going away */
808 status = sierra_net_send_cmd(dev, priv->shdwn_msg,
809 sizeof(priv->shdwn_msg), "Shutdown");
810 if (status < 0)
811 netdev_err(dev->net,
812 "usb_control_msg failed, status %d\n", status);
813
814 sierra_net_set_private(dev, NULL);
815
816 kfree(priv);
817}
818
819static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev,
820 struct sk_buff *skb, int len)
821{
822 struct sk_buff *new_skb;
823
824 /* clone skb */
825 new_skb = skb_clone(skb, GFP_ATOMIC);
826
827 /* remove len bytes from original */
828 skb_pull(skb, len);
829
830 /* trim next packet to it's length */
831 if (new_skb) {
832 skb_trim(new_skb, len);
833 } else {
834 if (netif_msg_rx_err(dev))
835 netdev_err(dev->net, "failed to get skb\n");
836 dev->net->stats.rx_dropped++;
837 }
838
839 return new_skb;
840}
841
842/* ---------------------------- Receive data path ----------------------*/
843static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
844{
845 int err;
846 struct hip_hdr hh;
847 struct sk_buff *new_skb;
848
849 dev_dbg(&dev->udev->dev, "%s", __func__);
850
851 /* could contain multiple packets */
852 while (likely(skb->len)) {
853 err = parse_hip(skb->data, skb->len, &hh);
854 if (err) {
855 if (netif_msg_rx_err(dev))
856 netdev_err(dev->net, "Invalid HIP header %d\n",
857 err);
858 /* dev->net->stats.rx_errors incremented by caller */
859 dev->net->stats.rx_length_errors++;
860 return 0;
861 }
862
863 /* Validate Extended HIP header */
864 if (!hh.extmsgid.is_present
865 || hh.extmsgid.word != SIERRA_NET_HIP_EXT_IP_IN_ID) {
866 if (netif_msg_rx_err(dev))
867 netdev_err(dev->net, "HIP/ETH: Invalid pkt\n");
868
869 dev->net->stats.rx_frame_errors++;
870 /* dev->net->stats.rx_errors incremented by caller */;
871 return 0;
872 }
873
874 skb_pull(skb, hh.hdrlen);
875
876 /* We are going to accept this packet, prepare it */
877 memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl,
878 ETH_HLEN);
879
880 /* Last packet in batch handled by usbnet */
881 if (hh.payload_len.word == skb->len)
882 return 1;
883
884 new_skb = sierra_net_skb_clone(dev, skb, hh.payload_len.word);
885 if (new_skb)
886 usbnet_skb_return(dev, new_skb);
887
888 } /* while */
889
890 return 0;
891}
892
893/* ---------------------------- Transmit data path ----------------------*/
894struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
895 gfp_t flags)
896{
897 struct sierra_net_data *priv = sierra_net_get_private(dev);
898 u16 len;
899 bool need_tail;
900
901 dev_dbg(&dev->udev->dev, "%s", __func__);
902 if (priv->link_up && check_ethip_packet(skb, dev) && is_ip(skb)) {
903 /* enough head room as is? */
904 if (SIERRA_NET_HIP_EXT_HDR_LEN <= skb_headroom(skb)) {
905 /* Save the Eth/IP length and set up HIP hdr */
906 len = skb->len;
907 skb_push(skb, SIERRA_NET_HIP_EXT_HDR_LEN);
908 /* Handle ZLP issue */
909 need_tail = ((len + SIERRA_NET_HIP_EXT_HDR_LEN)
910 % dev->maxpacket == 0);
911 if (need_tail) {
912 if (unlikely(skb_tailroom(skb) == 0)) {
913 netdev_err(dev->net, "tx_fixup:"
914 "no room for packet\n");
915 dev_kfree_skb_any(skb);
916 return NULL;
917 } else {
918 skb->data[skb->len] = 0;
919 __skb_put(skb, 1);
920 len = len + 1;
921 }
922 }
923 build_hip(skb->data, len, priv);
924 return skb;
925 } else {
926 /*
927 * compensate in the future if necessary
928 */
929 netdev_err(dev->net, "tx_fixup: no room for HIP\n");
930 } /* headroom */
931 }
932
933 if (!priv->link_up)
934 dev->net->stats.tx_carrier_errors++;
935
936 /* tx_dropped incremented by usbnet */
937
938 /* filter the packet out, release it */
939 dev_kfree_skb_any(skb);
940 return NULL;
941}
942
943static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
944static const struct sierra_net_info_data sierra_net_info_data_68A3 = {
945 .rx_urb_size = 8 * 1024,
946 .whitelist = {
947 .infolen = ARRAY_SIZE(sierra_net_ifnum_list),
948 .ifaceinfo = sierra_net_ifnum_list
949 }
950};
951
952static const struct driver_info sierra_net_info_68A3 = {
953 .description = "Sierra Wireless USB-to-WWAN Modem",
954 .flags = FLAG_WWAN | FLAG_SEND_ZLP,
955 .bind = sierra_net_bind,
956 .unbind = sierra_net_unbind,
957 .status = sierra_net_status,
958 .rx_fixup = sierra_net_rx_fixup,
959 .tx_fixup = sierra_net_tx_fixup,
960 .data = (unsigned long)&sierra_net_info_data_68A3,
961};
962
963static const struct usb_device_id products[] = {
964 {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
965 .driver_info = (unsigned long) &sierra_net_info_68A3},
966
967 {}, /* last item */
968};
969MODULE_DEVICE_TABLE(usb, products);
970
971/* We are based on usbnet, so let it handle the USB driver specifics */
972static struct usb_driver sierra_net_driver = {
973 .name = "sierra_net",
974 .id_table = products,
975 .probe = usbnet_probe,
976 .disconnect = usbnet_disconnect,
977 .suspend = usbnet_suspend,
978 .resume = usbnet_resume,
979 .no_dynamic_id = 1,
980};
981
982static int __init sierra_net_init(void)
983{
984 BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data)
985 < sizeof(struct cdc_state));
986
987 return usb_register(&sierra_net_driver);
988}
989
990static void __exit sierra_net_exit(void)
991{
992 usb_deregister(&sierra_net_driver);
993}
994
995module_exit(sierra_net_exit);
996module_init(sierra_net_init);
997
998MODULE_AUTHOR(DRIVER_AUTHOR);
999MODULE_DESCRIPTION(DRIVER_DESC);
1000MODULE_VERSION(DRIVER_VERSION);
1001MODULE_LICENSE("GPL");