diff options
author | Daniel Gollub <dgollub@suse.de> | 2007-01-16 11:03:01 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-01-22 11:46:55 -0800 |
commit | deb31f1764e0a11bcfe8d44e0658f83d83860e84 (patch) | |
tree | 618d3ac0b7860b1ff58a43154db7f91fac180900 /drivers/usb | |
parent | d0ffff8fddd5853e4b2b101790ac0c3690655af5 (diff) |
USB: rndis_host: fix crash while probing a Nokia S60 mobile
Bug fix for driver rndis_host which fixes rndis_host probing certain
Nokia S60 (Series 60) mobiles. While the rndis_host get probed by usbnet
and tries to bind the Nokia mobile the bind is going to fail. The
rndis_host module tries to release the device, in a wrong way, which
cause the oops.
Fixes Bugzilla #7201
Signed-off-by: Daniel Gollub <dgollub@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/net/rndis_host.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index ea5f44de3de2..a322a16d9cf8 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -379,6 +379,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) { int retval; struct net_device *net = dev->net; + struct cdc_state *info = (void *) &dev->data; union { void *buf; struct rndis_msg_hdr *header; @@ -397,7 +398,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) - goto done; + goto fail; net->hard_header_len += sizeof (struct rndis_data_hdr); @@ -412,10 +413,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); -fail: - usb_driver_release_interface(driver_of(intf), - ((struct cdc_state *)&(dev->data))->data); - goto done; + goto fail_and_release; } dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); /* REVISIT: peripheral "alignment" request is ignored ... */ @@ -431,7 +429,7 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); - goto fail; + goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); if (unlikely((tmp + 8) > (1024 - ETH_ALEN) @@ -439,7 +437,7 @@ fail: dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); retval = -EDOM; - goto fail; + goto fail_and_release; } memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); @@ -455,11 +453,18 @@ fail: retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); - goto fail; + goto fail_and_release; } retval = 0; -done: + + kfree(u.buf); + return retval; + +fail_and_release: + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver_of(intf), info->data); +fail: kfree(u.buf); return retval; } |