summaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-11-22 08:43:43 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-12-09 18:51:48 -0500
commit53c0ba74510c1182786dcd1e3710215467777601 (patch)
treed3099c9fa312136b2c1b9e958f78944386f22240 /net/bluetooth
parentf22525700b2ae34eb97a29a91e2eee902062b484 (diff)
Bluetooth: Move connectable changes to hdev->req_workqueue
This way the connectable changes are synchronized against each other, which helps avoid potential races. The connectable mode is also linked together with LE advertising which makes is more convenient to have it behind the same workqueue. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_request.c39
-rw-r--r--net/bluetooth/mgmt.c86
2 files changed, 51 insertions, 74 deletions
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index e6622bd1926d..167c90644b4b 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1274,6 +1274,43 @@ static void scan_update_work(struct work_struct *work)
1274 hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL); 1274 hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL);
1275} 1275}
1276 1276
1277static int connectable_update(struct hci_request *req, unsigned long opt)
1278{
1279 struct hci_dev *hdev = req->hdev;
1280
1281 hci_dev_lock(hdev);
1282
1283 __hci_req_update_scan(req);
1284
1285 /* If BR/EDR is not enabled and we disable advertising as a
1286 * by-product of disabling connectable, we need to update the
1287 * advertising flags.
1288 */
1289 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
1290 __hci_req_update_adv_data(req, HCI_ADV_CURRENT);
1291
1292 /* Update the advertising parameters if necessary */
1293 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
1294 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
1295 __hci_req_enable_advertising(req);
1296
1297 __hci_update_background_scan(req);
1298
1299 hci_dev_unlock(hdev);
1300
1301 return 0;
1302}
1303
1304static void connectable_update_work(struct work_struct *work)
1305{
1306 struct hci_dev *hdev = container_of(work, struct hci_dev,
1307 connectable_update);
1308 u8 status;
1309
1310 hci_req_sync(hdev, connectable_update, 0, HCI_CMD_TIMEOUT, &status);
1311 mgmt_set_connectable_complete(hdev, status);
1312}
1313
1277void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn, 1314void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
1278 u8 reason) 1315 u8 reason)
1279{ 1316{
@@ -1789,6 +1826,7 @@ void hci_request_setup(struct hci_dev *hdev)
1789 INIT_WORK(&hdev->discov_update, discov_update); 1826 INIT_WORK(&hdev->discov_update, discov_update);
1790 INIT_WORK(&hdev->bg_scan_update, bg_scan_update); 1827 INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
1791 INIT_WORK(&hdev->scan_update, scan_update_work); 1828 INIT_WORK(&hdev->scan_update, scan_update_work);
1829 INIT_WORK(&hdev->connectable_update, connectable_update_work);
1792 INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); 1830 INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
1793 INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); 1831 INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
1794 INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire); 1832 INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
@@ -1801,6 +1839,7 @@ void hci_request_cancel_all(struct hci_dev *hdev)
1801 cancel_work_sync(&hdev->discov_update); 1839 cancel_work_sync(&hdev->discov_update);
1802 cancel_work_sync(&hdev->bg_scan_update); 1840 cancel_work_sync(&hdev->bg_scan_update);
1803 cancel_work_sync(&hdev->scan_update); 1841 cancel_work_sync(&hdev->scan_update);
1842 cancel_work_sync(&hdev->connectable_update);
1804 cancel_delayed_work_sync(&hdev->le_scan_disable); 1843 cancel_delayed_work_sync(&hdev->le_scan_disable);
1805 cancel_delayed_work_sync(&hdev->le_scan_restart); 1844 cancel_delayed_work_sync(&hdev->le_scan_restart);
1806 1845
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 6d0f0025052f..d8b76ca5c820 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1580,12 +1580,9 @@ static void write_fast_connectable(struct hci_request *req, bool enable)
1580 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); 1580 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1581} 1581}
1582 1582
1583static void set_connectable_complete(struct hci_dev *hdev, u8 status, 1583void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
1584 u16 opcode)
1585{ 1584{
1586 struct mgmt_pending_cmd *cmd; 1585 struct mgmt_pending_cmd *cmd;
1587 struct mgmt_mode *cp;
1588 bool conn_changed, discov_changed;
1589 1586
1590 BT_DBG("status 0x%02x", status); 1587 BT_DBG("status 0x%02x", status);
1591 1588
@@ -1601,27 +1598,8 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1601 goto remove_cmd; 1598 goto remove_cmd;
1602 } 1599 }
1603 1600
1604 cp = cmd->param;
1605 if (cp->val) {
1606 conn_changed = !hci_dev_test_and_set_flag(hdev,
1607 HCI_CONNECTABLE);
1608 discov_changed = false;
1609 } else {
1610 conn_changed = hci_dev_test_and_clear_flag(hdev,
1611 HCI_CONNECTABLE);
1612 discov_changed = hci_dev_test_and_clear_flag(hdev,
1613 HCI_DISCOVERABLE);
1614 }
1615
1616 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); 1601 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1617 1602 new_settings(hdev, cmd->sk);
1618 if (conn_changed || discov_changed) {
1619 new_settings(hdev, cmd->sk);
1620 hci_req_update_scan(hdev);
1621 if (discov_changed)
1622 hci_req_update_adv_data(hdev, HCI_ADV_CURRENT);
1623 hci_update_background_scan(hdev);
1624 }
1625 1603
1626remove_cmd: 1604remove_cmd:
1627 mgmt_pending_remove(cmd); 1605 mgmt_pending_remove(cmd);
@@ -1664,8 +1642,6 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
1664{ 1642{
1665 struct mgmt_mode *cp = data; 1643 struct mgmt_mode *cp = data;
1666 struct mgmt_pending_cmd *cmd; 1644 struct mgmt_pending_cmd *cmd;
1667 struct hci_request req;
1668 u8 scan;
1669 int err; 1645 int err;
1670 1646
1671 BT_DBG("request for %s", hdev->name); 1647 BT_DBG("request for %s", hdev->name);
@@ -1699,57 +1675,19 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
1699 goto failed; 1675 goto failed;
1700 } 1676 }
1701 1677
1702 hci_req_init(&req, hdev); 1678 if (cp->val) {
1703 1679 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
1704 /* If BR/EDR is not enabled and we disable advertising as a 1680 } else {
1705 * by-product of disabling connectable, we need to update the 1681 if (hdev->discov_timeout > 0)
1706 * advertising flags. 1682 cancel_delayed_work(&hdev->discov_off);
1707 */
1708 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
1709 if (!cp->val) {
1710 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1711 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1712 }
1713 __hci_req_update_adv_data(&req, HCI_ADV_CURRENT);
1714 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1715 if (cp->val) {
1716 scan = SCAN_PAGE;
1717 } else {
1718 /* If we don't have any whitelist entries just
1719 * disable all scanning. If there are entries
1720 * and we had both page and inquiry scanning
1721 * enabled then fall back to only page scanning.
1722 * Otherwise no changes are needed.
1723 */
1724 if (list_empty(&hdev->whitelist))
1725 scan = SCAN_DISABLED;
1726 else if (test_bit(HCI_ISCAN, &hdev->flags))
1727 scan = SCAN_PAGE;
1728 else
1729 goto no_scan_update;
1730
1731 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1732 hdev->discov_timeout > 0)
1733 cancel_delayed_work(&hdev->discov_off);
1734 }
1735 1683
1736 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); 1684 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1685 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
1686 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1737 } 1687 }
1738 1688
1739no_scan_update: 1689 queue_work(hdev->req_workqueue, &hdev->connectable_update);
1740 /* Update the advertising parameters if necessary */ 1690 err = 0;
1741 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
1742 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
1743 __hci_req_enable_advertising(&req);
1744
1745 err = hci_req_run(&req, set_connectable_complete);
1746 if (err < 0) {
1747 mgmt_pending_remove(cmd);
1748 if (err == -ENODATA)
1749 err = set_connectable_update_settings(hdev, sk,
1750 cp->val);
1751 goto failed;
1752 }
1753 1691
1754failed: 1692failed:
1755 hci_dev_unlock(hdev); 1693 hci_dev_unlock(hdev);