52
52
#include <linux/ethtool.h>
53
53
#include <linux/usb.h>
54
54
#include <linux/workqueue.h>
55
+ #include <linux/usb/cdc.h>
55
56
56
57
#define USB_VENDOR_APPLE 0x05ac
57
58
58
59
#define IPHETH_USBINTF_CLASS 255
59
60
#define IPHETH_USBINTF_SUBCLASS 253
60
61
#define IPHETH_USBINTF_PROTO 1
61
62
62
- #define IPHETH_BUF_SIZE 1514
63
63
#define IPHETH_IP_ALIGN 2 /* padding at front of URB */
64
+ #define IPHETH_NCM_HEADER_SIZE (12 + 96) /* NCMH + NCM0 */
65
+ #define IPHETH_TX_BUF_SIZE ETH_FRAME_LEN
66
+ #define IPHETH_RX_BUF_SIZE_LEGACY (IPHETH_IP_ALIGN + ETH_FRAME_LEN)
67
+ #define IPHETH_RX_BUF_SIZE_NCM 65536
68
+
64
69
#define IPHETH_TX_TIMEOUT (5 * HZ)
65
70
66
71
#define IPHETH_INTFNUM 2
71
76
#define IPHETH_CTRL_TIMEOUT (5 * HZ)
72
77
73
78
#define IPHETH_CMD_GET_MACADDR 0x00
79
+ #define IPHETH_CMD_ENABLE_NCM 0x04
74
80
#define IPHETH_CMD_CARRIER_CHECK 0x45
75
81
76
82
#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
@@ -97,6 +103,8 @@ struct ipheth_device {
97
103
u8 bulk_out ;
98
104
struct delayed_work carrier_work ;
99
105
bool confirmed_pairing ;
106
+ int (* rcvbulk_callback )(struct urb * urb );
107
+ size_t rx_buf_len ;
100
108
};
101
109
102
110
static int ipheth_rx_submit (struct ipheth_device * dev , gfp_t mem_flags );
@@ -116,12 +124,12 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
116
124
if (rx_urb == NULL )
117
125
goto free_tx_urb ;
118
126
119
- tx_buf = usb_alloc_coherent (iphone -> udev , IPHETH_BUF_SIZE ,
127
+ tx_buf = usb_alloc_coherent (iphone -> udev , IPHETH_TX_BUF_SIZE ,
120
128
GFP_KERNEL , & tx_urb -> transfer_dma );
121
129
if (tx_buf == NULL )
122
130
goto free_rx_urb ;
123
131
124
- rx_buf = usb_alloc_coherent (iphone -> udev , IPHETH_BUF_SIZE + IPHETH_IP_ALIGN ,
132
+ rx_buf = usb_alloc_coherent (iphone -> udev , iphone -> rx_buf_len ,
125
133
GFP_KERNEL , & rx_urb -> transfer_dma );
126
134
if (rx_buf == NULL )
127
135
goto free_tx_buf ;
@@ -134,7 +142,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
134
142
return 0 ;
135
143
136
144
free_tx_buf :
137
- usb_free_coherent (iphone -> udev , IPHETH_BUF_SIZE , tx_buf ,
145
+ usb_free_coherent (iphone -> udev , IPHETH_TX_BUF_SIZE , tx_buf ,
138
146
tx_urb -> transfer_dma );
139
147
free_rx_urb :
140
148
usb_free_urb (rx_urb );
@@ -146,9 +154,9 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
146
154
147
155
static void ipheth_free_urbs (struct ipheth_device * iphone )
148
156
{
149
- usb_free_coherent (iphone -> udev , IPHETH_BUF_SIZE + IPHETH_IP_ALIGN , iphone -> rx_buf ,
157
+ usb_free_coherent (iphone -> udev , iphone -> rx_buf_len , iphone -> rx_buf ,
150
158
iphone -> rx_urb -> transfer_dma );
151
- usb_free_coherent (iphone -> udev , IPHETH_BUF_SIZE , iphone -> tx_buf ,
159
+ usb_free_coherent (iphone -> udev , IPHETH_TX_BUF_SIZE , iphone -> tx_buf ,
152
160
iphone -> tx_urb -> transfer_dma );
153
161
usb_free_urb (iphone -> rx_urb );
154
162
usb_free_urb (iphone -> tx_urb );
@@ -160,14 +168,105 @@ static void ipheth_kill_urbs(struct ipheth_device *dev)
160
168
usb_kill_urb (dev -> rx_urb );
161
169
}
162
170
163
- static void ipheth_rcvbulk_callback ( struct urb * urb )
171
+ static int ipheth_consume_skb ( char * buf , int len , struct ipheth_device * dev )
164
172
{
165
- struct ipheth_device * dev ;
166
173
struct sk_buff * skb ;
167
- int status ;
174
+
175
+ skb = dev_alloc_skb (len );
176
+ if (!skb ) {
177
+ dev -> net -> stats .rx_dropped ++ ;
178
+ return - ENOMEM ;
179
+ }
180
+
181
+ skb_put_data (skb , buf , len );
182
+ skb -> dev = dev -> net ;
183
+ skb -> protocol = eth_type_trans (skb , dev -> net );
184
+
185
+ dev -> net -> stats .rx_packets ++ ;
186
+ dev -> net -> stats .rx_bytes += len ;
187
+ netif_rx (skb );
188
+
189
+ return 0 ;
190
+ }
191
+
192
+ static int ipheth_rcvbulk_callback_legacy (struct urb * urb )
193
+ {
194
+ struct ipheth_device * dev ;
168
195
char * buf ;
169
196
int len ;
170
197
198
+ dev = urb -> context ;
199
+
200
+ if (urb -> actual_length <= IPHETH_IP_ALIGN ) {
201
+ dev -> net -> stats .rx_length_errors ++ ;
202
+ return - EINVAL ;
203
+ }
204
+ len = urb -> actual_length - IPHETH_IP_ALIGN ;
205
+ buf = urb -> transfer_buffer + IPHETH_IP_ALIGN ;
206
+
207
+ return ipheth_consume_skb (buf , len , dev );
208
+ }
209
+
210
+ static int ipheth_rcvbulk_callback_ncm (struct urb * urb )
211
+ {
212
+ struct usb_cdc_ncm_nth16 * ncmh ;
213
+ struct usb_cdc_ncm_ndp16 * ncm0 ;
214
+ struct usb_cdc_ncm_dpe16 * dpe ;
215
+ struct ipheth_device * dev ;
216
+ int retval = - EINVAL ;
217
+ char * buf ;
218
+ int len ;
219
+
220
+ dev = urb -> context ;
221
+
222
+ if (urb -> actual_length < IPHETH_NCM_HEADER_SIZE ) {
223
+ dev -> net -> stats .rx_length_errors ++ ;
224
+ return retval ;
225
+ }
226
+
227
+ ncmh = urb -> transfer_buffer ;
228
+ if (ncmh -> dwSignature != cpu_to_le32 (USB_CDC_NCM_NTH16_SIGN ) ||
229
+ le16_to_cpu (ncmh -> wNdpIndex ) >= urb -> actual_length ) {
230
+ dev -> net -> stats .rx_errors ++ ;
231
+ return retval ;
232
+ }
233
+
234
+ ncm0 = urb -> transfer_buffer + le16_to_cpu (ncmh -> wNdpIndex );
235
+ if (ncm0 -> dwSignature != cpu_to_le32 (USB_CDC_NCM_NDP16_NOCRC_SIGN ) ||
236
+ le16_to_cpu (ncmh -> wHeaderLength ) + le16_to_cpu (ncm0 -> wLength ) >=
237
+ urb -> actual_length ) {
238
+ dev -> net -> stats .rx_errors ++ ;
239
+ return retval ;
240
+ }
241
+
242
+ dpe = ncm0 -> dpe16 ;
243
+ while (le16_to_cpu (dpe -> wDatagramIndex ) != 0 &&
244
+ le16_to_cpu (dpe -> wDatagramLength ) != 0 ) {
245
+ if (le16_to_cpu (dpe -> wDatagramIndex ) >= urb -> actual_length ||
246
+ le16_to_cpu (dpe -> wDatagramIndex ) +
247
+ le16_to_cpu (dpe -> wDatagramLength ) > urb -> actual_length ) {
248
+ dev -> net -> stats .rx_length_errors ++ ;
249
+ return retval ;
250
+ }
251
+
252
+ buf = urb -> transfer_buffer + le16_to_cpu (dpe -> wDatagramIndex );
253
+ len = le16_to_cpu (dpe -> wDatagramLength );
254
+
255
+ retval = ipheth_consume_skb (buf , len , dev );
256
+ if (retval != 0 )
257
+ return retval ;
258
+
259
+ dpe ++ ;
260
+ }
261
+
262
+ return 0 ;
263
+ }
264
+
265
+ static void ipheth_rcvbulk_callback (struct urb * urb )
266
+ {
267
+ struct ipheth_device * dev ;
268
+ int retval , status ;
269
+
171
270
dev = urb -> context ;
172
271
if (dev == NULL )
173
272
return ;
@@ -191,25 +290,27 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
191
290
dev -> net -> stats .rx_length_errors ++ ;
192
291
return ;
193
292
}
194
- len = urb -> actual_length - IPHETH_IP_ALIGN ;
195
- buf = urb -> transfer_buffer + IPHETH_IP_ALIGN ;
196
293
197
- skb = dev_alloc_skb (len );
198
- if (!skb ) {
199
- dev_err (& dev -> intf -> dev , "%s: dev_alloc_skb: -ENOMEM\n" ,
200
- __func__ );
201
- dev -> net -> stats .rx_dropped ++ ;
294
+ /* RX URBs starting with 0x00 0x01 do not encapsulate Ethernet frames,
295
+ * but rather are control frames. Their purpose is not documented, and
296
+ * they don't affect driver functionality, okay to drop them.
297
+ * There is usually just one 4-byte control frame as the very first
298
+ * URB received from the bulk IN endpoint.
299
+ */
300
+ if (unlikely
301
+ (((char * )urb -> transfer_buffer )[0 ] == 0 &&
302
+ ((char * )urb -> transfer_buffer )[1 ] == 1 ))
303
+ goto rx_submit ;
304
+
305
+ retval = dev -> rcvbulk_callback (urb );
306
+ if (retval != 0 ) {
307
+ dev_err (& dev -> intf -> dev , "%s: callback retval: %d\n" ,
308
+ __func__ , retval );
202
309
return ;
203
310
}
204
311
205
- skb_put_data (skb , buf , len );
206
- skb -> dev = dev -> net ;
207
- skb -> protocol = eth_type_trans (skb , dev -> net );
208
-
209
- dev -> net -> stats .rx_packets ++ ;
210
- dev -> net -> stats .rx_bytes += len ;
312
+ rx_submit :
211
313
dev -> confirmed_pairing = true;
212
- netif_rx (skb );
213
314
ipheth_rx_submit (dev , GFP_ATOMIC );
214
315
}
215
316
@@ -310,14 +411,35 @@ static int ipheth_get_macaddr(struct ipheth_device *dev)
310
411
return retval ;
311
412
}
312
413
414
+ static int ipheth_enable_ncm (struct ipheth_device * dev )
415
+ {
416
+ struct usb_device * udev = dev -> udev ;
417
+ int retval ;
418
+
419
+ retval = usb_control_msg (udev ,
420
+ usb_sndctrlpipe (udev , IPHETH_CTRL_ENDP ),
421
+ IPHETH_CMD_ENABLE_NCM , /* request */
422
+ 0x41 , /* request type */
423
+ 0x00 , /* value */
424
+ 0x02 , /* index */
425
+ NULL ,
426
+ 0 ,
427
+ IPHETH_CTRL_TIMEOUT );
428
+
429
+ dev_info (& dev -> intf -> dev , "%s: usb_control_msg: %d\n" ,
430
+ __func__ , retval );
431
+
432
+ return retval ;
433
+ }
434
+
313
435
static int ipheth_rx_submit (struct ipheth_device * dev , gfp_t mem_flags )
314
436
{
315
437
struct usb_device * udev = dev -> udev ;
316
438
int retval ;
317
439
318
440
usb_fill_bulk_urb (dev -> rx_urb , udev ,
319
441
usb_rcvbulkpipe (udev , dev -> bulk_in ),
320
- dev -> rx_buf , IPHETH_BUF_SIZE + IPHETH_IP_ALIGN ,
442
+ dev -> rx_buf , dev -> rx_buf_len ,
321
443
ipheth_rcvbulk_callback ,
322
444
dev );
323
445
dev -> rx_urb -> transfer_flags |= URB_NO_TRANSFER_DMA_MAP ;
@@ -365,7 +487,7 @@ static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net)
365
487
int retval ;
366
488
367
489
/* Paranoid */
368
- if (skb -> len > IPHETH_BUF_SIZE ) {
490
+ if (skb -> len > IPHETH_TX_BUF_SIZE ) {
369
491
WARN (1 , "%s: skb too large: %d bytes\n" , __func__ , skb -> len );
370
492
dev -> net -> stats .tx_dropped ++ ;
371
493
dev_kfree_skb_any (skb );
@@ -448,6 +570,8 @@ static int ipheth_probe(struct usb_interface *intf,
448
570
dev -> net = netdev ;
449
571
dev -> intf = intf ;
450
572
dev -> confirmed_pairing = false;
573
+ dev -> rx_buf_len = IPHETH_RX_BUF_SIZE_LEGACY ;
574
+ dev -> rcvbulk_callback = ipheth_rcvbulk_callback_legacy ;
451
575
/* Set up endpoints */
452
576
hintf = usb_altnum_to_altsetting (intf , IPHETH_ALT_INTFNUM );
453
577
if (hintf == NULL ) {
@@ -479,6 +603,12 @@ static int ipheth_probe(struct usb_interface *intf,
479
603
if (retval )
480
604
goto err_get_macaddr ;
481
605
606
+ retval = ipheth_enable_ncm (dev );
607
+ if (!retval ) {
608
+ dev -> rx_buf_len = IPHETH_RX_BUF_SIZE_NCM ;
609
+ dev -> rcvbulk_callback = ipheth_rcvbulk_callback_ncm ;
610
+ }
611
+
482
612
INIT_DELAYED_WORK (& dev -> carrier_work , ipheth_carrier_check_work );
483
613
484
614
retval = ipheth_alloc_urbs (dev );
0 commit comments