Commit deb31f17 authored by Daniel Gollub's avatar Daniel Gollub Committed by Greg Kroah-Hartman

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: default avatarDaniel Gollub <dgollub@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d0ffff8f
...@@ -379,6 +379,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -379,6 +379,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{ {
int retval; int retval;
struct net_device *net = dev->net; struct net_device *net = dev->net;
struct cdc_state *info = (void *) &dev->data;
union { union {
void *buf; void *buf;
struct rndis_msg_hdr *header; struct rndis_msg_hdr *header;
...@@ -397,7 +398,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -397,7 +398,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
return -ENOMEM; return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf); retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0) if (retval < 0)
goto done; goto fail;
net->hard_header_len += sizeof (struct rndis_data_hdr); net->hard_header_len += sizeof (struct rndis_data_hdr);
...@@ -412,10 +413,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -412,10 +413,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
if (unlikely(retval < 0)) { if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */ /* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
fail: goto fail_and_release;
usb_driver_release_interface(driver_of(intf),
((struct cdc_state *)&(dev->data))->data);
goto done;
} }
dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
/* REVISIT: peripheral "alignment" request is ignored ... */ /* REVISIT: peripheral "alignment" request is ignored ... */
...@@ -431,7 +429,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -431,7 +429,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
retval = rndis_command(dev, u.header); retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) { if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
goto fail; goto fail_and_release;
} }
tmp = le32_to_cpu(u.get_c->offset); tmp = le32_to_cpu(u.get_c->offset);
if (unlikely((tmp + 8) > (1024 - ETH_ALEN) if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
...@@ -439,7 +437,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -439,7 +437,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len)); tmp, le32_to_cpu(u.get_c->len));
retval = -EDOM; retval = -EDOM;
goto fail; goto fail_and_release;
} }
memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN); memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
...@@ -455,11 +453,18 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -455,11 +453,18 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
retval = rndis_command(dev, u.header); retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) { if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
goto fail; goto fail_and_release;
} }
retval = 0; 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); kfree(u.buf);
return retval; return retval;
} }
......
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