aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-07 22:23:21 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-07 22:23:21 -0500
commitc96e2c92072d3e78954c961f53d8c7352f7abbd7 (patch)
treed844f26f926ff40e98e9eae0e11fd71acad81df4 /drivers/usb/net
parentf2aca47dc3c2d0c2d5dbd972558557e74232bbce (diff)
parent64358164f5bfe5e11d4040c1eb674c29e1436ce5 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (70 commits) USB: remove duplicate device id from zc0301 USB: remove duplicate device id from usb_storage USB: remove duplicate device id from keyspan USB: remove duplicate device id from ftdi_sio USB: remove duplicate device id from visor USB: a bit more coding style cleanup usbcore: trivial whitespace fixes usb-storage: use first bulk endpoints, not last EHCI: fix interrupt-driven remote wakeup USB: switch ehci-hcd to new polling scheme USB: autosuspend for usb printer driver USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products USB: Sierra Wireless auto set D0 USB: usb ethernet gadget recognizes HUSB2DEV USB: list atmel husb2_udc gadget controller USB: gadgetfs AIO tweaks USB: gadgetfs behaves better on userspace init bug USB: gadgetfs race fix USB: gadgetfs simplifications USB: gadgetfs cleanups ...
Diffstat (limited to 'drivers/usb/net')
-rw-r--r--drivers/usb/net/Kconfig6
-rw-r--r--drivers/usb/net/cdc_ether.c60
-rw-r--r--drivers/usb/net/kaweth.c37
-rw-r--r--drivers/usb/net/rndis_host.c81
4 files changed, 156 insertions, 28 deletions
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index e081836014ac..a2b94ef512bc 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -222,13 +222,15 @@ config USB_NET_MCS7830
222 adapters marketed under the DeLOCK brand. 222 adapters marketed under the DeLOCK brand.
223 223
224config USB_NET_RNDIS_HOST 224config USB_NET_RNDIS_HOST
225 tristate "Host for RNDIS devices (EXPERIMENTAL)" 225 tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
226 depends on USB_USBNET && EXPERIMENTAL 226 depends on USB_USBNET && EXPERIMENTAL
227 select USB_NET_CDCETHER 227 select USB_NET_CDCETHER
228 help 228 help
229 This option enables hosting "Remote NDIS" USB networking links, 229 This option enables hosting "Remote NDIS" USB networking links,
230 as encouraged by Microsoft (instead of CDC Ethernet!) for use in 230 as encouraged by Microsoft (instead of CDC Ethernet!) for use in
231 various devices that may only support this protocol. 231 various devices that may only support this protocol. A variant
232 of this protocol (with even less public documentation) seems to
233 be at the root of Microsoft's "ActiveSync" too.
232 234
233 Avoid using this protocol unless you have no better options. 235 Avoid using this protocol unless you have no better options.
234 The protocol specification is incomplete, and is controlled by 236 The protocol specification is incomplete, and is controlled by
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a91547146e..e5cdafa258dd 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * CDC Ethernet based networking peripherals 2 * CDC Ethernet based networking peripherals
3 * Copyright (C) 2003-2005 by David Brownell 3 * Copyright (C) 2003-2005 by David Brownell
4 * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
4 * 5 *
5 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -35,6 +36,29 @@
35#include "usbnet.h" 36#include "usbnet.h"
36 37
37 38
39#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
40
41static int is_rndis(struct usb_interface_descriptor *desc)
42{
43 return desc->bInterfaceClass == USB_CLASS_COMM
44 && desc->bInterfaceSubClass == 2
45 && desc->bInterfaceProtocol == 0xff;
46}
47
48static int is_activesync(struct usb_interface_descriptor *desc)
49{
50 return desc->bInterfaceClass == USB_CLASS_MISC
51 && desc->bInterfaceSubClass == 1
52 && desc->bInterfaceProtocol == 1;
53}
54
55#else
56
57#define is_rndis(desc) 0
58#define is_activesync(desc) 0
59
60#endif
61
38/* 62/*
39 * probes control interface, claims data interface, collects the bulk 63 * probes control interface, claims data interface, collects the bulk
40 * endpoints, activates data interface (if needed), maybe sets MTU. 64 * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
71 /* this assumes that if there's a non-RNDIS vendor variant 95 /* this assumes that if there's a non-RNDIS vendor variant
72 * of cdc-acm, it'll fail RNDIS requests cleanly. 96 * of cdc-acm, it'll fail RNDIS requests cleanly.
73 */ 97 */
74 rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); 98 rndis = is_rndis(&intf->cur_altsetting->desc)
99 || is_activesync(&intf->cur_altsetting->desc);
75 100
76 memset(info, 0, sizeof *info); 101 memset(info, 0, sizeof *info);
77 info->control = intf; 102 info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
99 goto bad_desc; 124 goto bad_desc;
100 } 125 }
101 break; 126 break;
127 case USB_CDC_ACM_TYPE:
128 /* paranoia: disambiguate a "real" vendor-specific
129 * modem interface from an RNDIS non-modem.
130 */
131 if (rndis) {
132 struct usb_cdc_acm_descriptor *d;
133
134 d = (void *) buf;
135 if (d->bmCapabilities) {
136 dev_dbg(&intf->dev,
137 "ACM capabilities %02x, "
138 "not really RNDIS?\n",
139 d->bmCapabilities);
140 goto bad_desc;
141 }
142 }
143 break;
102 case USB_CDC_UNION_TYPE: 144 case USB_CDC_UNION_TYPE:
103 if (info->u) { 145 if (info->u) {
104 dev_dbg(&intf->dev, "extra CDC union\n"); 146 dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
171 buf += buf [0]; 213 buf += buf [0];
172 } 214 }
173 215
174 if (!info->header || !info->u || (!rndis && !info->ether)) { 216 /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
217 * so we'll hard-wire the interfaces and not check for descriptors.
218 */
219 if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
220 info->control = usb_ifnum_to_if(dev->udev, 0);
221 info->data = usb_ifnum_to_if(dev->udev, 1);
222 if (!info->control || !info->data) {
223 dev_dbg(&intf->dev,
224 "activesync: master #0/%p slave #1/%p\n",
225 info->control,
226 info->data);
227 goto bad_desc;
228 }
229
230 } else if (!info->header || !info->u || (!rndis && !info->ether)) {
175 dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", 231 dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
176 info->header ? "" : "header ", 232 info->header ? "" : "header ",
177 info->u ? "" : "union ", 233 info->u ? "" : "union ",
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326d0bf0..36a989160a68 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
179 .suspend = kaweth_suspend, 179 .suspend = kaweth_suspend,
180 .resume = kaweth_resume, 180 .resume = kaweth_resume,
181 .id_table = usb_klsi_table, 181 .id_table = usb_klsi_table,
182 .supports_autosuspend = 1,
182}; 183};
183 184
184typedef __u8 eth_addr_t[6]; 185typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
225 struct delayed_work lowmem_work; 226 struct delayed_work lowmem_work;
226 227
227 struct usb_device *dev; 228 struct usb_device *dev;
229 struct usb_interface *intf;
228 struct net_device *net; 230 struct net_device *net;
229 wait_queue_head_t term_wait; 231 wait_queue_head_t term_wait;
230 232
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
662 664
663 dbg("Opening network device."); 665 dbg("Opening network device.");
664 666
667 res = usb_autopm_get_interface(kaweth->intf);
668 if (res) {
669 err("Interface cannot be resumed.");
670 return -EIO;
671 }
665 res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); 672 res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
666 if (res) 673 if (res)
667 return -EIO; 674 goto err_out;
668 675
669 usb_fill_int_urb( 676 usb_fill_int_urb(
670 kaweth->irq_urb, 677 kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
681 res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); 688 res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
682 if (res) { 689 if (res) {
683 usb_kill_urb(kaweth->rx_urb); 690 usb_kill_urb(kaweth->rx_urb);
684 return -EIO; 691 goto err_out;
685 } 692 }
686 kaweth->opened = 1; 693 kaweth->opened = 1;
687 694
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
689 696
690 kaweth_async_set_rx_mode(kaweth); 697 kaweth_async_set_rx_mode(kaweth);
691 return 0; 698 return 0;
699
700err_out:
701 usb_autopm_enable(kaweth->intf);
702 return -EIO;
692} 703}
693 704
694/**************************************************************** 705/****************************************************************
695 * kaweth_close 706 * kaweth_kill_urbs
696 ****************************************************************/ 707 ****************************************************************/
697static void kaweth_kill_urbs(struct kaweth_device *kaweth) 708static void kaweth_kill_urbs(struct kaweth_device *kaweth)
698{ 709{
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
724 735
725 kaweth->status &= ~KAWETH_STATUS_CLOSING; 736 kaweth->status &= ~KAWETH_STATUS_CLOSING;
726 737
738 usb_autopm_enable(kaweth->intf);
739
727 return 0; 740 return 0;
728} 741}
729 742
730static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 743static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
731{ 744{
745 struct kaweth_device *kaweth = netdev_priv(dev);
732 746
733 strlcpy(info->driver, driver_name, sizeof(info->driver)); 747 strlcpy(info->driver, driver_name, sizeof(info->driver));
748 usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
749}
750
751static u32 kaweth_get_link(struct net_device *dev)
752{
753 struct kaweth_device *kaweth = netdev_priv(dev);
754
755 return kaweth->linkstate;
734} 756}
735 757
736static struct ethtool_ops ops = { 758static struct ethtool_ops ops = {
737 .get_drvinfo = kaweth_get_drvinfo 759 .get_drvinfo = kaweth_get_drvinfo,
760 .get_link = kaweth_get_link
738}; 761};
739 762
740/**************************************************************** 763/****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
908 struct kaweth_device *kaweth = usb_get_intfdata(intf); 931 struct kaweth_device *kaweth = usb_get_intfdata(intf);
909 unsigned long flags; 932 unsigned long flags;
910 933
934 dbg("Suspending device");
911 spin_lock_irqsave(&kaweth->device_lock, flags); 935 spin_lock_irqsave(&kaweth->device_lock, flags);
912 kaweth->status |= KAWETH_STATUS_SUSPENDING; 936 kaweth->status |= KAWETH_STATUS_SUSPENDING;
913 spin_unlock_irqrestore(&kaweth->device_lock, flags); 937 spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
924 struct kaweth_device *kaweth = usb_get_intfdata(intf); 948 struct kaweth_device *kaweth = usb_get_intfdata(intf);
925 unsigned long flags; 949 unsigned long flags;
926 950
951 dbg("Resuming device");
927 spin_lock_irqsave(&kaweth->device_lock, flags); 952 spin_lock_irqsave(&kaweth->device_lock, flags);
928 kaweth->status &= ~KAWETH_STATUS_SUSPENDING; 953 kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
929 spin_unlock_irqrestore(&kaweth->device_lock, flags); 954 spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
1086 1111
1087 dbg("Initializing net device."); 1112 dbg("Initializing net device.");
1088 1113
1114 kaweth->intf = intf;
1115
1089 kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 1116 kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
1090 if (!kaweth->tx_urb) 1117 if (!kaweth->tx_urb)
1091 goto err_free_netdev; 1118 goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
1265{ 1292{
1266 struct urb *urb; 1293 struct urb *urb;
1267 int retv; 1294 int retv;
1268 int length; 1295 int length = 0; /* shut up GCC */
1269 1296
1270 urb = usb_alloc_urb(0, GFP_NOIO); 1297 urb = usb_alloc_urb(0, GFP_NOIO);
1271 if (!urb) 1298 if (!urb)
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index a322a16d9cf8..be888d2d813c 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -49,6 +49,8 @@
49 * - In some cases, MS-Windows will emit undocumented requests; this 49 * - In some cases, MS-Windows will emit undocumented requests; this
50 * matters more to peripheral implementations than host ones. 50 * matters more to peripheral implementations than host ones.
51 * 51 *
52 * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
53 *
52 * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in 54 * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
53 * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and 55 * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
54 * currently rare) "Ethernet Emulation Model" (EEM). 56 * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
61 * - control-in: GET_ENCAPSULATED 63 * - control-in: GET_ENCAPSULATED
62 * 64 *
63 * We'll try to ignore the RESPONSE_AVAILABLE notifications. 65 * We'll try to ignore the RESPONSE_AVAILABLE notifications.
66 *
67 * REVISIT some RNDIS implementations seem to have curious issues still
68 * to be resolved.
64 */ 69 */
65struct rndis_msg_hdr { 70struct rndis_msg_hdr {
66 __le32 msg_type; /* RNDIS_MSG_* */ 71 __le32 msg_type; /* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
71 // ... and more 76 // ... and more
72} __attribute__ ((packed)); 77} __attribute__ ((packed));
73 78
74/* RNDIS defines this (absurdly huge) control timeout */ 79/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
75#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000) 80#define CONTROL_BUFFER_SIZE 1025
81
82/* RNDIS defines an (absurdly huge) 10 second control timeout,
83 * but ActiveSync seems to use a more usual 5 second timeout
84 * (which matches the USB 2.0 spec).
85 */
86#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
76 87
77 88
78#define ccpu2 __constant_cpu_to_le32 89#define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
270static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) 281static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
271{ 282{
272 struct cdc_state *info = (void *) &dev->data; 283 struct cdc_state *info = (void *) &dev->data;
284 int master_ifnum;
273 int retval; 285 int retval;
274 unsigned count; 286 unsigned count;
275 __le32 rsp; 287 __le32 rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
279 * disconnect(): either serialize, or dispatch responses on xid 291 * disconnect(): either serialize, or dispatch responses on xid
280 */ 292 */
281 293
282 /* Issue the request; don't bother byteswapping our xid */ 294 /* Issue the request; xid is unique, don't bother byteswapping it */
283 if (likely(buf->msg_type != RNDIS_MSG_HALT 295 if (likely(buf->msg_type != RNDIS_MSG_HALT
284 && buf->msg_type != RNDIS_MSG_RESET)) { 296 && buf->msg_type != RNDIS_MSG_RESET)) {
285 xid = dev->xid++; 297 xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
287 xid = dev->xid++; 299 xid = dev->xid++;
288 buf->request_id = (__force __le32) xid; 300 buf->request_id = (__force __le32) xid;
289 } 301 }
302 master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
290 retval = usb_control_msg(dev->udev, 303 retval = usb_control_msg(dev->udev,
291 usb_sndctrlpipe(dev->udev, 0), 304 usb_sndctrlpipe(dev->udev, 0),
292 USB_CDC_SEND_ENCAPSULATED_COMMAND, 305 USB_CDC_SEND_ENCAPSULATED_COMMAND,
293 USB_TYPE_CLASS | USB_RECIP_INTERFACE, 306 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
294 0, info->u->bMasterInterface0, 307 0, master_ifnum,
295 buf, le32_to_cpu(buf->msg_len), 308 buf, le32_to_cpu(buf->msg_len),
296 RNDIS_CONTROL_TIMEOUT_MS); 309 RNDIS_CONTROL_TIMEOUT_MS);
297 if (unlikely(retval < 0 || xid == 0)) 310 if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
306 */ 319 */
307 rsp = buf->msg_type | RNDIS_MSG_COMPLETION; 320 rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
308 for (count = 0; count < 10; count++) { 321 for (count = 0; count < 10; count++) {
309 memset(buf, 0, 1024); 322 memset(buf, 0, CONTROL_BUFFER_SIZE);
310 retval = usb_control_msg(dev->udev, 323 retval = usb_control_msg(dev->udev,
311 usb_rcvctrlpipe(dev->udev, 0), 324 usb_rcvctrlpipe(dev->udev, 0),
312 USB_CDC_GET_ENCAPSULATED_RESPONSE, 325 USB_CDC_GET_ENCAPSULATED_RESPONSE,
313 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 326 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
314 0, info->u->bMasterInterface0, 327 0, master_ifnum,
315 buf, 1024, 328 buf, CONTROL_BUFFER_SIZE,
316 RNDIS_CONTROL_TIMEOUT_MS); 329 RNDIS_CONTROL_TIMEOUT_MS);
317 if (likely(retval >= 8)) { 330 if (likely(retval >= 8)) {
318 msg_len = le32_to_cpu(buf->msg_len); 331 msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
350 usb_sndctrlpipe(dev->udev, 0), 363 usb_sndctrlpipe(dev->udev, 0),
351 USB_CDC_SEND_ENCAPSULATED_COMMAND, 364 USB_CDC_SEND_ENCAPSULATED_COMMAND,
352 USB_TYPE_CLASS | USB_RECIP_INTERFACE, 365 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
353 0, info->u->bMasterInterface0, 366 0, master_ifnum,
354 msg, sizeof *msg, 367 msg, sizeof *msg,
355 RNDIS_CONTROL_TIMEOUT_MS); 368 RNDIS_CONTROL_TIMEOUT_MS);
356 if (unlikely(retval < 0)) 369 if (unlikely(retval < 0))
@@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
393 u32 tmp; 406 u32 tmp;
394 407
395 /* we can't rely on i/o from stack working, or stack allocation */ 408 /* we can't rely on i/o from stack working, or stack allocation */
396 u.buf = kmalloc(1024, GFP_KERNEL); 409 u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
397 if (!u.buf) 410 if (!u.buf)
398 return -ENOMEM; 411 return -ENOMEM;
399 retval = usbnet_generic_cdc_bind(dev, intf); 412 retval = usbnet_generic_cdc_bind(dev, intf);
400 if (retval < 0) 413 if (retval < 0)
401 goto fail; 414 goto fail;
402 415
403 net->hard_header_len += sizeof (struct rndis_data_hdr);
404
405 /* initialize; max transfer is 16KB at full speed */
406 u.init->msg_type = RNDIS_MSG_INIT; 416 u.init->msg_type = RNDIS_MSG_INIT;
407 u.init->msg_len = ccpu2(sizeof *u.init); 417 u.init->msg_len = ccpu2(sizeof *u.init);
408 u.init->major_version = ccpu2(1); 418 u.init->major_version = ccpu2(1);
409 u.init->minor_version = ccpu2(0); 419 u.init->minor_version = ccpu2(0);
410 u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
411 420
421 /* max transfer (in spec) is 0x4000 at full speed, but for
422 * TX we'll stick to one Ethernet packet plus RNDIS framing.
423 * For RX we handle drivers that zero-pad to end-of-packet.
424 * Don't let userspace change these settings.
425 */
426 net->hard_header_len += sizeof (struct rndis_data_hdr);
427 dev->hard_mtu = net->mtu + net->hard_header_len;
428
429 dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
430 dev->rx_urb_size &= ~(dev->maxpacket - 1);
431 u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
432
433 net->change_mtu = NULL;
412 retval = rndis_command(dev, u.header); 434 retval = rndis_command(dev, u.header);
413 if (unlikely(retval < 0)) { 435 if (unlikely(retval < 0)) {
414 /* it might not even be an RNDIS device!! */ 436 /* it might not even be an RNDIS device!! */
415 dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); 437 dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
438 goto fail_and_release;
439 }
440 tmp = le32_to_cpu(u.init_c->max_transfer_size);
441 if (tmp < dev->hard_mtu) {
442 dev_err(&intf->dev,
443 "dev can't take %u byte packets (max %u)\n",
444 dev->hard_mtu, tmp);
416 goto fail_and_release; 445 goto fail_and_release;
417 } 446 }
418 dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); 447
419 /* REVISIT: peripheral "alignment" request is ignored ... */ 448 /* REVISIT: peripheral "alignment" request is ignored ... */
420 dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu, 449 dev_dbg(&intf->dev,
450 "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
451 dev->hard_mtu, tmp, dev->rx_urb_size,
421 1 << le32_to_cpu(u.init_c->packet_alignment)); 452 1 << le32_to_cpu(u.init_c->packet_alignment));
422 453
423 /* get designated host ethernet address */ 454 /* Get designated host ethernet address.
424 memset(u.get, 0, sizeof *u.get); 455 *
456 * Adding a payload exactly the same size as the expected response
457 * payload is an evident requirement MSFT added for ActiveSync.
458 * This undocumented (and nonsensical) issue was found by sniffing
459 * protocol requests from the ActiveSync 4.1 Windows driver.
460 */
461 memset(u.get, 0, sizeof *u.get + 48);
425 u.get->msg_type = RNDIS_MSG_QUERY; 462 u.get->msg_type = RNDIS_MSG_QUERY;
426 u.get->msg_len = ccpu2(sizeof *u.get); 463 u.get->msg_len = ccpu2(sizeof *u.get + 48);
427 u.get->oid = OID_802_3_PERMANENT_ADDRESS; 464 u.get->oid = OID_802_3_PERMANENT_ADDRESS;
465 u.get->len = ccpu2(48);
466 u.get->offset = ccpu2(20);
428 467
429 retval = rndis_command(dev, u.header); 468 retval = rndis_command(dev, u.header);
430 if (unlikely(retval < 0)) { 469 if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
432 goto fail_and_release; 471 goto fail_and_release;
433 } 472 }
434 tmp = le32_to_cpu(u.get_c->offset); 473 tmp = le32_to_cpu(u.get_c->offset);
435 if (unlikely((tmp + 8) > (1024 - ETH_ALEN) 474 if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
436 || u.get_c->len != ccpu2(ETH_ALEN))) { 475 || u.get_c->len != ccpu2(ETH_ALEN))) {
437 dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", 476 dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
438 tmp, le32_to_cpu(u.get_c->len)); 477 tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@ static const struct usb_device_id products [] = {
598 /* RNDIS is MSFT's un-official variant of CDC ACM */ 637 /* RNDIS is MSFT's un-official variant of CDC ACM */
599 USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), 638 USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
600 .driver_info = (unsigned long) &rndis_info, 639 .driver_info = (unsigned long) &rndis_info,
640}, {
641 /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
642 USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
643 .driver_info = (unsigned long) &rndis_info,
601}, 644},
602 { }, // END 645 { }, // END
603}; 646};