mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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=215768 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
		
							parent
							
								
									a9a347655d
								
							
						
					
					
						commit
						3b42055388
					
				
					 1 changed files with 43 additions and 15 deletions
				
			
		| 
						 | 
					@ -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, ¶ms->addr, params->addr_type)) {
 | 
						    hci_find_irk_by_addr(hdev, ¶ms->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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	/* 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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue