Merge tag 'fixes-non-critical-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / hci_core.c
index 46aa702c189dc671de4c8dd9f7101389993fb7be..3322d3f4c85a25eb4bed8dbfaa1802b907b3f1d3 100644 (file)
@@ -1617,6 +1617,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
                cancel_delayed_work(&hdev->service_cache);
 
        cancel_delayed_work_sync(&hdev->le_scan_disable);
+       cancel_delayed_work_sync(&hdev->le_scan_restart);
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                cancel_delayed_work_sync(&hdev->rpa_expired);
@@ -1640,6 +1641,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        hci_conn_hash_flush(hdev);
        hci_dev_unlock(hdev);
 
+       smp_unregister(hdev);
+
        hci_notify(hdev, HCI_DEV_DOWN);
 
        if (hdev->flush)
@@ -1719,32 +1722,14 @@ done:
        return err;
 }
 
-int hci_dev_reset(__u16 dev)
+static int hci_dev_do_reset(struct hci_dev *hdev)
 {
-       struct hci_dev *hdev;
-       int ret = 0;
+       int ret;
 
-       hdev = hci_dev_get(dev);
-       if (!hdev)
-               return -ENODEV;
+       BT_DBG("%s %p", hdev->name, hdev);
 
        hci_req_lock(hdev);
 
-       if (!test_bit(HCI_UP, &hdev->flags)) {
-               ret = -ENETDOWN;
-               goto done;
-       }
-
-       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
-               ret = -EBUSY;
-               goto done;
-       }
-
-       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
-               ret = -EOPNOTSUPP;
-               goto done;
-       }
-
        /* Drop queues */
        skb_queue_purge(&hdev->rx_q);
        skb_queue_purge(&hdev->cmd_q);
@@ -1767,12 +1752,41 @@ int hci_dev_reset(__u16 dev)
 
        ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
 
-done:
        hci_req_unlock(hdev);
-       hci_dev_put(hdev);
        return ret;
 }
 
+int hci_dev_reset(__u16 dev)
+{
+       struct hci_dev *hdev;
+       int err;
+
+       hdev = hci_dev_get(dev);
+       if (!hdev)
+               return -ENODEV;
+
+       if (!test_bit(HCI_UP, &hdev->flags)) {
+               err = -ENETDOWN;
+               goto done;
+       }
+
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               err = -EBUSY;
+               goto done;
+       }
+
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
+               err = -EOPNOTSUPP;
+               goto done;
+       }
+
+       err = hci_dev_do_reset(hdev);
+
+done:
+       hci_dev_put(hdev);
+       return err;
+}
+
 int hci_dev_reset_stat(__u16 dev)
 {
        struct hci_dev *hdev;
@@ -2136,8 +2150,24 @@ static void hci_power_off(struct work_struct *work)
        BT_DBG("%s", hdev->name);
 
        hci_dev_do_close(hdev);
+}
 
-       smp_unregister(hdev);
+static void hci_error_reset(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev, error_reset);
+
+       BT_DBG("%s", hdev->name);
+
+       if (hdev->hw_error)
+               hdev->hw_error(hdev, hdev->hw_error_code);
+       else
+               BT_ERR("%s hardware error 0x%2.2x", hdev->name,
+                      hdev->hw_error_code);
+
+       if (hci_dev_do_close(hdev))
+               return;
+
+       hci_dev_do_open(hdev);
 }
 
 static void hci_discov_off(struct work_struct *work)
@@ -2552,9 +2582,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
        if (hash192 && rand192) {
                memcpy(data->hash192, hash192, sizeof(data->hash192));
                memcpy(data->rand192, rand192, sizeof(data->rand192));
+               if (hash256 && rand256)
+                       data->present = 0x03;
        } else {
                memset(data->hash192, 0, sizeof(data->hash192));
                memset(data->rand192, 0, sizeof(data->rand192));
+               if (hash256 && rand256)
+                       data->present = 0x02;
+               else
+                       data->present = 0x00;
        }
 
        if (hash256 && rand256) {
@@ -2563,6 +2599,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
        } else {
                memset(data->hash256, 0, sizeof(data->hash256));
                memset(data->rand256, 0, sizeof(data->rand256));
+               if (hash192 && rand192)
+                       data->present = 0x01;
        }
 
        BT_DBG("%s for %pMR", hdev->name, bdaddr);
@@ -2793,6 +2831,8 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status,
                return;
        }
 
+       hdev->discovery.scan_start = 0;
+
        switch (hdev->discovery.type) {
        case DISCOV_TYPE_LE:
                hci_dev_lock(hdev);
@@ -2832,6 +2872,8 @@ static void le_scan_disable_work(struct work_struct *work)
 
        BT_DBG("%s", hdev->name);
 
+       cancel_delayed_work_sync(&hdev->le_scan_restart);
+
        hci_req_init(&req, hdev);
 
        hci_req_add_le_scan_disable(&req);
@@ -2841,6 +2883,74 @@ static void le_scan_disable_work(struct work_struct *work)
                BT_ERR("Disable LE scanning request failed: err %d", err);
 }
 
+static void le_scan_restart_work_complete(struct hci_dev *hdev, u8 status,
+                                         u16 opcode)
+{
+       unsigned long timeout, duration, scan_start, now;
+
+       BT_DBG("%s", hdev->name);
+
+       if (status) {
+               BT_ERR("Failed to restart LE scan: status %d", status);
+               return;
+       }
+
+       if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
+           !hdev->discovery.scan_start)
+               return;
+
+       /* When the scan was started, hdev->le_scan_disable has been queued
+        * after duration from scan_start. During scan restart this job
+        * has been canceled, and we need to queue it again after proper
+        * timeout, to make sure that scan does not run indefinitely.
+        */
+       duration = hdev->discovery.scan_duration;
+       scan_start = hdev->discovery.scan_start;
+       now = jiffies;
+       if (now - scan_start <= duration) {
+               int elapsed;
+
+               if (now >= scan_start)
+                       elapsed = now - scan_start;
+               else
+                       elapsed = ULONG_MAX - scan_start + now;
+
+               timeout = duration - elapsed;
+       } else {
+               timeout = 0;
+       }
+       queue_delayed_work(hdev->workqueue,
+                          &hdev->le_scan_disable, timeout);
+}
+
+static void le_scan_restart_work(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           le_scan_restart.work);
+       struct hci_request req;
+       struct hci_cp_le_set_scan_enable cp;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       /* If controller is not scanning we are done. */
+       if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+               return;
+
+       hci_req_init(&req, hdev);
+
+       hci_req_add_le_scan_disable(&req);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = LE_SCAN_ENABLE;
+       cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+       hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+
+       err = hci_req_run(&req, le_scan_restart_work_complete);
+       if (err)
+               BT_ERR("Restart LE scan request failed: err %d", err);
+}
+
 /* Copy the Identity Address of the controller.
  *
  * If the controller has a public BD_ADDR, then by default use that one.
@@ -2932,10 +3042,12 @@ struct hci_dev *hci_alloc_dev(void)
        INIT_WORK(&hdev->cmd_work, hci_cmd_work);
        INIT_WORK(&hdev->tx_work, hci_tx_work);
        INIT_WORK(&hdev->power_on, hci_power_on);
+       INIT_WORK(&hdev->error_reset, hci_error_reset);
 
        INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
        INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
        INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+       INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
 
        skb_queue_head_init(&hdev->rx_q);
        skb_queue_head_init(&hdev->cmd_q);
@@ -3105,8 +3217,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
-       smp_unregister(hdev);
-
        device_del(&hdev->dev);
 
        debugfs_remove_recursive(hdev->debugfs);