Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 392ca68b authored by George Spelvin's avatar George Spelvin Committed by Greg Kroah-Hartman
Browse files

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: default avatarGeorge Spelvin <linux@horizon.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 48d31677
Loading
Loading
Loading
Loading
+64 −47
Original line number Diff line number Diff line
@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = {

/*-------------------------------------------------------------------------*/

/*
 * helper routine for returning string descriptors in UTF-16LE
 * input can actually be ISO-8859-1; ASCII is its 7-bit subset
/**
 * ascii2desc() - Helper routine for producing UTF-16LE string descriptors
 * @s: Null-terminated ASCII (actually ISO-8859-1) string
 * @buf: Buffer for USB string descriptor (header + UTF-16LE)
 * @len: Length (in bytes; may be odd) of descriptor buffer.
 *
 * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
 * buflen, whichever is less.
 *
 * USB String descriptors can contain at most 126 characters; input
 * strings longer than that are truncated.
 */
static unsigned ascii2utf(char *s, u8 *utf, int utfmax)
static unsigned
ascii2desc(char const *s, u8 *buf, unsigned len)
{
	unsigned retval;
	unsigned n, t = 2 + 2*strlen(s);

	for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
		*utf++ = *s++;
		*utf++ = 0;
	}
	if (utfmax > 0) {
		*utf = *s;
		++retval;
	if (t > 254)
		t = 254;	/* Longest possible UTF string descriptor */
	if (len > t)
		len = t;

	t += USB_DT_STRING << 8;	/* Now t is first 16 bits to store */

	n = len;
	while (n--) {
		*buf++ = t;
		if (!n--)
			break;
		*buf++ = t >> 8;
		t = (unsigned char)*s++;
	}
	return retval;
	return len;
}

/*
 * rh_string - provides manufacturer, product and serial strings for root hub
 * @id: the string ID number (1: serial number, 2: product, 3: vendor)
/**
 * rh_string() - provides string descriptors for root hub
 * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
 * @hcd: the host controller for this root hub
 * @data: return packet in UTF-16 LE
 * @len: length of the return packet
 * @data: buffer for output packet
 * @len: length of the provided buffer
 *
 * Produces either a manufacturer, product or serial number string for the
 * virtual root hub device.
 * Returns the number of bytes filled in: the length of the descriptor or
 * of the provided buffer, whichever is less.
 */
static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len)
static unsigned
rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)
{
	char buf[100];
	char const *s;
	static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};

	// language ids
	if (id == 0) {
		buf[0] = 4;    buf[1] = 3;	/* 4 bytes string data */
		buf[2] = 0x09; buf[3] = 0x04;	/* MSFT-speak for "en-us" */
		len = min_t(unsigned, len, 4);
		memcpy (data, buf, len);
	switch (id) {
	case 0:
		/* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
		/* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
		if (len > 4)
			len = 4;
		memcpy(data, langids, len);
		return len;

	// serial number
	} else if (id == 1) {
		strlcpy (buf, hcd->self.bus_name, sizeof buf);

	// product description
	} else if (id == 2) {
		strlcpy (buf, hcd->product_desc, sizeof buf);

 	// id 3 == vendor description
	} else if (id == 3) {
	case 1:
		/* Serial number */
		s = hcd->self.bus_name;
		break;
	case 2:
		/* Product name */
		s = hcd->product_desc;
		break;
	case 3:
		/* Manufacturer */
		snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
			init_utsname()->release, hcd->driver->description);
	}

	switch (len) {		/* All cases fall through */
		s = buf;
		break;
	default:
		len = 2 + ascii2utf (buf, data + 2, len - 2);
	case 2:
		data [1] = 3;	/* type == string */
	case 1:
		data [0] = 2 * (strlen (buf) + 1);
	case 0:
		;		/* Compiler wants a statement here */
		/* Can't happen; caller guarantees it */
		return 0;
	}
	return len;

	return ascii2desc(s, data, len);
}