Bluetooth: hci_sync: Only allow hci_cmd_sync_queue if running
This makes sure hci_cmd_sync_queue only queue new work if HCI_RUNNING has been set otherwise there is a risk of commands being sent while turning off. Because hci_cmd_sync_queue can no longer queue work while HCI_RUNNING is not set it cannot be used to power on adapters so instead hci_cmd_sync_submit is introduced which bypass the HCI_RUNNING check, so it behaves like the old implementation. Link: https://lore.kernel.org/all/CAB4PzUpDMvdc8j2MdeSAy1KkAE-D3woprCwAdYWeOc-3v3c9Sw@mail.gmail.com/ Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Родитель
20981ce2d5
Коммит
d883a4669a
|
@ -41,6 +41,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev);
|
|||
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
|
||||
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
|
||||
|
||||
int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy);
|
||||
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy);
|
||||
|
||||
|
|
|
@ -684,8 +684,12 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
|
|||
}
|
||||
EXPORT_SYMBOL(hci_cmd_sync_cancel);
|
||||
|
||||
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy)
|
||||
/* Submit HCI command to be run in as cmd_sync_work:
|
||||
*
|
||||
* - hdev must _not_ be unregistered
|
||||
*/
|
||||
int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy)
|
||||
{
|
||||
struct hci_cmd_sync_work_entry *entry;
|
||||
|
||||
|
@ -708,6 +712,23 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_cmd_sync_submit);
|
||||
|
||||
/* Queue HCI command:
|
||||
*
|
||||
* - hdev must be running
|
||||
*/
|
||||
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy)
|
||||
{
|
||||
/* Only queue command if hdev is running which means it had been opened
|
||||
* and is either on init phase or is already up.
|
||||
*/
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -ENETDOWN;
|
||||
|
||||
return hci_cmd_sync_submit(hdev, func, data, destroy);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_cmd_sync_queue);
|
||||
|
||||
int hci_update_eir_sync(struct hci_dev *hdev)
|
||||
|
|
|
@ -1400,11 +1400,15 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
}
|
||||
|
||||
/* Cancel potentially blocking sync operation before power off */
|
||||
if (cp->val == 0x00)
|
||||
if (cp->val == 0x00) {
|
||||
__hci_cmd_sync_cancel(hdev, -EHOSTDOWN);
|
||||
|
||||
err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
|
||||
mgmt_set_powered_complete);
|
||||
err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
|
||||
mgmt_set_powered_complete);
|
||||
} else {
|
||||
/* Use hci_cmd_sync_submit since hdev might not be running */
|
||||
err = hci_cmd_sync_submit(hdev, set_powered_sync, cmd,
|
||||
mgmt_set_powered_complete);
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
mgmt_pending_remove(cmd);
|
||||
|
|
Загрузка…
Ссылка в новой задаче