Commit 93993a0a authored by Inaky Perez-Gonzalez's avatar Inaky Perez-Gonzalez Committed by Greg Kroah-Hartman

usb: introduce usb_authorize/deauthorize()

These USB API functions will do the full authorization/deauthorization
to be used for a device. When authorized we effectively allow a
configuration to be set. Reverse that when deauthorized.

Effectively this means that we have to clean all the configuration
descriptors on deauthorize and reload them when we authorized. We could
do without throwing them out for wired devices, but for wireless, we can
read them only after authenticating, and thus, when authorizing an
authenticated device we would need to read them. So to simplify, always
release them on deauthorize(), re-read them on authorize().

Also fix leak reported by Ragner Magalhaes; in usb_deauthorize_device(),
bNumConfigurations was being set to zero before the for loop, and thus
the different raw descriptors where never being freed.
Signed-off-by: default avatarInaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d9d16e8a
...@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) ...@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1; && desc->bInterfaceProtocol == 1;
} }
static int choose_configuration(struct usb_device *udev) int choose_configuration(struct usb_device *udev)
{ {
int i; int i;
int num_configs; int num_configs;
......
...@@ -1399,6 +1399,87 @@ int usb_new_device(struct usb_device *udev) ...@@ -1399,6 +1399,87 @@ int usb_new_device(struct usb_device *udev)
return err; return err;
} }
/**
* Similar to usb_disconnect()
*
* We share a lock (that we have) with device_del(), so we need to
* defer its call.
*/
int usb_deauthorize_device(struct usb_device *usb_dev)
{
unsigned cnt;
usb_lock_device(usb_dev);
if (usb_dev->authorized == 0)
goto out_unauthorized;
usb_dev->authorized = 0;
usb_set_configuration(usb_dev, -1);
usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
kfree(usb_dev->config);
usb_dev->config = NULL;
for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
kfree(usb_dev->rawdescriptors[cnt]);
usb_dev->descriptor.bNumConfigurations = 0;
kfree(usb_dev->rawdescriptors);
out_unauthorized:
usb_unlock_device(usb_dev);
return 0;
}
int usb_authorize_device(struct usb_device *usb_dev)
{
int result = 0, c;
usb_lock_device(usb_dev);
if (usb_dev->authorized == 1)
goto out_authorized;
kfree(usb_dev->product);
usb_dev->product = NULL;
kfree(usb_dev->manufacturer);
usb_dev->manufacturer = NULL;
kfree(usb_dev->serial);
usb_dev->serial = NULL;
result = usb_autoresume_device(usb_dev);
if (result < 0) {
dev_err(&usb_dev->dev,
"can't autoresume for authorization: %d\n", result);
goto error_autoresume;
}
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
if (result < 0) {
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
"authorization: %d\n", result);
goto error_device_descriptor;
}
usb_dev->authorized = 1;
result = usb_configure_device(usb_dev);
if (result < 0)
goto error_configure;
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
c = choose_configuration(usb_dev);
if (c >= 0) {
result = usb_set_configuration(usb_dev, c);
if (result) {
dev_err(&usb_dev->dev,
"can't set config #%d, error %d\n", c, result);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
dev_info(&usb_dev->dev, "authorized to connect\n");
error_configure:
error_device_descriptor:
error_autoresume:
out_authorized:
usb_unlock_device(usb_dev); // complements locktree
return result;
}
static int hub_port_status(struct usb_hub *hub, int port1, static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change) u16 *status, u16 *change)
{ {
......
...@@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev, ...@@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf); struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref); extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern int usb_deauthorize_device (struct usb_device *);
extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size); unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index); extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev); extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev, extern int usb_match_device(struct usb_device *dev,
......
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