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

Configure Feed

Select the types of activity you want to include in your feed.

usb: Export BOS descriptor to sysfs

Motivation
----------

The binary device object store (BOS) of a USB device consists of the BOS
descriptor followed by 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, and it allows parties outside of USB-IF to add
additional metadata about a USB device in a standards-compliant manner.
Notable examples include the WebUSB and Microsoft OS 2.0 descriptors.

The kernel already retrieves and caches the BOS from USB devices if its
bcdUSB is >= 0x0201. Because the BOS is flexible and extensible, we export
the entire BOS to sysfs so users can retrieve whatever device capabilities
they desire, without requiring USB I/O or elevated permissions.

Implementation
--------------

Add bos_descriptors attribute to sysfs. This is a binary file and it works
the same way as the existing descriptors attribute. The file exists only if
the BOS is present in the USB device.

Also create a binary attribute group, so the driver core can handle the
creation of both the descriptors and bos_descriptors attributes in sysfs.

Signed-off-by: Elbert Mai <code@elbertmai.com>
Link: https://lore.kernel.org/r/20240305002301.95323-1-code@elbertmai.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Elbert Mai and committed by
Greg Kroah-Hartman
12fc84e8 a14e6fd1

+71 -17
+10
Documentation/ABI/testing/sysfs-bus-usb
··· 442 442 Description: 443 443 Contains the interface descriptors, in binary. 444 444 445 + What: /sys/bus/usb/devices/usbX/bos_descriptors 446 + Date: March 2024 447 + Contact: Elbert Mai <code@elbertmai.com> 448 + Description: 449 + Binary file containing the cached binary device object store (BOS) 450 + of the device. This consists of the BOS descriptor followed by the 451 + set of device capability descriptors. All descriptors read from 452 + this file are in bus-endian format. Note that the kernel will not 453 + request the BOS from a device if its bcdUSB is less than 0x0201. 454 + 445 455 What: /sys/bus/usb/devices/usbX/idProduct 446 456 Description: 447 457 Product ID, in hexadecimal.
+61 -17
drivers/usb/core/sysfs.c
··· 849 849 .is_visible = dev_string_attrs_are_visible, 850 850 }; 851 851 852 - const struct attribute_group *usb_device_groups[] = { 853 - &dev_attr_grp, 854 - &dev_string_attr_grp, 855 - NULL 856 - }; 857 - 858 852 /* Binary descriptors */ 859 853 860 854 static ssize_t 861 - read_descriptors(struct file *filp, struct kobject *kobj, 855 + descriptors_read(struct file *filp, struct kobject *kobj, 862 856 struct bin_attribute *attr, 863 857 char *buf, loff_t off, size_t count) 864 858 { ··· 874 880 srclen = sizeof(struct usb_device_descriptor); 875 881 } else { 876 882 src = udev->rawdescriptors[cfgno]; 877 - srclen = __le16_to_cpu(udev->config[cfgno].desc. 883 + srclen = le16_to_cpu(udev->config[cfgno].desc. 878 884 wTotalLength); 879 885 } 880 886 if (off < srclen) { ··· 889 895 } 890 896 return count - nleft; 891 897 } 898 + static BIN_ATTR_RO(descriptors, 18 + 65535); /* dev descr + max-size raw descriptor */ 892 899 893 - static struct bin_attribute dev_bin_attr_descriptors = { 894 - .attr = {.name = "descriptors", .mode = 0444}, 895 - .read = read_descriptors, 896 - .size = 18 + 65535, /* dev descr + max-size raw descriptor */ 900 + static ssize_t 901 + bos_descriptors_read(struct file *filp, struct kobject *kobj, 902 + struct bin_attribute *attr, 903 + char *buf, loff_t off, size_t count) 904 + { 905 + struct device *dev = kobj_to_dev(kobj); 906 + struct usb_device *udev = to_usb_device(dev); 907 + struct usb_host_bos *bos = udev->bos; 908 + struct usb_bos_descriptor *desc; 909 + size_t desclen, n = 0; 910 + 911 + if (bos) { 912 + desc = bos->desc; 913 + desclen = le16_to_cpu(desc->wTotalLength); 914 + if (off < desclen) { 915 + n = min(count, desclen - (size_t) off); 916 + memcpy(buf, (void *) desc + off, n); 917 + } 918 + } 919 + return n; 920 + } 921 + static BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */ 922 + 923 + /* When modifying this list, be sure to modify dev_bin_attrs_are_visible() 924 + * accordingly. 925 + */ 926 + static struct bin_attribute *dev_bin_attrs[] = { 927 + &bin_attr_descriptors, 928 + &bin_attr_bos_descriptors, 929 + NULL 930 + }; 931 + 932 + static umode_t dev_bin_attrs_are_visible(struct kobject *kobj, 933 + struct bin_attribute *a, int n) 934 + { 935 + struct device *dev = kobj_to_dev(kobj); 936 + struct usb_device *udev = to_usb_device(dev); 937 + 938 + /* All USB devices have a device descriptor, so the descriptors 939 + * attribute always exists. No need to check for its visibility. 940 + */ 941 + if (a == &bin_attr_bos_descriptors) { 942 + if (udev->bos == NULL) 943 + return 0; 944 + } 945 + return a->attr.mode; 946 + } 947 + 948 + static const struct attribute_group dev_bin_attr_grp = { 949 + .bin_attrs = dev_bin_attrs, 950 + .is_bin_visible = dev_bin_attrs_are_visible, 951 + }; 952 + 953 + const struct attribute_group *usb_device_groups[] = { 954 + &dev_attr_grp, 955 + &dev_string_attr_grp, 956 + &dev_bin_attr_grp, 957 + NULL 897 958 }; 898 959 899 960 /* ··· 1066 1017 struct device *dev = &udev->dev; 1067 1018 int retval; 1068 1019 1069 - retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); 1070 - if (retval) 1071 - goto error; 1072 - 1073 1020 retval = add_persist_attributes(dev); 1074 1021 if (retval) 1075 1022 goto error; ··· 1095 1050 1096 1051 remove_power_attributes(dev); 1097 1052 remove_persist_attributes(dev); 1098 - device_remove_bin_file(dev, &dev_bin_attr_descriptors); 1099 1053 } 1100 1054 1101 1055 /* Interface Association Descriptor fields */