aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_request.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-11-16 05:52:21 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-12-09 18:51:47 -0500
commit01b1cb87d37fb19cdaa5e7002416fdde156873d0 (patch)
tree87fdc0ba8b3872cea7267fb3a3b3b7ed101ffbba /net/bluetooth/hci_request.c
parentad2c8c73d29702c3193f739390f6661f9a4ecad9 (diff)
Bluetooth: Run page scan updates through hdev->req_workqueue
Since Add/Remove Device perform the page scan updates independently from the HCI command completion we've introduced a potential race when multiple mgmt commands are queued. Doing the page scan updates through the req_workqueue ensures that the state changes are performed in a race-free manner. At the same time, to make the request helper more widely usable, extend it to also cover Inquiry Scan changes since those are behind the same HCI command. This is also reflected in the new name of the API as well as the work struct name. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_request.c')
-rw-r--r--net/bluetooth/hci_request.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index e639671f54bd..78c026b4ffa1 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -637,7 +637,7 @@ static bool disconnected_whitelist_entries(struct hci_dev *hdev)
637 return false; 637 return false;
638} 638}
639 639
640void __hci_update_page_scan(struct hci_request *req) 640void __hci_req_update_scan(struct hci_request *req)
641{ 641{
642 struct hci_dev *hdev = req->hdev; 642 struct hci_dev *hdev = req->hdev;
643 u8 scan; 643 u8 scan;
@@ -657,22 +657,29 @@ void __hci_update_page_scan(struct hci_request *req)
657 else 657 else
658 scan = SCAN_DISABLED; 658 scan = SCAN_DISABLED;
659 659
660 if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE))
661 return;
662
663 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) 660 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
664 scan |= SCAN_INQUIRY; 661 scan |= SCAN_INQUIRY;
665 662
663 if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE) &&
664 test_bit(HCI_ISCAN, &hdev->flags) == !!(scan & SCAN_INQUIRY))
665 return;
666
666 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); 667 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
667} 668}
668 669
669void hci_update_page_scan(struct hci_dev *hdev) 670static int update_scan(struct hci_request *req, unsigned long opt)
670{ 671{
671 struct hci_request req; 672 hci_dev_lock(req->hdev);
673 __hci_req_update_scan(req);
674 hci_dev_unlock(req->hdev);
675 return 0;
676}
672 677
673 hci_req_init(&req, hdev); 678static void scan_update_work(struct work_struct *work)
674 __hci_update_page_scan(&req); 679{
675 hci_req_run(&req, NULL); 680 struct hci_dev *hdev = container_of(work, struct hci_dev, scan_update);
681
682 hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL);
676} 683}
677 684
678/* This function controls the background scanning based on hdev->pend_le_conns 685/* This function controls the background scanning based on hdev->pend_le_conns
@@ -1270,6 +1277,7 @@ void hci_request_setup(struct hci_dev *hdev)
1270{ 1277{
1271 INIT_WORK(&hdev->discov_update, discov_update); 1278 INIT_WORK(&hdev->discov_update, discov_update);
1272 INIT_WORK(&hdev->bg_scan_update, bg_scan_update); 1279 INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
1280 INIT_WORK(&hdev->scan_update, scan_update_work);
1273 INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); 1281 INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
1274 INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); 1282 INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
1275} 1283}
@@ -1280,6 +1288,7 @@ void hci_request_cancel_all(struct hci_dev *hdev)
1280 1288
1281 cancel_work_sync(&hdev->discov_update); 1289 cancel_work_sync(&hdev->discov_update);
1282 cancel_work_sync(&hdev->bg_scan_update); 1290 cancel_work_sync(&hdev->bg_scan_update);
1291 cancel_work_sync(&hdev->scan_update);
1283 cancel_delayed_work_sync(&hdev->le_scan_disable); 1292 cancel_delayed_work_sync(&hdev->le_scan_disable);
1284 cancel_delayed_work_sync(&hdev->le_scan_restart); 1293 cancel_delayed_work_sync(&hdev->le_scan_restart);
1285} 1294}