aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-03-03 15:16:04 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-25 00:16:33 -0400
commiteb764c4be1e5db3ee34df5745e98cf2f148c7320 (patch)
treef434cf49540ab6ea2c7fae6490a693916c2e5501 /drivers/usb/core
parentfeccc30d90155bcbc937f87643182a43d25873eb (diff)
USB: check serial-number string after device reset
This patch (as1048) extends the descriptor checking after a device is reset. Now the SerialNumber string descriptor is compared to its old value, in addition to the device and configuration descriptors. As a consequence, the kmalloc() call in usb_string() is now on the error-handling pathway for usb-storage. Hence its allocation type is changed to GFO_NOIO. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c65
-rw-r--r--drivers/usb/core/message.c2
2 files changed, 51 insertions, 16 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6dc589955d75..9fc5179dfc60 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3010,16 +3010,36 @@ void usb_hub_cleanup(void)
3010 usb_deregister(&hub_driver); 3010 usb_deregister(&hub_driver);
3011} /* usb_hub_cleanup() */ 3011} /* usb_hub_cleanup() */
3012 3012
3013static int config_descriptors_changed(struct usb_device *udev) 3013static int descriptors_changed(struct usb_device *udev,
3014{ 3014 struct usb_device_descriptor *old_device_descriptor)
3015 unsigned index; 3015{
3016 unsigned len = 0; 3016 int changed = 0;
3017 struct usb_config_descriptor *buf; 3017 unsigned index;
3018 unsigned serial_len = 0;
3019 unsigned len;
3020 unsigned old_length;
3021 int length;
3022 char *buf;
3023
3024 if (memcmp(&udev->descriptor, old_device_descriptor,
3025 sizeof(*old_device_descriptor)) != 0)
3026 return 1;
3027
3028 /* Since the idVendor, idProduct, and bcdDevice values in the
3029 * device descriptor haven't changed, we will assume the
3030 * Manufacturer and Product strings haven't changed either.
3031 * But the SerialNumber string could be different (e.g., a
3032 * different flash card of the same brand).
3033 */
3034 if (udev->serial)
3035 serial_len = strlen(udev->serial) + 1;
3018 3036
3037 len = serial_len;
3019 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { 3038 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
3020 if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) 3039 old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3021 len = le16_to_cpu(udev->config[index].desc.wTotalLength); 3040 len = max(len, old_length);
3022 } 3041 }
3042
3023 buf = kmalloc(len, GFP_NOIO); 3043 buf = kmalloc(len, GFP_NOIO);
3024 if (buf == NULL) { 3044 if (buf == NULL) {
3025 dev_err(&udev->dev, "no mem to re-read configs after reset\n"); 3045 dev_err(&udev->dev, "no mem to re-read configs after reset\n");
@@ -3027,25 +3047,41 @@ static int config_descriptors_changed(struct usb_device *udev)
3027 return 1; 3047 return 1;
3028 } 3048 }
3029 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { 3049 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
3030 int length; 3050 old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3031 int old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3032
3033 length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, 3051 length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
3034 old_length); 3052 old_length);
3035 if (length < old_length) { 3053 if (length != old_length) {
3036 dev_dbg(&udev->dev, "config index %d, error %d\n", 3054 dev_dbg(&udev->dev, "config index %d, error %d\n",
3037 index, length); 3055 index, length);
3056 changed = 1;
3038 break; 3057 break;
3039 } 3058 }
3040 if (memcmp (buf, udev->rawdescriptors[index], old_length) 3059 if (memcmp (buf, udev->rawdescriptors[index], old_length)
3041 != 0) { 3060 != 0) {
3042 dev_dbg(&udev->dev, "config index %d changed (#%d)\n", 3061 dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
3043 index, buf->bConfigurationValue); 3062 index,
3063 ((struct usb_config_descriptor *) buf)->
3064 bConfigurationValue);
3065 changed = 1;
3044 break; 3066 break;
3045 } 3067 }
3046 } 3068 }
3069
3070 if (!changed && serial_len) {
3071 length = usb_string(udev, udev->descriptor.iSerialNumber,
3072 buf, serial_len);
3073 if (length + 1 != serial_len) {
3074 dev_dbg(&udev->dev, "serial string error %d\n",
3075 length);
3076 changed = 1;
3077 } else if (memcmp(buf, udev->serial, length) != 0) {
3078 dev_dbg(&udev->dev, "serial string changed\n");
3079 changed = 1;
3080 }
3081 }
3082
3047 kfree(buf); 3083 kfree(buf);
3048 return index != udev->descriptor.bNumConfigurations; 3084 return changed;
3049} 3085}
3050 3086
3051/** 3087/**
@@ -3118,8 +3154,7 @@ int usb_reset_device(struct usb_device *udev)
3118 goto re_enumerate; 3154 goto re_enumerate;
3119 3155
3120 /* Device might have changed firmware (DFU or similar) */ 3156 /* Device might have changed firmware (DFU or similar) */
3121 if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor) 3157 if (descriptors_changed(udev, &descriptor)) {
3122 || config_descriptors_changed (udev)) {
3123 dev_info(&udev->dev, "device firmware changed\n"); 3158 dev_info(&udev->dev, "device firmware changed\n");
3124 udev->descriptor = descriptor; /* for disconnect() calls */ 3159 udev->descriptor = descriptor; /* for disconnect() calls */
3125 goto re_enumerate; 3160 goto re_enumerate;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index c311f67b7f08..a3695b5115ff 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -784,7 +784,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
784 if (size <= 0 || !buf || !index) 784 if (size <= 0 || !buf || !index)
785 return -EINVAL; 785 return -EINVAL;
786 buf[0] = 0; 786 buf[0] = 0;
787 tbuf = kmalloc(256, GFP_KERNEL); 787 tbuf = kmalloc(256, GFP_NOIO);
788 if (!tbuf) 788 if (!tbuf)
789 return -ENOMEM; 789 return -ENOMEM;
790 790