diff options
author | Benjamin Berg <bberg@redhat.com> | 2021-12-03 15:59:01 +0100 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2021-12-03 10:41:59 -0800 |
commit | 2250abadd3508d6961f1aa56cf8cff59f0196cb8 (patch) | |
tree | 7efa8e9fe7cc7020c723711599f5d04e4dd9867e /net | |
parent | 914b08b330d6722ed081e14580aae6fe66cd5946 (diff) | |
download | linux-2250abadd3508d6961f1aa56cf8cff59f0196cb8.tar.bz2 |
Bluetooth: hci_core: Cancel sync command if sending a frame failed
If sending a frame failed any sync command associated with it will never
be completed. As such, cancel any such command immediately to avoid
timing out.
Signed-off-by: Benjamin Berg <bberg@redhat.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fdc0dcf8ee36..5cadecd31f66 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2906,7 +2906,7 @@ int hci_unregister_cb(struct hci_cb *cb) } EXPORT_SYMBOL(hci_unregister_cb); -static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +static int hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { int err; @@ -2929,14 +2929,17 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) if (!test_bit(HCI_RUNNING, &hdev->flags)) { kfree_skb(skb); - return; + return -EINVAL; } err = hdev->send(hdev, skb); if (err < 0) { bt_dev_err(hdev, "sending frame failed (%d)", err); kfree_skb(skb); + return err; } + + return 0; } /* Send HCI command */ @@ -3843,10 +3846,15 @@ static void hci_cmd_work(struct work_struct *work) hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); if (hdev->sent_cmd) { + int res; if (hci_req_status_pend(hdev)) hci_dev_set_flag(hdev, HCI_CMD_PENDING); atomic_dec(&hdev->cmd_cnt); - hci_send_frame(hdev, skb); + + res = hci_send_frame(hdev, skb); + if (res < 0) + hci_cmd_sync_cancel(hdev, -res); + if (test_bit(HCI_RESET, &hdev->flags)) cancel_delayed_work(&hdev->cmd_timer); else |