diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 56 | 
1 files changed, 27 insertions, 29 deletions
| diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 546a17e8ad5b..683617714e7c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf,  	unsigned long quirks;  	int num_rx_buf;  	int i; +	unsigned int elength = 0;  	int combined_interfaces = 0;  	struct device *tty_dev;  	int rv = -ENOMEM; @@ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf,  			dev_err(&intf->dev, "skipping garbage\n");  			goto next_desc;  		} +		elength = buffer[0];  		switch (buffer[2]) {  		case USB_CDC_UNION_TYPE: /* we've found it */ +			if (elength < sizeof(struct usb_cdc_union_desc)) +				goto next_desc;  			if (union_header) {  				dev_err(&intf->dev, "More than one "  					"union descriptor, skipping ...\n"); @@ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf,  			union_header = (struct usb_cdc_union_desc *)buffer;  			break;  		case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ +			if (elength < sizeof(struct usb_cdc_country_functional_desc)) +				goto next_desc;  			cfd = (struct usb_cdc_country_functional_desc *)buffer;  			break;  		case USB_CDC_HEADER_TYPE: /* maybe check version */  			break; /* for now we ignore it */  		case USB_CDC_ACM_TYPE: +			if (elength < 4) +				goto next_desc;  			ac_management_function = buffer[3];  			break;  		case USB_CDC_CALL_MANAGEMENT_TYPE: +			if (elength < 5) +				goto next_desc;  			call_management_function = buffer[3];  			call_interface_num = buffer[4];  			break;  		default: -			/* there are LOTS more CDC descriptors that +			/* +			 * there are LOTS more CDC descriptors that  			 * could legitimately be found here.  			 */  			dev_dbg(&intf->dev, "Ignoring descriptor: " -					"type %02x, length %d\n", -					buffer[2], buffer[0]); +					"type %02x, length %ud\n", +					buffer[2], elength);  			break;  		}  next_desc: -		buflen -= buffer[0]; -		buffer += buffer[0]; +		buflen -= elength; +		buffer += elength;  	}  	if (!union_header) { @@ -1287,10 +1298,8 @@ made_compressed_probe:  	dev_dbg(&intf->dev, "interfaces are valid\n");  	acm = kzalloc(sizeof(struct acm), GFP_KERNEL); -	if (acm == NULL) { -		dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); +	if (acm == NULL)  		goto alloc_fail; -	}  	minor = acm_alloc_minor(acm);  	if (minor == ACM_TTY_MINORS) { @@ -1329,42 +1338,32 @@ made_compressed_probe:  	acm->quirks = quirks;  	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); -	if (!buf) { -		dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); +	if (!buf)  		goto alloc_fail2; -	}  	acm->ctrl_buffer = buf; -	if (acm_write_buffers_alloc(acm) < 0) { -		dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); +	if (acm_write_buffers_alloc(acm) < 0)  		goto alloc_fail4; -	}  	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); -	if (!acm->ctrlurb) { -		dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); +	if (!acm->ctrlurb)  		goto alloc_fail5; -	} +  	for (i = 0; i < num_rx_buf; i++) {  		struct acm_rb *rb = &(acm->read_buffers[i]);  		struct urb *urb;  		rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,  								&rb->dma); -		if (!rb->base) { -			dev_err(&intf->dev, "out of memory " -					"(read bufs usb_alloc_coherent)\n"); +		if (!rb->base)  			goto alloc_fail6; -		}  		rb->index = i;  		rb->instance = acm;  		urb = usb_alloc_urb(0, GFP_KERNEL); -		if (!urb) { -			dev_err(&intf->dev, -				"out of memory (read urbs usb_alloc_urb)\n"); +		if (!urb)  			goto alloc_fail6; -		} +  		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  		urb->transfer_dma = rb->dma;  		if (acm->is_int_ep) { @@ -1389,11 +1388,8 @@ made_compressed_probe:  		struct acm_wb *snd = &(acm->wb[i]);  		snd->urb = usb_alloc_urb(0, GFP_KERNEL); -		if (snd->urb == NULL) { -			dev_err(&intf->dev, -				"out of memory (write urbs usb_alloc_urb)\n"); +		if (snd->urb == NULL)  			goto alloc_fail7; -		}  		if (usb_endpoint_xfer_int(epwrite))  			usb_fill_int_urb(snd->urb, usb_dev, @@ -1654,6 +1650,8 @@ static int acm_reset_resume(struct usb_interface *intf)  static const struct usb_device_id acm_ids[] = {  	/* quirky and broken devices */ +	{ USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */ +	.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */  	{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */  	.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */  	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ |