linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Elbert Mai <code@elbertmai.com>
To: Greg KH <gregkh@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
Subject: Re: [PATCH] usb: Export BOS descriptor to sysfs
Date: Sat, 02 Mar 2024 00:37:24 +0000	[thread overview]
Message-ID: <faf0abfeefde4bb44494160224c78eca@purelymail.com> (raw)
In-Reply-To: <2024030142-gloater-stem-fe94@gregkh>

On 2024-03-01 06:18, Greg KH wrote:
> On Thu, Feb 29, 2024 at 03:59:05PM -0800, Elbert Mai wrote:
>> Motivation
>> ----------
>> 
>> The kernel already retrieves and caches the binary device object store
>> (BOS) descriptor from USB devices it enumerates. Export this 
>> descriptor to
>> userspace via sysfs, so users do not need to open the USB device with 
>> the
>> correct permissions and requesting the descriptor themselves.
>> 
>> A BOS descriptor contains a set of device capability descriptors. One 
>> that
>> is of interest to users is the platform descriptor. This contains a 
>> 128-bit
>> UUID and arbitrary data. The descriptor allows parties outside of 
>> USB-IF to
>> add additional metadata about a device in a standards-compliant 
>> manner.
>> 
>> Notable examples include the WebUSB and Microsoft OS 2.0 descriptors. 
>> Of
>> course, there could be more. By exporting the entire BOS descriptor we 
>> can
>> handle these and all future device capabilities. In addition, tools 
>> like
>> udev can match rules on device capabilities in the BOS without 
>> requiring
>> additional I/O with the USB device.
> 
> But this requires that userspace parse the raw descriptor, right?  Why
> not also export the descriptor information in simpler form through
> different sysfs files as well so that scripts can read this information
> easily?
> 
> That's not to say we don't also want this binary file, just maybe add
> more?

I've thought about this for a while, but IMHO it doesn't seem possible 
to
present the BOS in a simpler form like how it's done for the device and
configuration descriptors. The BOS was explicitly designed to be 
flexible
and extensible, and it's hard to make a "rich" sysfs interface around 
that.

We could have a platform_uuids file that lists all platform UUIDs in the 
BOS.
These could be presented in RFC 4122 string format, each separated by 
some
delimiter. This would make it possible to write a udev rule that matches 
a
particular UUID via a glob pattern. This seems like a rather inelegant 
way
of handling this, IMHO.

With regards to parsing raw descriptors in userspace, this already 
happens
at least with udev. About a dozen files in /usr/lib/udev/rules.d invoke 
a
built-in program called "usb_id", which opens the descriptors binary 
file
(among other files in sysfs) and parses it for interface information.

I think users and scripts interested in reading the BOS are best served 
with
userspace tools that can parse the BOS and present it in a convenient 
textual
format of their choosing. Having bos_descriptor in sysfs makes this 
possible
without needing elevated permissions or USB I/O. But I could be mistaken 
in
this regard.

>> Implementation
>> --------------
>> 
>> Add bos_descriptor file to sysfs. This is a binary file and it works 
>> the
>> same way as the existing descriptors file. The file exists even if a 
>> device
>> does not have a BOS descriptor (the file will be empty in this case). 
>> This
>> allows users to detect if the kernel supports reading the BOS via 
>> sysfs and
>> fall back to direct USB I/O if needed.
> 
> This is nice, but can you only create the file if it actually is
> present?  Use the is_visible callback to determine this, having an
> "empty" binary sysfs file isn't that nice.

Of course, I can make that happen.

