Commit 823bd343 authored by Oliver Neukum's avatar Oliver Neukum Committed by David S. Miller

cdc-ether: switch to common CDC parser

This patch uses the common parser to parse extra CDC
headers in order to reduce code duplication.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 77b0a099
...@@ -112,8 +112,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -112,8 +112,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
int rndis; int rndis;
bool android_rndis_quirk = false; bool android_rndis_quirk = false;
struct usb_driver *driver = driver_of(intf); struct usb_driver *driver = driver_of(intf);
struct usb_cdc_mdlm_desc *desc = NULL; struct usb_cdc_parsed_header header;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
if (sizeof(dev->data) < sizeof(*info)) if (sizeof(dev->data) < sizeof(*info))
return -EDOM; return -EDOM;
...@@ -155,59 +154,12 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -155,59 +154,12 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
info->control = intf; info->control = intf;
while (len > 3) {
if (buf[1] != USB_DT_CS_INTERFACE)
goto next_desc;
/* use bDescriptorSubType to identify the CDC descriptors.
* We expect devices with CDC header and union descriptors.
* For CDC Ethernet we need the ethernet descriptor.
* For RNDIS, ignore two (pointless) CDC modem descriptors
* in favor of a complicated OID-based RPC scheme doing what
* CDC Ethernet achieves with a simple descriptor.
*/
switch (buf[2]) {
case USB_CDC_HEADER_TYPE:
if (info->header) {
dev_dbg(&intf->dev, "extra CDC header\n");
goto bad_desc;
}
info->header = (void *) buf;
if (info->header->bLength != sizeof(*info->header)) {
dev_dbg(&intf->dev, "CDC header len %u\n",
info->header->bLength);
goto bad_desc;
}
break;
case USB_CDC_ACM_TYPE:
/* paranoia: disambiguate a "real" vendor-specific
* modem interface from an RNDIS non-modem.
*/
if (rndis) {
struct usb_cdc_acm_descriptor *acm;
acm = (void *) buf; cdc_parse_cdc_header(&header, intf, buf, len);
if (acm->bmCapabilities) {
dev_dbg(&intf->dev,
"ACM capabilities %02x, "
"not really RNDIS?\n",
acm->bmCapabilities);
goto bad_desc;
}
}
break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
goto bad_desc;
}
info->u = (void *) buf;
if (info->u->bLength != sizeof(*info->u)) {
dev_dbg(&intf->dev, "CDC union len %u\n",
info->u->bLength);
goto bad_desc;
}
info->u = header.usb_cdc_union_desc;
info->header = header.usb_cdc_header_desc;
info->ether = header.usb_cdc_ether_desc;
/* we need a master/control interface (what we're /* we need a master/control interface (what we're
* probed with) and a slave/data interface; union * probed with) and a slave/data interface; union
* descriptors sort this all out. * descriptors sort this all out.
...@@ -226,7 +178,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -226,7 +178,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* fall back to hard-wiring for RNDIS */ /* fall back to hard-wiring for RNDIS */
if (rndis) { if (rndis) {
android_rndis_quirk = true; android_rndis_quirk = true;
goto next_desc; goto skip;
} }
goto bad_desc; goto bad_desc;
} }
...@@ -244,7 +196,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -244,7 +196,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* some devices merge these - skip class check */ /* some devices merge these - skip class check */
if (info->control == info->data) if (info->control == info->data)
goto next_desc; goto skip;
/* a data interface altsetting does the real i/o */ /* a data interface altsetting does the real i/o */
d = &info->data->cur_altsetting->desc; d = &info->data->cur_altsetting->desc;
...@@ -253,57 +205,37 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -253,57 +205,37 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
d->bInterfaceClass); d->bInterfaceClass);
goto bad_desc; goto bad_desc;
} }
break; skip:
case USB_CDC_ETHERNET_TYPE: if ( rndis &&
if (info->ether) { header.usb_cdc_acm_descriptor &&
dev_dbg(&intf->dev, "extra CDC ether\n"); header.usb_cdc_acm_descriptor->bmCapabilities) {
goto bad_desc; dev_dbg(&intf->dev,
} "ACM capabilities %02x, not really RNDIS?\n",
info->ether = (void *) buf; header.usb_cdc_acm_descriptor->bmCapabilities);
if (info->ether->bLength != sizeof(*info->ether)) {
dev_dbg(&intf->dev, "CDC ether len %u\n",
info->ether->bLength);
goto bad_desc; goto bad_desc;
} }
dev->hard_mtu = le16_to_cpu(
info->ether->wMaxSegmentSize); if (header.usb_cdc_ether_desc) {
dev->hard_mtu = le16_to_cpu(info->ether->wMaxSegmentSize);
/* because of Zaurus, we may be ignoring the host /* because of Zaurus, we may be ignoring the host
* side link address we were given. * side link address we were given.
*/ */
break;
case USB_CDC_MDLM_TYPE:
if (desc) {
dev_dbg(&intf->dev, "extra MDLM descriptor\n");
goto bad_desc;
} }
desc = (void *)buf; if (header.usb_cdc_mdlm_desc &&
memcmp(header.usb_cdc_mdlm_desc->bGUID, mbm_guid, 16)) {
if (desc->bLength != sizeof(*desc)) dev_dbg(&intf->dev, "GUID doesn't match\n");
goto bad_desc; goto bad_desc;
}
if (memcmp(&desc->bGUID, mbm_guid, 16)) if (header.usb_cdc_mdlm_detail_desc &&
goto bad_desc; header.usb_cdc_mdlm_detail_desc->bLength <
break; (sizeof(struct usb_cdc_mdlm_detail_desc) + 1)) {
case USB_CDC_MDLM_DETAIL_TYPE: dev_dbg(&intf->dev, "Descriptor too short\n");
if (detail) {
dev_dbg(&intf->dev, "extra MDLM detail descriptor\n");
goto bad_desc; goto bad_desc;
} }
detail = (void *)buf;
if (detail->bGuidDescriptorType == 0) {
if (detail->bLength < (sizeof(*detail) + 1))
goto bad_desc;
} else
goto bad_desc;
break;
}
next_desc:
len -= buf[0]; /* bLength */
buf += buf[0];
}
/* Microsoft ActiveSync based and some regular RNDIS devices lack the /* Microsoft ActiveSync based and some regular RNDIS devices lack the
* CDC descriptors, so we'll hard-wire the interfaces and not check * CDC descriptors, so we'll hard-wire the interfaces and not check
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment