From d43efbd0d545f476be0bbef30cbe18234f8a9631 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Mar 2016 17:30:33 +0200 Subject: Bluetooth: Fix adding discoverable to adv instance flags When lookup up the advertising instance flags for the default advertising instance (0) the discoverable flag should be filled in based on the HCI_DISCOVERABLE flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/bluetooth/hci_request.c') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index c78ee2dc9323..77be344efd18 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -866,6 +866,9 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) flags |= MGMT_ADV_FLAG_CONNECTABLE; + if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) + flags |= MGMT_ADV_FLAG_DISCOV; + return flags; } -- cgit v1.2.3 From 82a37adeedd38880940e2772ec1ae27a09353e5a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Mar 2016 17:30:34 +0200 Subject: 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 Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_conn.c | 13 ++++++++++-- net/bluetooth/hci_request.c | 51 +++++++++++++++++++++++++++++++++++++++------ net/bluetooth/hci_request.h | 2 +- net/bluetooth/mgmt.c | 20 ++++++++++++++++-- 5 files changed, 76 insertions(+), 11 deletions(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 339ea57be423..5d38d980b89d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -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, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7264025dc781..bf9f8a801a2e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -719,6 +719,13 @@ done: 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)); diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 77be344efd18..95a545ca9dbc 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -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; diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 64ff8c040d50..b2d044bdc732 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -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, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5a5089cb6570..2ca355519d79 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -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); -- cgit v1.2.3 From 6a19cc8c892b113fb84947207346f783de76dbd1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 11 Mar 2016 09:56:32 +0200 Subject: Bluetooth: Fix setting correct flags in AD A recent change added MGMT_ADV_FLAG_DISCOV to the flags returned by get_adv_instance_flags(), however failed to take into account limited discoverable mode. This patch fixes the issue by setting the correct discoverability flag in the AD data. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 95a545ca9dbc..6e125d76df0d 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -872,7 +872,9 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) flags |= MGMT_ADV_FLAG_CONNECTABLE; - if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) + if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) + flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; + else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) flags |= MGMT_ADV_FLAG_DISCOV; return flags; -- cgit v1.2.3