diff options
| author | Jakub Pawlowski <jpawlowski@google.com> | 2015-02-02 02:07:54 -0500 |
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2015-02-02 02:52:33 -0500 |
| commit | 2d28cfe7aada495f87bb439151e9bcc86998fb6d (patch) | |
| tree | 732485826c4bf96c215fc716926e9a31809b5c69 | |
| parent | 3251ca334bcc379b4685bf6850bf38db365cbe6f (diff) | |
Bluetooth: Add le_scan_restart work for LE scan restarting
Currently there is no way to restart le scan, and it's needed in
service scan method. The way it work: it disable, and then enable le
scan on controller.
During the restart, we must remember when the scan was started, and
it's duration, to later re-schedule the le_scan_disable work, that was
stopped during the stop scan phase.
Signed-off-by: Jakub Pawlowski <jpawlowski@google.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
| -rw-r--r-- | include/net/bluetooth/hci_core.h | 5 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 74 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 19 |
3 files changed, 97 insertions, 1 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a37e10f4e2b3..d3a232be9d9b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
| @@ -79,6 +79,8 @@ struct discovery_state { | |||
| 79 | s8 rssi; | 79 | s8 rssi; |
| 80 | u16 uuid_count; | 80 | u16 uuid_count; |
| 81 | u8 (*uuids)[16]; | 81 | u8 (*uuids)[16]; |
| 82 | unsigned long scan_start; | ||
| 83 | unsigned long scan_duration; | ||
| 82 | }; | 84 | }; |
| 83 | 85 | ||
| 84 | struct hci_conn_hash { | 86 | struct hci_conn_hash { |
| @@ -354,6 +356,7 @@ struct hci_dev { | |||
| 354 | unsigned long dev_flags; | 356 | unsigned long dev_flags; |
| 355 | 357 | ||
| 356 | struct delayed_work le_scan_disable; | 358 | struct delayed_work le_scan_disable; |
| 359 | struct delayed_work le_scan_restart; | ||
| 357 | 360 | ||
| 358 | __s8 adv_tx_power; | 361 | __s8 adv_tx_power; |
| 359 | __u8 adv_data[HCI_MAX_AD_LENGTH]; | 362 | __u8 adv_data[HCI_MAX_AD_LENGTH]; |
| @@ -531,6 +534,8 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev) | |||
| 531 | hdev->discovery.uuid_count = 0; | 534 | hdev->discovery.uuid_count = 0; |
| 532 | kfree(hdev->discovery.uuids); | 535 | kfree(hdev->discovery.uuids); |
| 533 | hdev->discovery.uuids = NULL; | 536 | hdev->discovery.uuids = NULL; |
| 537 | hdev->discovery.scan_start = 0; | ||
| 538 | hdev->discovery.scan_duration = 0; | ||
| 534 | } | 539 | } |
| 535 | 540 | ||
| 536 | bool hci_discovery_active(struct hci_dev *hdev); | 541 | bool hci_discovery_active(struct hci_dev *hdev); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f045c062f8f0..3322d3f4c85a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -1617,6 +1617,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 1617 | cancel_delayed_work(&hdev->service_cache); | 1617 | cancel_delayed_work(&hdev->service_cache); |
| 1618 | 1618 | ||
| 1619 | cancel_delayed_work_sync(&hdev->le_scan_disable); | 1619 | cancel_delayed_work_sync(&hdev->le_scan_disable); |
| 1620 | cancel_delayed_work_sync(&hdev->le_scan_restart); | ||
| 1620 | 1621 | ||
| 1621 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | 1622 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) |
| 1622 | cancel_delayed_work_sync(&hdev->rpa_expired); | 1623 | cancel_delayed_work_sync(&hdev->rpa_expired); |
| @@ -2830,6 +2831,8 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, | |||
| 2830 | return; | 2831 | return; |
| 2831 | } | 2832 | } |
| 2832 | 2833 | ||
| 2834 | hdev->discovery.scan_start = 0; | ||
| 2835 | |||
| 2833 | switch (hdev->discovery.type) { | 2836 | switch (hdev->discovery.type) { |
| 2834 | case DISCOV_TYPE_LE: | 2837 | case DISCOV_TYPE_LE: |
| 2835 | hci_dev_lock(hdev); | 2838 | hci_dev_lock(hdev); |
| @@ -2869,6 +2872,8 @@ static void le_scan_disable_work(struct work_struct *work) | |||
| 2869 | 2872 | ||
| 2870 | BT_DBG("%s", hdev->name); | 2873 | BT_DBG("%s", hdev->name); |
| 2871 | 2874 | ||
| 2875 | cancel_delayed_work_sync(&hdev->le_scan_restart); | ||
| 2876 | |||
| 2872 | hci_req_init(&req, hdev); | 2877 | hci_req_init(&req, hdev); |
| 2873 | 2878 | ||
| 2874 | hci_req_add_le_scan_disable(&req); | 2879 | hci_req_add_le_scan_disable(&req); |
| @@ -2878,6 +2883,74 @@ static void le_scan_disable_work(struct work_struct *work) | |||
| 2878 | BT_ERR("Disable LE scanning request failed: err %d", err); | 2883 | BT_ERR("Disable LE scanning request failed: err %d", err); |
| 2879 | } | 2884 | } |
| 2880 | 2885 | ||
| 2886 | static void le_scan_restart_work_complete(struct hci_dev *hdev, u8 status, | ||
| 2887 | u16 opcode) | ||
| 2888 | { | ||
| 2889 | unsigned long timeout, duration, scan_start, now; | ||
| 2890 | |||
| 2891 | BT_DBG("%s", hdev->name); | ||
| 2892 | |||
| 2893 | if (status) { | ||
| 2894 | BT_ERR("Failed to restart LE scan: status %d", status); | ||
| 2895 | return; | ||
| 2896 | } | ||
| 2897 | |||
| 2898 | if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) || | ||
| 2899 | !hdev->discovery.scan_start) | ||
| 2900 | return; | ||
| 2901 | |||
| 2902 | /* When the scan was started, hdev->le_scan_disable has been queued | ||
| 2903 | * after duration from scan_start. During scan restart this job | ||
| 2904 | * has been canceled, and we need to queue it again after proper | ||
| 2905 | * timeout, to make sure that scan does not run indefinitely. | ||
| 2906 | */ | ||
| 2907 | duration = hdev->discovery.scan_duration; | ||
| 2908 | scan_start = hdev->discovery.scan_start; | ||
| 2909 | now = jiffies; | ||
| 2910 | if (now - scan_start <= duration) { | ||
| 2911 | int elapsed; | ||
| 2912 | |||
| 2913 | if (now >= scan_start) | ||
| 2914 | elapsed = now - scan_start; | ||
| 2915 | else | ||
| 2916 | elapsed = ULONG_MAX - scan_start + now; | ||
| 2917 | |||
| 2918 | timeout = duration - elapsed; | ||
| 2919 | } else { | ||
| 2920 | timeout = 0; | ||
| 2921 | } | ||
| 2922 | queue_delayed_work(hdev->workqueue, | ||
| 2923 | &hdev->le_scan_disable, timeout); | ||
| 2924 | } | ||
| 2925 | |||
| 2926 | static void le_scan_restart_work(struct work_struct *work) | ||
| 2927 | { | ||
| 2928 | struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
| 2929 | le_scan_restart.work); | ||
| 2930 | struct hci_request req; | ||
| 2931 | struct hci_cp_le_set_scan_enable cp; | ||
| 2932 | int err; | ||
| 2933 | |||
| 2934 | BT_DBG("%s", hdev->name); | ||
| 2935 | |||
| 2936 | /* If controller is not scanning we are done. */ | ||
| 2937 | if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) | ||
| 2938 | return; | ||
| 2939 | |||
| 2940 | hci_req_init(&req, hdev); | ||
| 2941 | |||
| 2942 | hci_req_add_le_scan_disable(&req); | ||
| 2943 | |||
| 2944 | memset(&cp, 0, sizeof(cp)); | ||
| 2945 | cp.enable = LE_SCAN_ENABLE; | ||
| 2946 | cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; | ||
| 2947 | hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); | ||
| 2948 | |||
| 2949 | err = hci_req_run(&req, le_scan_restart_work_complete); | ||
| 2950 | if (err) | ||
| 2951 | BT_ERR("Restart LE scan request failed: err %d", err); | ||
| 2952 | } | ||
| 2953 | |||
| 2881 | /* Copy the Identity Address of the controller. | 2954 | /* Copy the Identity Address of the controller. |
| 2882 | * | 2955 | * |
| 2883 | * If the controller has a public BD_ADDR, then by default use that one. | 2956 | * If the controller has a public BD_ADDR, then by default use that one. |
| @@ -2974,6 +3047,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 2974 | INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); | 3047 | INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); |
| 2975 | INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); | 3048 | INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); |
| 2976 | INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); | 3049 | INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); |
| 3050 | INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); | ||
| 2977 | 3051 | ||
| 2978 | skb_queue_head_init(&hdev->rx_q); | 3052 | skb_queue_head_init(&hdev->rx_q); |
| 2979 | skb_queue_head_init(&hdev->cmd_q); | 3053 | skb_queue_head_init(&hdev->cmd_q); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ba3b4a5820b1..8c2520a7f386 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -3896,6 +3896,9 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status, | |||
| 3896 | 3896 | ||
| 3897 | hci_discovery_set_state(hdev, DISCOVERY_FINDING); | 3897 | hci_discovery_set_state(hdev, DISCOVERY_FINDING); |
| 3898 | 3898 | ||
| 3899 | /* If the scan involves LE scan, pick proper timeout to schedule | ||
| 3900 | * hdev->le_scan_disable that will stop it. | ||
| 3901 | */ | ||
| 3899 | switch (hdev->discovery.type) { | 3902 | switch (hdev->discovery.type) { |
| 3900 | case DISCOV_TYPE_LE: | 3903 | case DISCOV_TYPE_LE: |
| 3901 | timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); | 3904 | timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT); |
| @@ -3912,9 +3915,23 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status, | |||
| 3912 | break; | 3915 | break; |
| 3913 | } | 3916 | } |
| 3914 | 3917 | ||
| 3915 | if (timeout) | 3918 | if (timeout) { |
| 3919 | /* When service discovery is used and the controller has | ||
| 3920 | * a strict duplicate filter, it is important to remember | ||
| 3921 | * the start and duration of the scan. This is required | ||
| 3922 | * for restarting scanning during the discovery phase. | ||
| 3923 | */ | ||
| 3924 | if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, | ||
| 3925 | &hdev->quirks) && | ||
| 3926 | (hdev->discovery.uuid_count > 0 || | ||
| 3927 | hdev->discovery.rssi != HCI_RSSI_INVALID)) { | ||
| 3928 | hdev->discovery.scan_start = jiffies; | ||
| 3929 | hdev->discovery.scan_duration = timeout; | ||
| 3930 | } | ||
| 3931 | |||
| 3916 | queue_delayed_work(hdev->workqueue, | 3932 | queue_delayed_work(hdev->workqueue, |
| 3917 | &hdev->le_scan_disable, timeout); | 3933 | &hdev->le_scan_disable, timeout); |
| 3934 | } | ||
| 3918 | 3935 | ||
| 3919 | unlock: | 3936 | unlock: |
| 3920 | hci_dev_unlock(hdev); | 3937 | hci_dev_unlock(hdev); |
