git: ab18352d8f9d - main - usb: Add usbd_bos_foreach helper

From: ShengYi Hung <aokblast_at_FreeBSD.org>
Date: Mon, 02 Nov 2026 03:02:48 UTC
The branch main has been updated by aokblast:

URL: https://cgit.FreeBSD.org/src/commit/?id=ab18352d8f9dd26d94da1165259460ead44a9e4c

commit ab18352d8f9dd26d94da1165259460ead44a9e4c
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2026-05-22 16:18:57 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-11-02 03:02:11 +0000

    usb: Add usbd_bos_foreach helper
    
    Iterate the capabilities of a BOS descriptor.
    
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57199
---
 sys/dev/usb/usb_parse.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/usb/usbdi_util.h |  2 ++
 2 files changed, 47 insertions(+)

diff --git a/sys/dev/usb/usb_parse.c b/sys/dev/usb/usb_parse.c
index bb592f1a4c03..7beb4dbd29a2 100644
--- a/sys/dev/usb/usb_parse.c
+++ b/sys/dev/usb/usb_parse.c
@@ -315,3 +315,48 @@ usbd_get_no_alts(struct usb_config_descriptor *cd,
 	}
 	return (n);
 }
+
+/*------------------------------------------------------------------------*
+ *	usbd_bos_foreach
+ *
+ * This function iterates the capabilities of a BOS descriptor. "bos"
+ * must be the complete descriptor, because "wTotalLength" is taken as
+ * the size of the buffer.
+ *
+ * Returns:
+ *   NULL: End of capabilities
+ *   Else: Pointer to the next capability
+ *------------------------------------------------------------------------*/
+struct usb_bos_cap_descriptor *
+usbd_bos_foreach(struct usb_bos_descriptor *bos,
+    struct usb_bos_cap_descriptor *cap)
+{
+	uint32_t offset;
+	uint32_t total;
+
+	/*
+	 * No capability
+	 */
+	if (bos == NULL || bos->bLength < sizeof(*bos))
+		return (NULL);
+
+	total = UGETW(bos->wTotalLength);
+
+	if (cap == NULL)
+		offset = bos->bLength;
+	else
+		offset = (uint8_t *)cap - (uint8_t *)bos + cap->bLength;
+
+	/*
+	 * The returned capability must be complete
+	 */
+	if (offset + sizeof(*cap) > total)
+		return (NULL);
+
+	cap = (struct usb_bos_cap_descriptor *)((uint8_t *)bos + offset);
+
+	if (cap->bLength < sizeof(*cap) || offset + cap->bLength > total)
+		return (NULL);
+
+	return (cap);
+}
diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h
index 403327e8070f..0b422387f97c 100644
--- a/sys/dev/usb/usbdi_util.h
+++ b/sys/dev/usb/usbdi_util.h
@@ -54,6 +54,8 @@ struct usb_endpoint_descriptor *usb_edesc_foreach(
 struct usb_endpoint_ss_comp_descriptor *usb_ed_comp_foreach(
 	    struct usb_config_descriptor *cd,
 	    struct usb_endpoint_ss_comp_descriptor *ped);
+struct usb_bos_cap_descriptor *usbd_bos_foreach(struct usb_bos_descriptor *bos,
+	    struct usb_bos_cap_descriptor *cap);
 uint8_t usbd_get_no_descriptors(struct usb_config_descriptor *cd,
 	    uint8_t type);
 uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd,