Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Clean up root hub string descriptors

The previous code had a bug that would add a trailing null byte to
the returned descriptor.

Signed-off-by: George Spelvin <linux@horizon.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

George Spelvin and committed by
Greg Kroah-Hartman
392ca68b 48d31677

+64 -47
+64 -47
drivers/usb/core/hcd.c
··· 337 337 338 338 /*-------------------------------------------------------------------------*/ 339 339 340 - /* 341 - * helper routine for returning string descriptors in UTF-16LE 342 - * input can actually be ISO-8859-1; ASCII is its 7-bit subset 340 + /** 341 + * ascii2desc() - Helper routine for producing UTF-16LE string descriptors 342 + * @s: Null-terminated ASCII (actually ISO-8859-1) string 343 + * @buf: Buffer for USB string descriptor (header + UTF-16LE) 344 + * @len: Length (in bytes; may be odd) of descriptor buffer. 345 + * 346 + * The return value is the number of bytes filled in: 2 + 2*strlen(s) or 347 + * buflen, whichever is less. 348 + * 349 + * USB String descriptors can contain at most 126 characters; input 350 + * strings longer than that are truncated. 343 351 */ 344 - static unsigned ascii2utf(char *s, u8 *utf, int utfmax) 352 + static unsigned 353 + ascii2desc(char const *s, u8 *buf, unsigned len) 345 354 { 346 - unsigned retval; 355 + unsigned n, t = 2 + 2*strlen(s); 347 356 348 - for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { 349 - *utf++ = *s++; 350 - *utf++ = 0; 357 + if (t > 254) 358 + t = 254; /* Longest possible UTF string descriptor */ 359 + if (len > t) 360 + len = t; 361 + 362 + t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */ 363 + 364 + n = len; 365 + while (n--) { 366 + *buf++ = t; 367 + if (!n--) 368 + break; 369 + *buf++ = t >> 8; 370 + t = (unsigned char)*s++; 351 371 } 352 - if (utfmax > 0) { 353 - *utf = *s; 354 - ++retval; 355 - } 356 - return retval; 372 + return len; 357 373 } 358 374 359 - /* 360 - * rh_string - provides manufacturer, product and serial strings for root hub 361 - * @id: the string ID number (1: serial number, 2: product, 3: vendor) 375 + /** 376 + * rh_string() - provides string descriptors for root hub 377 + * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor) 362 378 * @hcd: the host controller for this root hub 363 - * @data: return packet in UTF-16 LE 364 - * @len: length of the return packet 379 + * @data: buffer for output packet 380 + * @len: length of the provided buffer 365 381 * 366 382 * Produces either a manufacturer, product or serial number string for the 367 383 * virtual root hub device. 384 + * Returns the number of bytes filled in: the length of the descriptor or 385 + * of the provided buffer, whichever is less. 368 386 */ 369 - static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) 387 + static unsigned 388 + rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) 370 389 { 371 - char buf [100]; 390 + char buf[100]; 391 + char const *s; 392 + static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; 372 393 373 394 // language ids 374 - if (id == 0) { 375 - buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ 376 - buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ 377 - len = min_t(unsigned, len, 4); 378 - memcpy (data, buf, len); 395 + switch (id) { 396 + case 0: 397 + /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ 398 + /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */ 399 + if (len > 4) 400 + len = 4; 401 + memcpy(data, langids, len); 379 402 return len; 380 - 381 - // serial number 382 - } else if (id == 1) { 383 - strlcpy (buf, hcd->self.bus_name, sizeof buf); 384 - 385 - // product description 386 - } else if (id == 2) { 387 - strlcpy (buf, hcd->product_desc, sizeof buf); 388 - 389 - // id 3 == vendor description 390 - } else if (id == 3) { 403 + case 1: 404 + /* Serial number */ 405 + s = hcd->self.bus_name; 406 + break; 407 + case 2: 408 + /* Product name */ 409 + s = hcd->product_desc; 410 + break; 411 + case 3: 412 + /* Manufacturer */ 391 413 snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, 392 414 init_utsname()->release, hcd->driver->description); 415 + s = buf; 416 + break; 417 + default: 418 + /* Can't happen; caller guarantees it */ 419 + return 0; 393 420 } 394 421 395 - switch (len) { /* All cases fall through */ 396 - default: 397 - len = 2 + ascii2utf (buf, data + 2, len - 2); 398 - case 2: 399 - data [1] = 3; /* type == string */ 400 - case 1: 401 - data [0] = 2 * (strlen (buf) + 1); 402 - case 0: 403 - ; /* Compiler wants a statement here */ 404 - } 405 - return len; 422 + return ascii2desc(s, data, len); 406 423 } 407 424 408 425