Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82a37ade authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann
Browse files

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: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent d43efbd0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -233,6 +233,7 @@ enum {
	HCI_SC_ENABLED,
	HCI_SC_ONLY,
	HCI_PRIVACY,
	HCI_LIMITED_PRIVACY,
	HCI_RPA_EXPIRED,
	HCI_RPA_RESOLVING,
	HCI_HS_ENABLED,
+11 −2
Original line number Diff line number Diff line
@@ -719,6 +719,13 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
	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,
				       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
	 * 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;

	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
	 * 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;

	memset(&cp, 0, sizeof(cp));
+45 −6
Original line number Diff line number Diff line
@@ -771,6 +771,11 @@ static u8 update_white_list(struct hci_request *req)
	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)
{
	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
	 * 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;

	/* 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;
}

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)
{
	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
	 * 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;

	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,
			      u8 *own_addr_type)
			      bool use_rpa, u8 *own_addr_type)
{
	struct hci_dev *hdev = req->hdev;
	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
	 * the current RPA in use, then generate a new one.
	 */
	if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
	if (use_rpa) {
		int to;

		*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
	 * 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);

		/* 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);

	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
	 * 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)
		own_addr_type = ADDR_LE_DEV_PUBLIC;

+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ static inline void hci_req_update_scan(struct hci_dev *hdev)
void __hci_req_update_scan(struct hci_request *req);

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);
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
+18 −2
Original line number Diff line number Diff line
@@ -1382,8 +1382,19 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
	if (err < 0)
		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);
	}

unlock:
	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,
				       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,
				       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);
		memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
		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 {
		changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
		memset(hdev->irk, 0, sizeof(hdev->irk));
		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);