Commit 3b420553 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

Bluetooth: hci_sync: Fix attempting to suspend with unfiltered passive scan

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=215768Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent a9a34765
...@@ -1664,20 +1664,19 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev, ...@@ -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; struct hci_cp_le_add_to_accept_list cp;
int err; 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 */ /* Select filter policy to accept all advertising */
if (*num_entries >= hdev->le_accept_list_size) if (*num_entries >= hdev->le_accept_list_size)
return -ENOSPC; return -ENOSPC;
/* Accept list can not be used with RPAs */ /* Accept list can not be used with RPAs */
if (!use_ll_privacy(hdev) && if (!use_ll_privacy(hdev) &&
hci_find_irk_by_addr(hdev, &params->addr, params->addr_type)) { hci_find_irk_by_addr(hdev, &params->addr, params->addr_type))
return -EINVAL; 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 /* Attempt to program the device in the resolving list first to avoid
* having to rollback in case it fails since the resolving list is * having to rollback in case it fails since the resolving list is
...@@ -4913,10 +4912,28 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev) ...@@ -4913,10 +4912,28 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
return 0; 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: /* This function performs the HCI suspend procedures in the follow order:
* *
* Pause discovery (active scanning/inquiry) * Pause discovery (active scanning/inquiry)
* Pause Directed Advertising/Advertising * Pause Directed Advertising/Advertising
* Pause Scanning (passive scanning in case discovery was not active)
* Disconnect all connections * Disconnect all connections
* Set suspend_status to BT_SUSPEND_DISCONNECT if hdev cannot wakeup * Set suspend_status to BT_SUSPEND_DISCONNECT if hdev cannot wakeup
* otherwise: * otherwise:
...@@ -4942,15 +4959,11 @@ int hci_suspend_sync(struct hci_dev *hdev) ...@@ -4942,15 +4959,11 @@ int hci_suspend_sync(struct hci_dev *hdev)
/* Pause other advertisements */ /* Pause other advertisements */
hci_pause_advertising_sync(hdev); 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 */ /* Suspend monitor filters */
hci_suspend_monitor_sync(hdev); hci_suspend_monitor_sync(hdev);
/* Prevent disconnects from causing scanning to be re-enabled */ /* Prevent disconnects from causing scanning to be re-enabled */
hdev->scanning_paused = true; hci_pause_scan_sync(hdev);
/* Soft disconnect everything (power off) */ /* Soft disconnect everything (power off) */
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF); err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
...@@ -5021,6 +5034,22 @@ static void hci_resume_monitor_sync(struct hci_dev *hdev) ...@@ -5021,6 +5034,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: /* This function performs the HCI suspend procedures in the follow order:
* *
* Restore event mask * Restore event mask
...@@ -5043,10 +5072,9 @@ int hci_resume_sync(struct hci_dev *hdev) ...@@ -5043,10 +5072,9 @@ int hci_resume_sync(struct hci_dev *hdev)
/* Clear any event filters and restore scan state */ /* Clear any event filters and restore scan state */
hci_clear_event_filter_sync(hdev); hci_clear_event_filter_sync(hdev);
hci_update_scan_sync(hdev);
/* Reset passive scanning to normal */ /* Resume scanning */
hci_update_passive_scan_sync(hdev); hci_resume_scan_sync(hdev);
/* Resume monitor filters */ /* Resume monitor filters */
hci_resume_monitor_sync(hdev); hci_resume_monitor_sync(hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment