summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_event.c
diff options
context:
space:
mode:
authorKiran K <kiran.k@intel.com>2021-08-16 01:37:47 +0200
committerMarcel Holtmann <marcel@holtmann.org>2021-08-16 18:04:23 +0200
commitecb71f2566673553bc067e5b0036756871d0b9d3 (patch)
tree9513dedd4d026f232947452601b3ee9bb0ed8e16 /net/bluetooth/hci_event.c
parentBluetooth: btbcm: add patch ram for bluetooth (diff)
downloadlinux-ecb71f2566673553bc067e5b0036756871d0b9d3.tar.xz
linux-ecb71f2566673553bc067e5b0036756871d0b9d3.zip
Bluetooth: Fix race condition in handling NOP command
For NOP command, need to cancel work scheduled on cmd_timer, on receiving command status or commmand complete event. Below use case might lead to race condition multiple when NOP commands are queued sequentially: hci_cmd_work() { if (atomic_read(&hdev->cmd_cnt) { . . . atomic_dec(&hdev->cmd_cnt); hci_send_frame(hdev,...); schedule_delayed_work(&hdev->cmd_timer,...); } } On receiving event for first NOP, the work scheduled on hdev->cmd_timer is not cancelled and second NOP is dequeued and sent to controller. While waiting for an event for second NOP command, work scheduled on cmd_timer for the first NOP can get scheduled, resulting in sending third NOP command (sending back to back NOP commands). This might cause issues at controller side (like memory overrun, controller going unresponsive) resulting in hci tx timeouts, hardware errors etc. The fix to this issue is to cancel the delayed work scheduled on cmd_timer on receiving command status or command complete event for NOP command (this patch handles NOP command same as any other SIG command). Signed-off-by: Kiran K <kiran.k@intel.com> Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com> Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com> Acked-by: Manish Mandlik <mmandlik@google.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r--net/bluetooth/hci_event.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1ee89d9b2ed4..0bca035bf2dc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3311,11 +3311,9 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev,
- u16 opcode, u8 ncmd)
+static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev, u8 ncmd)
{
- if (opcode != HCI_OP_NOP)
- cancel_delayed_work(&hdev->cmd_timer);
+ cancel_delayed_work(&hdev->cmd_timer);
if (!test_bit(HCI_RESET, &hdev->flags)) {
if (ncmd) {
@@ -3690,7 +3688,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
break;
}
- handle_cmd_cnt_and_timer(hdev, *opcode, ev->ncmd);
+ handle_cmd_cnt_and_timer(hdev, ev->ncmd);
hci_req_cmd_complete(hdev, *opcode, *status, req_complete,
req_complete_skb);
@@ -3791,7 +3789,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
break;
}
- handle_cmd_cnt_and_timer(hdev, *opcode, ev->ncmd);
+ handle_cmd_cnt_and_timer(hdev, ev->ncmd);
/* Indicate request completion if the command failed. Also, if
* we're not waiting for a special event and we get a success