]> git.baikalelectronics.ru Git - kernel.git/commitdiff
Bluetooth: Ignore HCI_ERROR_CANCELLED_BY_HOST on adv set terminated event
authorArchie Pusaka <apusaka@chromium.org>
Thu, 11 Nov 2021 05:20:53 +0000 (13:20 +0800)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 16 Nov 2021 14:16:30 +0000 (15:16 +0100)
This event is received when the controller stops advertising,
specifically for these three reasons:
(a) Connection is successfully created (success).
(b) Timeout is reached (error).
(c) Number of advertising events is reached (error).
(*) This event is NOT generated when the host stops the advertisement.
Refer to the BT spec ver 5.3 vol 4 part E sec 7.7.65.18. Note that the
section was revised from BT spec ver 5.0 vol 2 part E sec 7.7.65.18
which was ambiguous about (*).

Some chips (e.g. RTL8822CE) send this event when the host stops the
advertisement with status = HCI_ERROR_CANCELLED_BY_HOST (due to (*)
above). This is treated as an error and the advertisement will be
removed and userspace will be informed via MGMT event.

On suspend, we are supposed to temporarily disable advertisements,
and continue advertising on resume. However, due to the behavior
above, the advertisements are removed instead.

This patch returns early if HCI_ERROR_CANCELLED_BY_HOST is received.

Btmon snippet of the unexpected behavior:
@ MGMT Command: Remove Advertising (0x003f) plen 1
        Instance: 1
< HCI Command: LE Set Extended Advertising Enable (0x08|0x0039) plen 6
        Extended advertising: Disabled (0x00)
        Number of sets: 1 (0x01)
        Entry 0
          Handle: 0x01
          Duration: 0 ms (0x00)
          Max ext adv events: 0
> HCI Event: LE Meta Event (0x3e) plen 6
      LE Advertising Set Terminated (0x12)
        Status: Operation Cancelled by Host (0x44)
        Handle: 1
        Connection handle: 0
        Number of completed extended advertising events: 5
> HCI Event: Command Complete (0x0e) plen 4
      LE Set Extended Advertising Enable (0x08|0x0039) ncmd 2
        Status: Success (0x00)

Signed-off-by: Archie Pusaka <apusaka@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci.h
net/bluetooth/hci_event.c

index 63065bc01b766c0a3049002d6173e8e79fd2d18b..84db6b275231bb6e5d8ae28ad268e5079a87c4f8 100644 (file)
@@ -566,6 +566,7 @@ enum {
 #define HCI_ERROR_INVALID_LL_PARAMS    0x1e
 #define HCI_ERROR_UNSPECIFIED          0x1f
 #define HCI_ERROR_ADVERTISING_TIMEOUT  0x3c
+#define HCI_ERROR_CANCELLED_BY_HOST    0x44
 
 /* Flow control modes */
 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
index 9e27ff343716318f9f4d5b6d517dc6c3fffbf000..8eae38129a6eb163096c30ea426c8ee39db34c14 100644 (file)
@@ -5533,6 +5533,18 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        adv = hci_find_adv_instance(hdev, ev->handle);
 
+       /* The Bluetooth Core 5.3 specification clearly states that this event
+        * shall not be sent when the Host disables the advertising set. So in
+        * case of HCI_ERROR_CANCELLED_BY_HOST, just ignore the event.
+        *
+        * When the Host disables an advertising set, all cleanup is done via
+        * its command callback and not needed to be duplicated here.
+        */
+       if (ev->status == HCI_ERROR_CANCELLED_BY_HOST) {
+               bt_dev_warn_ratelimited(hdev, "Unexpected advertising set terminated event");
+               return;
+       }
+
        if (ev->status) {
                if (!adv)
                        return;