Bluetooth: Fix race condition in hidp_session_thread
[platform/kernel/linux-starfive.git] / net / bluetooth / hci_core.c
index 0540555..334e308 100644 (file)
@@ -2660,7 +2660,7 @@ int hci_register_dev(struct hci_dev *hdev)
 
        error = hci_register_suspend_notifier(hdev);
        if (error)
-               goto err_wqueue;
+               BT_WARN("register suspend notifier failed error:%d\n", error);
 
        queue_work(hdev->req_workqueue, &hdev->power_on);
 
@@ -2764,7 +2764,8 @@ int hci_register_suspend_notifier(struct hci_dev *hdev)
 {
        int ret = 0;
 
-       if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
+       if (!hdev->suspend_notifier.notifier_call &&
+           !test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
                hdev->suspend_notifier.notifier_call = hci_suspend_notifier;
                ret = register_pm_notifier(&hdev->suspend_notifier);
        }
@@ -2776,8 +2777,11 @@ int hci_unregister_suspend_notifier(struct hci_dev *hdev)
 {
        int ret = 0;
 
-       if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
+       if (hdev->suspend_notifier.notifier_call) {
                ret = unregister_pm_notifier(&hdev->suspend_notifier);
+               if (!ret)
+                       hdev->suspend_notifier.notifier_call = NULL;
+       }
 
        return ret;
 }
@@ -2867,10 +2871,25 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
                return -ENXIO;
        }
 
-       if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
-           hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
-           hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
-           hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
+       switch (hci_skb_pkt_type(skb)) {
+       case HCI_EVENT_PKT:
+               break;
+       case HCI_ACLDATA_PKT:
+               /* Detect if ISO packet has been sent as ACL */
+               if (hci_conn_num(hdev, ISO_LINK)) {
+                       __u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
+                       __u8 type;
+
+                       type = hci_conn_lookup_type(hdev, hci_handle(handle));
+                       if (type == ISO_LINK)
+                               hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
+               }
+               break;
+       case HCI_SCODATA_PKT:
+               break;
+       case HCI_ISODATA_PKT:
+               break;
+       default:
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -3981,7 +4000,7 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
                        *req_complete_skb = bt_cb(skb)->hci.req_complete_skb;
                else
                        *req_complete = bt_cb(skb)->hci.req_complete;
-               kfree_skb(skb);
+               dev_kfree_skb_irq(skb);
        }
        spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
 }