git: 0b23c50ae834 - main - ng_ubt_intel: Ignore unexpected HCI events

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Wed, 06 Nov 2024 23:31:53 UTC
The branch main has been updated by wulf:

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

commit 0b23c50ae834d11842810304e4ddad2754298ada
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2024-11-06 23:27:20 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2024-11-06 23:27:20 +0000

    ng_ubt_intel: Ignore unexpected HCI events
    
    If Intel firmware is already in operational mode at boot that takes
    place at warm boot, BT adaptor can generate extra HCI events which
    interferes with firmware mode detection logic. Ignore them.
    
    Sponsored by:   Future Crew LLC
    MFC after:      1 month
    Reviewed by:    bz
    Differential Revision:  https://reviews.freebsd.org/D46736
---
 sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c       | 27 +++++++++++++++++++++++
 sys/netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c |  5 +++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
index a63ccae3cc03..59405629efb1 100644
--- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
+++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
@@ -534,6 +534,7 @@ static const STRUCT_USB_HOST_ID ubt_devs[] =
  * Size of both command and response buffers are passed in length field of
  * corresponding structures in "Parameter Total Length" format i.e.
  * not including HCI packet headers.
+ * Expected event code must be placed into "Event code" of the response buffer.
  *
  * Must not be used after USB transfers have been configured in attach routine.
  */
@@ -572,6 +573,12 @@ ubt_do_hci_request(struct usb_device *udev, struct ubt_hci_cmd *cmd,
 	if (evt == NULL)
 		return (USB_ERR_NORMAL_COMPLETION);
 
+	/* Save operation code if we expect completion event in response */
+	if(((struct ubt_hci_event *)evt)->header.event ==
+	    NG_HCI_EVENT_COMMAND_COMPL)
+		((struct ubt_hci_event_command_compl *)evt)->opcode =
+		  cmd->opcode;
+
 	/* Initialize INTR endpoint xfer and wait for response */
 	mtx_init(&mtx, "ubt pb", NULL, MTX_DEF | MTX_NEW);
 
@@ -842,6 +849,8 @@ ubt_probe_intr_callback(struct usb_xfer *xfer, usb_error_t error)
 	struct ubt_hci_event	*evt = usbd_xfer_softc(xfer);
 	struct usb_page_cache	*pc;
 	int			actlen;
+	struct ubt_hci_evhdr	evhdr;
+	uint16_t		opcode;
 
 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
 
@@ -849,7 +858,25 @@ ubt_probe_intr_callback(struct usb_xfer *xfer, usb_error_t error)
 	case USB_ST_TRANSFERRED:
 		if (actlen > UBT_HCI_EVENT_SIZE(evt))
 			actlen = UBT_HCI_EVENT_SIZE(evt);
+		if (actlen < sizeof(evhdr))
+			goto submit_next;
 		pc = usbd_xfer_get_frame(xfer, 0);
+		usbd_copy_out(pc, 0, &evhdr, sizeof(evhdr));
+		/* Check for expected event code */
+		if (evt->header.event != 0 &&
+		    (evt->header.event != evhdr.event))
+			goto submit_next;
+		/* For completion events check operation code as well */
+		if (evt->header.event == NG_HCI_EVENT_COMMAND_COMPL) {
+			if (actlen < sizeof(struct ubt_hci_event_command_compl))
+				goto submit_next;
+			usbd_copy_out(pc,
+			    offsetof(struct ubt_hci_event_command_compl, opcode),
+			    &opcode, sizeof(opcode));
+			if (opcode !=
+			    ((struct ubt_hci_event_command_compl *)evt)->opcode)
+				goto submit_next;
+		}
 		usbd_copy_out(pc, 0, evt, actlen);
 		/* OneShot mode */
 		wakeup(evt);
diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c
index f93b74b264ad..c4410b7b2c80 100644
--- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c
+++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c
@@ -119,14 +119,14 @@ ubt_intel_do_hci_request(struct usb_device *udev, uint16_t opcode,
 	cmd.opcode = htole16(opcode);
 	evt = malloc(offsetof(struct ubt_hci_event_command_compl, data) +
 	    resp_len, M_TEMP, M_ZERO | M_WAITOK);
+	evt->header.event = NG_HCI_EVENT_COMMAND_COMPL;
 	evt->header.length = resp_len + UBT_HCI_EVENT_COMPL_HEAD_SIZE;
 
 	error = ubt_do_hci_request(udev, &cmd, evt, UBT_INTEL_HCICMD_TIMEOUT);
 	if (error != USB_ERR_NORMAL_COMPLETION)
 		goto exit;
 
-	if (evt->header.event == NG_HCI_EVENT_COMMAND_COMPL &&
-	    evt->header.length == resp_len + UBT_HCI_EVENT_COMPL_HEAD_SIZE)
+	if (evt->header.length == resp_len + UBT_HCI_EVENT_COMPL_HEAD_SIZE)
 		memcpy(resp, evt->data, resp_len);
 	else
 		error = USB_ERR_INVAL;
@@ -150,6 +150,7 @@ ubt_intel_get_img_type(struct usb_device *udev)
 	uint8_t *data;
 
 	evt = malloc(UBT_INTEL_MAX_EVT_SIZE, M_TEMP, M_ZERO | M_WAITOK);
+	evt->header.event = NG_HCI_EVENT_COMMAND_COMPL;
 	evt->header.length =
 	    UBT_INTEL_MAX_EVT_SIZE - sizeof(struct ubt_hci_evhdr);