> Other tiny review comments below:
> 
>> Signed-off-by: Elbert Mai <code@elbertmai.com>
>> ---
>>  Documentation/ABI/testing/sysfs-bus-usb |  9 +++++++
>>  drivers/usb/core/sysfs.c                | 35 
>> ++++++++++++++++++++++++-
>>  2 files changed, 43 insertions(+), 1 deletion(-)
>> 
>> diff --git a/Documentation/ABI/testing/sysfs-bus-usb 
>> b/Documentation/ABI/testing/sysfs-bus-usb
>> index 614d216dff1d..bfffaa752a13 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-usb
>> +++ b/Documentation/ABI/testing/sysfs-bus-usb
>> @@ -293,3 +293,12 @@ Description:
>>  		USB 3.2 adds Dual-lane support, 2 rx and 2 tx -lanes over Type-C.
>>  		Inter-Chip SSIC devices support asymmetric lanes up to 4 lanes per
>>  		direction. Devices before USB 3.2 are single lane (tx_lanes = 1)
>> +
>> +What:		/sys/bus/usb/devices/.../bos_descriptor
>> +Date:		March 2024
>> +Contact:	Elbert Mai <code@elbertmai.com>
>> +Description:
>> +		Binary file containing the cached binary device object store (BOS)
>> +		descriptor of the device. This file is empty if the BOS descriptor
>> +		is not present. The kernel will not request a BOS descriptor from
>> +		the device if its bcdUSB value is less than 0x0201.
>> diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
>> index a2ca38e25e0c..208d2f8cde2d 100644
>> --- a/drivers/usb/core/sysfs.c
>> +++ b/drivers/usb/core/sysfs.c
>> @@ -901,7 +901,7 @@ read_descriptors(struct file *filp, struct kobject 
>> *kobj,
>>  			srclen = sizeof(struct usb_device_descriptor);
>>  		} else {
>>  			src = udev->rawdescriptors[cfgno];
>> -			srclen = __le16_to_cpu(udev->config[cfgno].desc.
>> +			srclen = le16_to_cpu(udev->config[cfgno].desc.
> 
> Why is this line changed?

Consistency with the rest of the file. This was the only instance of 
__le16_to_cpu,
other lines used le16_to_cpu (no underscores).

>>  					wTotalLength);
>>  		}
>>  		if (off < srclen) {
>> @@ -923,6 +923,34 @@ static struct bin_attribute 
>> dev_bin_attr_descriptors = {
>>  	.size = 18 + 65535,	/* dev descr + max-size raw descriptor */
>>  };
>> 
>> +static ssize_t
>> +read_bos_descriptor(struct file *filp, struct kobject *kobj,
>> +		struct bin_attribute *attr,
>> +		char *buf, loff_t off, size_t count)
>> +{
>> +	struct device *dev = kobj_to_dev(kobj);
>> +	struct usb_device *udev = to_usb_device(dev);
>> +	struct usb_host_bos *bos = udev->bos;
>> +	struct usb_bos_descriptor *desc;
>> +	size_t desclen, n = 0;
>> +
>> +	if (bos) {
>> +		desc = bos->desc;
>> +		desclen = le16_to_cpu(desc->wTotalLength);
>> +		if (off < desclen) {
>> +			n = min(count, desclen - (size_t) off);
>> +			memcpy(buf, (void *) desc + off, n);
>> +		}
>> +	}
>> +	return n;
> 
> If bos is not present an error should return, not 0, right?

The interface_show function in sysfs.c returns 0 if the string 
describing
the interface is not present, so I did it the same way. Should I instead
return -ENOENT or some other specific error code?

>> +}
>> +
>> +static struct bin_attribute dev_bin_attr_bos_descriptor = {
>> +	.attr = {.name = "bos_descriptor", .mode = 0444},
>> +	.read = read_bos_descriptor,
> 
> Isn't there a mscro for all of this?

It turns out there is, called BIN_ATTR_RO in in linux/sysfs.h. I'm not 
sure
why the original code didn't use it for read_descriptors. I can change
both instances to shorten the code.

>> +	.size = 65535,	/* max-size BOS descriptor */
> 
> Do we know the size of the descriptor at runtime?  Ideally we would set
> it to be that, not an unknown size that way userspace knows what needs
> to be read.  But that's not really a big deal, if it's not possible, as
> the other USB binary descriptor does much the same.

We do know the size via wTotalLength, but that varies between USB 
devices
and dev_bin_attr_bos_descriptor is a static variable. So not really 
possible
unless we dynamically allocate all the attribute structs.

>> +};
> 
> This should go into an attribute group with the other descriptor, 
> making
> the rest of the patch not needed and simpler.

Will do. I'm in favor of simpler patches.

>> +
>>  /*
>>   * Show & store the current value of authorized_default
>>   */
>> @@ -1042,6 +1070,10 @@ int usb_create_sysfs_dev_files(struct 
>> usb_device *udev)
>>  	if (retval)
>>  		goto error;
>> 
>> +	retval = device_create_bin_file(dev, &dev_bin_attr_bos_descriptor);
>> +	if (retval)
>> +		goto error;
>> +
> 
> long-term I'd like to get rid of the individual "add and remove" sysfs
> files in this function, and just use the default groups instead so the
> driver core handles it.  It's not an issue here for this change, but if
> you can find a way to work on that as part of a patch series here, I
> think that would be really good (if possible, not a requirement.)

I'll see what I can do. I'll go for at least the low-hanging fruit.

> thanks!
> 
> greg k-h

And thank you for taking the time to review this patch!

-Elbert

      reply	other threads:[~2024-03-02  0:37 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-29 23:59 [PATCH] usb: Export BOS descriptor to sysfs Elbert Mai
2024-03-01  6:18 ` Greg KH
2024-03-02  0:37   ` Elbert Mai [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=faf0abfeefde4bb44494160224c78eca@purelymail.com \
    --to=code@elbertmai.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).