[PATCH 2/2] Bluetooth: hci_event: keep HCI_LE_ADV set when the host cancelled the connection

Valentin Kindschi <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
le_conn_complete_evt() clears HCI_LE_ADV before looking at the event
status:

	/* All controllers implicitly stop advertising in the event of a
	 * connection, so ensure that the state bit is cleared.
	 */
	hci_dev_clear_flag(hdev, HCI_LE_ADV);

The premise fails for Unknown Connection Identifier (0x02), which is
what an HCI_LE_Connection_Complete carries after the host issued
LE Create Connection Cancel: no connection was created and the
controller never stopped advertising. Clearing the flag there makes the
host believe advertising is off while the controller has it on.

Other non-zero statuses must keep clearing it. Advertising Timeout
(0x3c) in particular means the controller gave up advertising on its
own, so the flag has to go; leaving it set would make the
"already advertising" shortcut in hci_schedule_adv_instance_sync() skip
the HCI commands and silently stop advertising altogether.

With legacy advertising the disagreement is self-sustaining. On the next
software rotation tick hci_enable_advertising_sync() runs:

  - hci_disable_advertising_sync() returns early without sending
    anything, because HCI_LE_ADV is clear;
  - LE Set Advertising Parameters is then sent while the controller is
    still advertising, and is correctly rejected with Command Disallowed
    (0x0c);
  - the function returns before LE Set Advertising Enable, so nothing
    re-sets HCI_LE_ADV.

hci_schedule_adv_instance_sync() re-arms adv_instance_expire every
HCI_DEFAULT_ADV_DURATION (2 s) and its "already advertising" shortcut
tests HCI_LE_ADV, which can no longer become true, so the command is
retried every 2 s indefinitely:

  Bluetooth: hci0: Opcode 0x2006 failed: -16

Captured on a BCM43455 (no LE Extended Advertising) after a central
connection attempt timed out and was cancelled:

  LE Set Advertising Parameters (0x2006)   Success
  LE Set Advertising Enable     (0x200a)   Success        HCI_LE_ADV set
  LE Create Connection Cancel   (0x200e)   Success
  LE Connection Complete                   Unknown Conn Id  <- flag cleared
  LE Set Advertising Parameters (0x2006)   Command Disallowed  [+2.033 s]
  LE Set Advertising Parameters (0x2006)   Command Disallowed  [+2.016 s]
  ...

Keep the flag only for the host-cancelled case.

Fixes: fbd96c151cdc ("Bluetooth: Fix clearing HCI_LE_ADV for LE connections")
Cc: [email protected]
Assisted-by: Claude:claude-opus-5 btmon
Signed-off-by: Valentin Kindschi <[email protected]>
---
 net/bluetooth/hci_event.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5646,10 +5646,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,

 	hci_dev_lock(hdev);

-	/* All controllers implicitly stop advertising in the event of a
-	 * connection, so ensure that the state bit is cleared.
+	/* Advertising stops when a connection is created, and when the
+	 * controller gives up advertising on its own. It keeps advertising
+	 * when the host cancelled an outgoing connection.
 	 */
-	hci_dev_clear_flag(hdev, HCI_LE_ADV);
+	if (status != HCI_ERROR_UNKNOWN_CONN_ID)
+		hci_dev_clear_flag(hdev, HCI_LE_ADV);

 	/* Check for existing connection:
 	 *
--
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.