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