aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2014-02-28 05:54:14 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-28 10:53:06 -0500
commit8d97250ea2231736225f2e99a91adb266eedfcbe (patch)
tree5a49d319540bf0d60605d7f9016cebf62fccd8e9
parent759331d7cc660be17bcdc5df53f196135f9dfaf6 (diff)
Bluetooth: Add protections for updating local random address
Different controllers behave differently when HCI_Set_Random_Address is called while they are advertising or have a HCI_LE_Create_Connection in progress. Some take the newly written address into use for the pending operation while others use the random address that we had at the time that the operation started. Due to this undefined behavior and for the fact that we want to reliably determine the initiator address of all connections for the sake of SMP it's best to simply prevent the random address update if we have these problematic operations in progress. This patch adds a set_random_addr() helper function for the use of hci_update_random_address which contains the necessary checks for advertising and ongoing LE connections. One extra thing we need to do is to clear the HCI_ADVERTISING flag in the enable_advertising() function before sending any commands. Since re-enabling advertising happens by calling first disable_advertising() and then enable_advertising() all while having the HCI_ADVERTISING flag set. Clearing the flag lets the set_random_addr() function know that it's safe to write a new address at least as far as advertising is concerned. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--net/bluetooth/hci_core.c27
-rw-r--r--net/bluetooth/mgmt.c7
2 files changed, 32 insertions, 2 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 32c0c2c58f66..8bbfdea9cbec 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3649,6 +3649,29 @@ static void le_scan_disable_work(struct work_struct *work)
3649 BT_ERR("Disable LE scanning request failed: err %d", err); 3649 BT_ERR("Disable LE scanning request failed: err %d", err);
3650} 3650}
3651 3651
3652static void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
3653{
3654 struct hci_dev *hdev = req->hdev;
3655
3656 /* If we're advertising or initiating an LE connection we can't
3657 * go ahead and change the random address at this time. This is
3658 * because the eventual initiator address used for the
3659 * subsequently created connection will be undefined (some
3660 * controllers use the new address and others the one we had
3661 * when the operation started).
3662 *
3663 * In this kind of scenario skip the update and let the random
3664 * address be updated at the next cycle.
3665 */
3666 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
3667 hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
3668 BT_DBG("Deferring random address update");
3669 return;
3670 }
3671
3672 hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa);
3673}
3674
3652int hci_update_random_address(struct hci_request *req, bool require_privacy, 3675int hci_update_random_address(struct hci_request *req, bool require_privacy,
3653 u8 *own_addr_type) 3676 u8 *own_addr_type)
3654{ 3677{
@@ -3674,7 +3697,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
3674 return err; 3697 return err;
3675 } 3698 }
3676 3699
3677 hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &hdev->rpa); 3700 set_random_addr(req, &hdev->rpa);
3678 3701
3679 to = msecs_to_jiffies(hdev->rpa_timeout * 1000); 3702 to = msecs_to_jiffies(hdev->rpa_timeout * 1000);
3680 queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to); 3703 queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to);
@@ -3693,7 +3716,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
3693 urpa.b[5] &= 0x3f; /* Clear two most significant bits */ 3716 urpa.b[5] &= 0x3f; /* Clear two most significant bits */
3694 3717
3695 *own_addr_type = ADDR_LE_DEV_RANDOM; 3718 *own_addr_type = ADDR_LE_DEV_RANDOM;
3696 hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &urpa); 3719 set_random_addr(req, &urpa);
3697 return 0; 3720 return 0;
3698 } 3721 }
3699 3722
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2d11c817d082..98e9df3556e7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -840,6 +840,13 @@ static void enable_advertising(struct hci_request *req)
840 u8 own_addr_type, enable = 0x01; 840 u8 own_addr_type, enable = 0x01;
841 bool connectable; 841 bool connectable;
842 842
843 /* Clear the HCI_ADVERTISING bit temporarily so that the
844 * hci_update_random_address knows that it's safe to go ahead
845 * and write a new random address. The flag will be set back on
846 * as soon as the SET_ADV_ENABLE HCI command completes.
847 */
848 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
849
843 connectable = get_connectable(hdev); 850 connectable = get_connectable(hdev);
844 851
845 /* Set require_privacy to true only when non-connectable 852 /* Set require_privacy to true only when non-connectable