diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/generic.c | 28 | ||||
-rw-r--r-- | drivers/usb/net/Kconfig | 6 | ||||
-rw-r--r-- | drivers/usb/net/cdc_ether.c | 60 | ||||
-rw-r--r-- | drivers/usb/net/rndis_host.c | 81 |
4 files changed, 144 insertions, 31 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index ebb20ff7ac58..b531a4fd30c2 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c | |||
@@ -25,6 +25,20 @@ static inline const char *plural(int n) | |||
25 | return (n == 1 ? "" : "s"); | 25 | return (n == 1 ? "" : "s"); |
26 | } | 26 | } |
27 | 27 | ||
28 | static int is_rndis(struct usb_interface_descriptor *desc) | ||
29 | { | ||
30 | return desc->bInterfaceClass == USB_CLASS_COMM | ||
31 | && desc->bInterfaceSubClass == 2 | ||
32 | && desc->bInterfaceProtocol == 0xff; | ||
33 | } | ||
34 | |||
35 | static int is_activesync(struct usb_interface_descriptor *desc) | ||
36 | { | ||
37 | return desc->bInterfaceClass == USB_CLASS_MISC | ||
38 | && desc->bInterfaceSubClass == 1 | ||
39 | && desc->bInterfaceProtocol == 1; | ||
40 | } | ||
41 | |||
28 | static int choose_configuration(struct usb_device *udev) | 42 | static int choose_configuration(struct usb_device *udev) |
29 | { | 43 | { |
30 | int i; | 44 | int i; |
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev) | |||
87 | continue; | 101 | continue; |
88 | } | 102 | } |
89 | 103 | ||
90 | /* If the first config's first interface is COMM/2/0xff | 104 | /* When the first config's first interface is one of Microsoft's |
91 | * (MSFT RNDIS), rule it out unless Linux has host-side | 105 | * pet nonstandard Ethernet-over-USB protocols, ignore it unless |
92 | * RNDIS support. */ | 106 | * this kernel has enabled the necessary host side driver. |
93 | if (i == 0 && desc | 107 | */ |
94 | && desc->bInterfaceClass == USB_CLASS_COMM | 108 | if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) { |
95 | && desc->bInterfaceSubClass == 2 | 109 | #if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) |
96 | && desc->bInterfaceProtocol == 0xff) { | ||
97 | #ifndef CONFIG_USB_NET_RNDIS_HOST | ||
98 | continue; | 110 | continue; |
99 | #else | 111 | #else |
100 | best = c; | 112 | best = c; |
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 | ||
224 | config USB_NET_RNDIS_HOST | 224 | config 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 | |||
41 | static 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 | |||
48 | static 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/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 | */ |
65 | struct rndis_msg_hdr { | 70 | struct 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) | |||
270 | static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) | 281 | static 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 | }; |