aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Paulo Rechi Vita <jprvita@gmail.com>2019-05-01 22:01:52 -0400
committerMarcel Holtmann <marcel@holtmann.org>2019-05-05 13:29:04 -0400
commitf80c5dad7b6467b884c445ffea45985793b4b2d0 (patch)
tree09f6df01a2fdb95675f69bc43fcc3f6173739b77
parent300926b138eb30ce1763d1d10604230d4d38d64a (diff)
Bluetooth: Ignore CC events not matching the last HCI command
This commit makes the kernel not send the next queued HCI command until a command complete arrives for the last HCI command sent to the controller. This change avoids a problem with some buggy controllers (seen on two SKUs of QCA9377) that send an extra command complete event for the previous command after the kernel had already sent a new HCI command to the controller. The problem was reproduced when starting an active scanning procedure, where an extra command complete event arrives for the LE_SET_RANDOM_ADDR command. When this happends the kernel ends up not processing the command complete for the following commmand, LE_SET_SCAN_PARAM, and ultimately behaving as if a passive scanning procedure was being performed, when in fact controller is performing an active scanning procedure. This makes it impossible to discover BLE devices as no device found events are sent to userspace. This problem is reproducible on 100% of the attempts on the affected controllers. The extra command complete event can be seen at timestamp 27.420131 on the btmon logs bellow. Bluetooth monitor ver 5.50 = Note: Linux version 5.0.0+ (x86_64) 0.352340 = Note: Bluetooth subsystem version 2.22 0.352343 = New Index: 80:C5:F2:8F:87:84 (Primary,USB,hci0) [hci0] 0.352344 = Open Index: 80:C5:F2:8F:87:84 [hci0] 0.352345 = Index Info: 80:C5:F2:8F:87:84 (Qualcomm) [hci0] 0.352346 @ MGMT Open: bluetoothd (privileged) version 1.14 {0x0001} 0.352347 @ MGMT Open: btmon (privileged) version 1.14 {0x0002} 0.352366 @ MGMT Open: btmgmt (privileged) version 1.14 {0x0003} 27.302164 @ MGMT Command: Start Discovery (0x0023) plen 1 {0x0003} [hci0] 27.302310 Address type: 0x06 LE Public LE Random < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 #1 [hci0] 27.302496 Address: 15:60:F2:91:B2:24 (Non-Resolvable) > HCI Event: Command Complete (0x0e) plen 4 #2 [hci0] 27.419117 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 #3 [hci0] 27.419244 Type: Active (0x01) Interval: 11.250 msec (0x0012) Window: 11.250 msec (0x0012) Own address type: Random (0x01) Filter policy: Accept all advertisement (0x00) > HCI Event: Command Complete (0x0e) plen 4 #4 [hci0] 27.420131 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #5 [hci0] 27.420259 Scanning: Enabled (0x01) Filter duplicates: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 #6 [hci0] 27.420969 LE Set Scan Parameters (0x08|0x000b) ncmd 1 Status: Success (0x00) > HCI Event: Command Complete (0x0e) plen 4 #7 [hci0] 27.421983 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) @ MGMT Event: Command Complete (0x0001) plen 4 {0x0003} [hci0] 27.422059 Start Discovery (0x0023) plen 1 Status: Success (0x00) Address type: 0x06 LE Public LE Random @ MGMT Event: Discovering (0x0013) plen 2 {0x0003} [hci0] 27.422067 Address type: 0x06 LE Public LE Random Discovery: Enabled (0x01) @ MGMT Event: Discovering (0x0013) plen 2 {0x0002} [hci0] 27.422067 Address type: 0x06 LE Public LE Random Discovery: Enabled (0x01) @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 27.422067 Address type: 0x06 LE Public LE Random Discovery: Enabled (0x01) Signed-off-by: João Paulo Rechi Vita <jprvita@endlessm.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci.h1
-rw-r--r--net/bluetooth/hci_core.c5
-rw-r--r--net/bluetooth/hci_event.c12
-rw-r--r--net/bluetooth/hci_request.c5
-rw-r--r--net/bluetooth/hci_request.h1
5 files changed, 24 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fbba43e9bef5..9a5330eed794 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -282,6 +282,7 @@ enum {
282 HCI_FORCE_BREDR_SMP, 282 HCI_FORCE_BREDR_SMP,
283 HCI_FORCE_STATIC_ADDR, 283 HCI_FORCE_STATIC_ADDR,
284 HCI_LL_RPA_RESOLUTION, 284 HCI_LL_RPA_RESOLUTION,
285 HCI_CMD_PENDING,
285 286
286 __HCI_NUM_FLAGS, 287 __HCI_NUM_FLAGS,
287}; 288};
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 3d9175f130b3..b81bf53c5ac4 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -4381,6 +4381,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
4381 return; 4381 return;
4382 } 4382 }
4383 4383
4384 /* If we reach this point this event matches the last command sent */
4385 hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
4386
4384 /* If the command succeeded and there's still more commands in 4387 /* If the command succeeded and there's still more commands in
4385 * this request the request is not yet complete. 4388 * this request the request is not yet complete.
4386 */ 4389 */
@@ -4491,6 +4494,8 @@ static void hci_cmd_work(struct work_struct *work)
4491 4494
4492 hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); 4495 hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
4493 if (hdev->sent_cmd) { 4496 if (hdev->sent_cmd) {
4497 if (hci_req_status_pend(hdev))
4498 hci_dev_set_flag(hdev, HCI_CMD_PENDING);
4494 atomic_dec(&hdev->cmd_cnt); 4499 atomic_dec(&hdev->cmd_cnt);
4495 hci_send_frame(hdev, skb); 4500 hci_send_frame(hdev, skb);
4496 if (test_bit(HCI_RESET, &hdev->flags)) 4501 if (test_bit(HCI_RESET, &hdev->flags))
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 66b631ab0d35..9e4fcf406d9c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3404,6 +3404,12 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
3404 hci_req_cmd_complete(hdev, *opcode, *status, req_complete, 3404 hci_req_cmd_complete(hdev, *opcode, *status, req_complete,
3405 req_complete_skb); 3405 req_complete_skb);
3406 3406
3407 if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) {
3408 bt_dev_err(hdev,
3409 "unexpected event for opcode 0x%4.4x", *opcode);
3410 return;
3411 }
3412
3407 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) 3413 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q))
3408 queue_work(hdev->workqueue, &hdev->cmd_work); 3414 queue_work(hdev->workqueue, &hdev->cmd_work);
3409} 3415}
@@ -3511,6 +3517,12 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
3511 hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete, 3517 hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete,
3512 req_complete_skb); 3518 req_complete_skb);
3513 3519
3520 if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) {
3521 bt_dev_err(hdev,
3522 "unexpected event for opcode 0x%4.4x", *opcode);
3523 return;
3524 }
3525
3514 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) 3526 if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q))
3515 queue_work(hdev->workqueue, &hdev->cmd_work); 3527 queue_work(hdev->workqueue, &hdev->cmd_work);
3516} 3528}
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index ca73d36cc149..e9a95ed65491 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -46,6 +46,11 @@ void hci_req_purge(struct hci_request *req)
46 skb_queue_purge(&req->cmd_q); 46 skb_queue_purge(&req->cmd_q);
47} 47}
48 48
49bool hci_req_status_pend(struct hci_dev *hdev)
50{
51 return hdev->req_status == HCI_REQ_PEND;
52}
53
49static int req_run(struct hci_request *req, hci_req_complete_t complete, 54static int req_run(struct hci_request *req, hci_req_complete_t complete,
50 hci_req_complete_skb_t complete_skb) 55 hci_req_complete_skb_t complete_skb)
51{ 56{
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 692cc8b13368..55b2050cc9ff 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -37,6 +37,7 @@ struct hci_request {
37 37
38void hci_req_init(struct hci_request *req, struct hci_dev *hdev); 38void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
39void hci_req_purge(struct hci_request *req); 39void hci_req_purge(struct hci_request *req);
40bool hci_req_status_pend(struct hci_dev *hdev);
40int hci_req_run(struct hci_request *req, hci_req_complete_t complete); 41int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
41int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete); 42int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete);
42void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, 43void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,