Bluetooth: Add support for limited privacy mode
Introduce a limited privacy mode indicated by value 0x02 to the mgmt Set Privacy command. With value 0x02 the kernel will use privacy mode with a resolvable private address. In case the controller is bondable and discoverable the identity address will be used. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
d43efbd0d5
commit
82a37adeed
|
@ -233,6 +233,7 @@ enum {
|
||||||
HCI_SC_ENABLED,
|
HCI_SC_ENABLED,
|
||||||
HCI_SC_ONLY,
|
HCI_SC_ONLY,
|
||||||
HCI_PRIVACY,
|
HCI_PRIVACY,
|
||||||
|
HCI_LIMITED_PRIVACY,
|
||||||
HCI_RPA_EXPIRED,
|
HCI_RPA_EXPIRED,
|
||||||
HCI_RPA_RESOLVING,
|
HCI_RPA_RESOLVING,
|
||||||
HCI_HS_ENABLED,
|
HCI_HS_ENABLED,
|
||||||
|
|
|
@ -719,6 +719,13 @@ done:
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool conn_use_rpa(struct hci_conn *conn)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = conn->hdev;
|
||||||
|
|
||||||
|
return hci_dev_test_flag(hdev, HCI_PRIVACY);
|
||||||
|
}
|
||||||
|
|
||||||
static void hci_req_add_le_create_conn(struct hci_request *req,
|
static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||||
struct hci_conn *conn)
|
struct hci_conn *conn)
|
||||||
{
|
{
|
||||||
|
@ -729,7 +736,8 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||||
/* Update random address, but set require_privacy to false so
|
/* Update random address, but set require_privacy to false so
|
||||||
* that we never connect with an non-resolvable address.
|
* that we never connect with an non-resolvable address.
|
||||||
*/
|
*/
|
||||||
if (hci_update_random_address(req, false, &own_addr_type))
|
if (hci_update_random_address(req, false, conn_use_rpa(conn),
|
||||||
|
&own_addr_type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(&cp, 0, sizeof(cp));
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
@ -774,7 +782,8 @@ static void hci_req_directed_advertising(struct hci_request *req,
|
||||||
/* Set require_privacy to false so that the remote device has a
|
/* Set require_privacy to false so that the remote device has a
|
||||||
* chance of identifying us.
|
* chance of identifying us.
|
||||||
*/
|
*/
|
||||||
if (hci_update_random_address(req, false, &own_addr_type) < 0)
|
if (hci_update_random_address(req, false, conn_use_rpa(conn),
|
||||||
|
&own_addr_type) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(&cp, 0, sizeof(cp));
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
|
|
@ -771,6 +771,11 @@ static u8 update_white_list(struct hci_request *req)
|
||||||
return 0x01;
|
return 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool scan_use_rpa(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
return hci_dev_test_flag(hdev, HCI_PRIVACY);
|
||||||
|
}
|
||||||
|
|
||||||
void hci_req_add_le_passive_scan(struct hci_request *req)
|
void hci_req_add_le_passive_scan(struct hci_request *req)
|
||||||
{
|
{
|
||||||
struct hci_cp_le_set_scan_param param_cp;
|
struct hci_cp_le_set_scan_param param_cp;
|
||||||
|
@ -785,7 +790,8 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
|
||||||
* advertising with our address will be correctly reported
|
* advertising with our address will be correctly reported
|
||||||
* by the controller.
|
* by the controller.
|
||||||
*/
|
*/
|
||||||
if (hci_update_random_address(req, false, &own_addr_type))
|
if (hci_update_random_address(req, false, scan_use_rpa(hdev),
|
||||||
|
&own_addr_type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Adding or removing entries from the white list must
|
/* Adding or removing entries from the white list must
|
||||||
|
@ -881,6 +887,29 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
|
||||||
return adv_instance->flags;
|
return adv_instance->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)
|
||||||
|
{
|
||||||
|
/* If privacy is not enabled don't use RPA */
|
||||||
|
if (!hci_dev_test_flag(hdev, HCI_PRIVACY))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If basic privacy mode is enabled use RPA */
|
||||||
|
if (!hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If limited privacy mode is enabled don't use RPA if we're
|
||||||
|
* both discoverable and bondable.
|
||||||
|
*/
|
||||||
|
if ((flags & MGMT_ADV_FLAG_DISCOV) &&
|
||||||
|
hci_dev_test_flag(hdev, HCI_BONDABLE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We're neither bondable nor discoverable in the limited
|
||||||
|
* privacy mode, therefore use RPA.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void __hci_req_enable_advertising(struct hci_request *req)
|
void __hci_req_enable_advertising(struct hci_request *req)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = req->hdev;
|
struct hci_dev *hdev = req->hdev;
|
||||||
|
@ -914,7 +943,9 @@ void __hci_req_enable_advertising(struct hci_request *req)
|
||||||
* advertising is used. In that case it is fine to use a
|
* advertising is used. In that case it is fine to use a
|
||||||
* non-resolvable private address.
|
* non-resolvable private address.
|
||||||
*/
|
*/
|
||||||
if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
|
if (hci_update_random_address(req, !connectable,
|
||||||
|
adv_use_rpa(hdev, flags),
|
||||||
|
&own_addr_type) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(&cp, 0, sizeof(cp));
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
@ -1328,7 +1359,7 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
|
||||||
}
|
}
|
||||||
|
|
||||||
int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
||||||
u8 *own_addr_type)
|
bool use_rpa, u8 *own_addr_type)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = req->hdev;
|
struct hci_dev *hdev = req->hdev;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1337,7 +1368,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
||||||
* current RPA has expired or there is something else than
|
* current RPA has expired or there is something else than
|
||||||
* the current RPA in use, then generate a new one.
|
* the current RPA in use, then generate a new one.
|
||||||
*/
|
*/
|
||||||
if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
|
if (use_rpa) {
|
||||||
int to;
|
int to;
|
||||||
|
|
||||||
*own_addr_type = ADDR_LE_DEV_RANDOM;
|
*own_addr_type = ADDR_LE_DEV_RANDOM;
|
||||||
|
@ -1599,9 +1630,16 @@ static int discoverable_update(struct hci_request *req, unsigned long opt)
|
||||||
/* Advertising instances don't use the global discoverable setting, so
|
/* Advertising instances don't use the global discoverable setting, so
|
||||||
* only update AD if advertising was enabled using Set Advertising.
|
* only update AD if advertising was enabled using Set Advertising.
|
||||||
*/
|
*/
|
||||||
if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
|
if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
|
||||||
__hci_req_update_adv_data(req, 0x00);
|
__hci_req_update_adv_data(req, 0x00);
|
||||||
|
|
||||||
|
/* Discoverable mode affects the local advertising
|
||||||
|
* address in limited privacy mode.
|
||||||
|
*/
|
||||||
|
if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
|
||||||
|
__hci_req_enable_advertising(req);
|
||||||
|
}
|
||||||
|
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1944,7 +1982,8 @@ static int active_scan(struct hci_request *req, unsigned long opt)
|
||||||
* address (when privacy feature has been enabled) or non-resolvable
|
* address (when privacy feature has been enabled) or non-resolvable
|
||||||
* private address.
|
* private address.
|
||||||
*/
|
*/
|
||||||
err = hci_update_random_address(req, true, &own_addr_type);
|
err = hci_update_random_address(req, true, scan_use_rpa(hdev),
|
||||||
|
&own_addr_type);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
own_addr_type = ADDR_LE_DEV_PUBLIC;
|
own_addr_type = ADDR_LE_DEV_PUBLIC;
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ static inline void hci_req_update_scan(struct hci_dev *hdev)
|
||||||
void __hci_req_update_scan(struct hci_request *req);
|
void __hci_req_update_scan(struct hci_request *req);
|
||||||
|
|
||||||
int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
||||||
u8 *own_addr_type);
|
bool use_rpa, u8 *own_addr_type);
|
||||||
|
|
||||||
int hci_abort_conn(struct hci_conn *conn, u8 reason);
|
int hci_abort_conn(struct hci_conn *conn, u8 reason);
|
||||||
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
|
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
|
||||||
|
|
|
@ -1382,8 +1382,19 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (changed)
|
if (changed) {
|
||||||
|
/* In limited privacy mode the change of bondable mode
|
||||||
|
* may affect the local advertising address.
|
||||||
|
*/
|
||||||
|
if (hdev_is_powered(hdev) &&
|
||||||
|
hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
|
||||||
|
hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
|
||||||
|
hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
|
||||||
|
queue_work(hdev->req_workqueue,
|
||||||
|
&hdev->discoverable_update);
|
||||||
|
|
||||||
err = new_settings(hdev, sk);
|
err = new_settings(hdev, sk);
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
@ -4423,7 +4434,7 @@ static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
|
||||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
|
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
|
||||||
MGMT_STATUS_NOT_SUPPORTED);
|
MGMT_STATUS_NOT_SUPPORTED);
|
||||||
|
|
||||||
if (cp->privacy != 0x00 && cp->privacy != 0x01)
|
if (cp->privacy != 0x00 && cp->privacy != 0x01 && cp->privacy != 0x02)
|
||||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
|
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
|
||||||
MGMT_STATUS_INVALID_PARAMS);
|
MGMT_STATUS_INVALID_PARAMS);
|
||||||
|
|
||||||
|
@ -4442,10 +4453,15 @@ static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
|
||||||
changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
|
changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
|
||||||
memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
|
memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
|
||||||
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
|
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
|
||||||
|
if (cp->privacy == 0x02)
|
||||||
|
hci_dev_set_flag(hdev, HCI_LIMITED_PRIVACY);
|
||||||
|
else
|
||||||
|
hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
|
||||||
} else {
|
} else {
|
||||||
changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
|
changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
|
||||||
memset(hdev->irk, 0, sizeof(hdev->irk));
|
memset(hdev->irk, 0, sizeof(hdev->irk));
|
||||||
hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
|
hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
|
||||||
|
hci_dev_clear_flag(hdev, HCI_LIMITED_PRIVACY);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
|
err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
|
||||||
|
|
Loading…
Reference in New Issue