| From ae35bef17d17dae5e945fb9237c4892ca3e4a111 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 12 May 2022 15:31:34 -0700 |
| Subject: Bluetooth: hci_sync: Fix attempting to suspend with unfiltered |
| passive scan |
| |
| From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| |
| [ Upstream commit 3b42055388c30f2761a2d9cd9af2c99611dfe457 ] |
| |
| When suspending the passive scanning _must_ have its filter_policy set |
| to 0x01 to use the accept list otherwise _any_ advertise report would |
| end up waking up the system. |
| |
| In order to fix the filter_policy the code now checks for |
| hdev->suspended && HCI_CONN_FLAG_REMOTE_WAKEUP |
| first, since the MGMT_OP_SET_DEVICE_FLAGS will reject any attempt to |
| set HCI_CONN_FLAG_REMOTE_WAKEUP when it cannot be programmed in the |
| acceptlist, so it can return success causing the proper filter_policy |
| to be used. |
| |
| Link: https://bugzilla.kernel.org/show_bug.cgi?id=215768 |
| Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> |
| Signed-off-by: Marcel Holtmann <marcel@holtmann.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/bluetooth/hci_sync.c | 58 +++++++++++++++++++++++++++++----------- |
| 1 file changed, 43 insertions(+), 15 deletions(-) |
| |
| diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c |
| index 13600bf120b0..6b8d1cd65de4 100644 |
| --- a/net/bluetooth/hci_sync.c |
| +++ b/net/bluetooth/hci_sync.c |
| @@ -1664,20 +1664,19 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev, |
| struct hci_cp_le_add_to_accept_list cp; |
| int err; |
| |
| + /* During suspend, only wakeable devices can be in acceptlist */ |
| + if (hdev->suspended && |
| + !test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags)) |
| + return 0; |
| + |
| /* Select filter policy to accept all advertising */ |
| if (*num_entries >= hdev->le_accept_list_size) |
| return -ENOSPC; |
| |
| /* Accept list can not be used with RPAs */ |
| if (!use_ll_privacy(hdev) && |
| - hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type)) { |
| + hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type)) |
| return -EINVAL; |
| - } |
| - |
| - /* During suspend, only wakeable devices can be in acceptlist */ |
| - if (hdev->suspended && |
| - !test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags)) |
| - return 0; |
| |
| /* Attempt to program the device in the resolving list first to avoid |
| * having to rollback in case it fails since the resolving list is |
| @@ -4881,10 +4880,28 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev) |
| return 0; |
| } |
| |
| +/* This function disables scan (BR and LE) and mark it as paused */ |
| +static int hci_pause_scan_sync(struct hci_dev *hdev) |
| +{ |
| + if (hdev->scanning_paused) |
| + return 0; |
| + |
| + /* Disable page scan if enabled */ |
| + if (test_bit(HCI_PSCAN, &hdev->flags)) |
| + hci_write_scan_enable_sync(hdev, SCAN_DISABLED); |
| + |
| + hci_scan_disable_sync(hdev); |
| + |
| + hdev->scanning_paused = true; |
| + |
| + return 0; |
| +} |
| + |
| /* This function performs the HCI suspend procedures in the follow order: |
| * |
| * Pause discovery (active scanning/inquiry) |
| * Pause Directed Advertising/Advertising |
| + * Pause Scanning (passive scanning in case discovery was not active) |
| * Disconnect all connections |
| * Set suspend_status to BT_SUSPEND_DISCONNECT if hdev cannot wakeup |
| * otherwise: |
| @@ -4910,15 +4927,11 @@ int hci_suspend_sync(struct hci_dev *hdev) |
| /* Pause other advertisements */ |
| hci_pause_advertising_sync(hdev); |
| |
| - /* Disable page scan if enabled */ |
| - if (test_bit(HCI_PSCAN, &hdev->flags)) |
| - hci_write_scan_enable_sync(hdev, SCAN_DISABLED); |
| - |
| /* Suspend monitor filters */ |
| hci_suspend_monitor_sync(hdev); |
| |
| /* Prevent disconnects from causing scanning to be re-enabled */ |
| - hdev->scanning_paused = true; |
| + hci_pause_scan_sync(hdev); |
| |
| /* Soft disconnect everything (power off) */ |
| err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF); |
| @@ -4989,6 +5002,22 @@ static void hci_resume_monitor_sync(struct hci_dev *hdev) |
| } |
| } |
| |
| +/* This function resume scan and reset paused flag */ |
| +static int hci_resume_scan_sync(struct hci_dev *hdev) |
| +{ |
| + if (!hdev->scanning_paused) |
| + return 0; |
| + |
| + hci_update_scan_sync(hdev); |
| + |
| + /* Reset passive scanning to normal */ |
| + hci_update_passive_scan_sync(hdev); |
| + |
| + hdev->scanning_paused = false; |
| + |
| + return 0; |
| +} |
| + |
| /* This function performs the HCI suspend procedures in the follow order: |
| * |
| * Restore event mask |
| @@ -5011,10 +5040,9 @@ int hci_resume_sync(struct hci_dev *hdev) |
| |
| /* Clear any event filters and restore scan state */ |
| hci_clear_event_filter_sync(hdev); |
| - hci_update_scan_sync(hdev); |
| |
| - /* Reset passive scanning to normal */ |
| - hci_update_passive_scan_sync(hdev); |
| + /* Resume scanning */ |
| + hci_resume_scan_sync(hdev); |
| |
| /* Resume monitor filters */ |
| hci_resume_monitor_sync(hdev); |
| -- |
| 2.35.1 |
| |