@@ -1437,8 +1437,11 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
+#define ll_privacy_capable(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
+
/* Use LL Privacy based address resolution if supported */
-#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
+#define use_ll_privacy(dev) (ll_privacy_capable(dev) && \
+ hci_dev_test_flag(dev, HCI_ENABLE_LL_PRIVACY))
/* Use ext scanning if set ext scan param and ext scan enable is supported */
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
@@ -2340,8 +2340,7 @@ static void cs_le_create_conn(struct hci_dev *hdev, bdaddr_t *peer_addr,
* address types 0x02 and 0x03 are used. These types need to be
* converted back into either public address or random address type
*/
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
+ if (hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
switch (own_address_type) {
case ADDR_LE_DEV_PUBLIC_RESOLVED:
own_address_type = ADDR_LE_DEV_PUBLIC;
@@ -5201,9 +5200,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
* address types 0x02 and 0x03 are used. These types need to be
* converted back into either public address or random address type
*/
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
- hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
+ if (hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
switch (conn->dst_type) {
case ADDR_LE_DEV_PUBLIC_RESOLVED:
conn->dst_type = ADDR_LE_DEV_PUBLIC;
@@ -5310,9 +5307,7 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev,
le16_to_cpu(ev->latency),
le16_to_cpu(ev->supervision_timeout));
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
- hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
+ if (hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
hci_req_disable_address_resolution(hdev);
}
@@ -511,9 +511,7 @@ void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn)
}
/* Disable address resolution */
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
- hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) && !rpa_le_conn) {
+ if (hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) && !rpa_le_conn) {
__u8 enable = 0x00;
hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
@@ -532,8 +530,7 @@ static void del_from_accept_list(struct hci_request *req, bdaddr_t *bdaddr,
cp.bdaddr_type);
hci_req_add(req, HCI_OP_LE_DEL_FROM_ACCEPT_LIST, sizeof(cp), &cp);
- if (use_ll_privacy(req->hdev) &&
- hci_dev_test_flag(req->hdev, HCI_ENABLE_LL_PRIVACY)) {
+ if (use_ll_privacy(req->hdev)) {
struct smp_irk *irk;
irk = hci_find_irk_by_addr(req->hdev, bdaddr, bdaddr_type);
@@ -586,8 +583,7 @@ static int add_to_accept_list(struct hci_request *req,
cp.bdaddr_type);
hci_req_add(req, HCI_OP_LE_ADD_TO_ACCEPT_LIST, sizeof(cp), &cp);
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) {
+ if (use_ll_privacy(hdev)) {
struct smp_irk *irk;
irk = hci_find_irk_by_addr(hdev, ¶ms->addr,
@@ -626,8 +622,7 @@ static u8 update_accept_list(struct hci_request *req)
*/
bool allow_rpa = hdev->suspended;
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (use_ll_privacy(hdev))
allow_rpa = true;
/* Go through the current accept list programmed into the
@@ -716,9 +711,7 @@ static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
return;
}
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
- addr_resolv) {
+ if (use_ll_privacy(hdev) && addr_resolv) {
u8 enable = 0x01;
hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
@@ -1477,8 +1470,7 @@ void hci_req_disable_address_resolution(struct hci_dev *hdev)
struct hci_request req;
__u8 enable = 0x00;
- if (!use_ll_privacy(hdev) &&
- !hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
+ if (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
return;
hci_req_init(&req, hdev);
@@ -1623,8 +1615,7 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (use_ll_privacy(hdev))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
@@ -2098,8 +2089,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (use_ll_privacy(hdev))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
@@ -272,8 +272,7 @@ int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (use_ll_privacy(hdev))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
@@ -633,11 +632,9 @@ int hci_enable_advertising_sync(struct hci_dev *hdev)
if (!is_advertising_allowed(hdev, connectable))
return -EINVAL;
- if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
- status = hci_disable_advertising_sync(hdev);
- if (status)
- return status;
- }
+ status = hci_disable_advertising_sync(hdev);
+ if (status)
+ return status;
/* Clear the HCI_LE_ADV bit temporarily so that the
* hci_update_random_address knows that it's safe to go ahead
@@ -926,6 +923,10 @@ int hci_disable_advertising_sync(struct hci_dev *hdev)
{
u8 enable = 0x00;
+ /* If controller is not advertising we are done. */
+ if (!hci_dev_test_flag(hdev, HCI_LE_ADV))
+ return 0;
+
if (ext_adv_capable(hdev))
return hci_disable_ext_adv_instance_sync(hdev, 0x00);
@@ -964,15 +965,18 @@ static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
static int hci_le_set_addr_resolution_enable_sync(struct hci_dev *hdev, u8 val)
{
- if (!use_ll_privacy(hdev) ||
- !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (!use_ll_privacy(hdev))
+ return 0;
+
+ /* If controller is not/already resolving we are done. */
+ if (val == hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE,
sizeof(val), &val, HCI_CMD_TIMEOUT);
}
-int hci_scan_disable_sync(struct hci_dev *hdev, bool rpa_le_conn)
+int hci_scan_disable_sync(struct hci_dev *hdev)
{
int err;
@@ -994,13 +998,6 @@ int hci_scan_disable_sync(struct hci_dev *hdev, bool rpa_le_conn)
return err;
}
- if (rpa_le_conn) {
- err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
- if (err)
- bt_dev_err(hdev, "Unable to disable LL privacy: %d",
- err);
- }
-
return err;
}
@@ -1068,8 +1065,7 @@ static int hci_le_del_resolve_list_sync(struct hci_dev *hdev,
struct hci_cp_le_del_from_resolv_list cp;
struct smp_irk *irk;
- if (!use_ll_privacy(hdev) ||
- !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (!use_ll_privacy(hdev))
return 0;
irk = hci_find_irk_by_addr(hdev, bdaddr, bdaddr_type);
@@ -1111,9 +1107,9 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
{
struct hci_cp_le_add_to_resolv_list cp;
struct smp_irk *irk;
+ int err;
- if (!use_ll_privacy(hdev) ||
- !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (!use_ll_privacy(hdev))
return 0;
irk = hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type);
@@ -1129,8 +1125,16 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
else
memset(cp.local_irk, 0, 16);
- return __hci_cmd_sync_status(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST,
- sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+ err = __hci_cmd_sync_status(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST,
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+ /* When a controller cannot add a device to the list because there is
+ * no space available, it shall return the error code Memory Capacity
+ * Exceeded (0x07).
+ */
+ if (err == HCI_ERROR_MEMORY_EXCEEDED)
+ return 0;
+
+ return err;
}
/* Adds connection to allow list if needed.*/
@@ -1192,8 +1196,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
*/
bool allow_rpa = hdev->suspended;
- if (use_ll_privacy(hdev) &&
- hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+ if (use_ll_privacy(hdev))
allow_rpa = true;
/* Go through the current accept list programmed into the
@@ -1382,22 +1385,25 @@ static int hci_start_scan_sync(struct hci_dev *hdev, u8 type, u16 interval,
LE_SCAN_FILTER_DUP_ENABLE);
}
-/* Ensure to call hci_scan_disable_sync first to disable the controller based
- * address resolution to be able to reconfigure resolving list.
- */
int hci_passive_scan_sync(struct hci_dev *hdev)
{
u8 own_addr_type;
u8 filter_policy;
u16 window, interval;
- /* Background scanning should run with address resolution */
- bool addr_resolv = true;
+ bool restart_adv = false;
+ int err;
if (hdev->scanning_paused) {
bt_dev_dbg(hdev, "Scanning is paused for suspend");
return 0;
}
+ err = hci_scan_disable_sync(hdev);
+ if (err) {
+ bt_dev_err(hdev, "disable scanning failed: %d", err);
+ return err;
+ }
+
/* Set require_privacy to false since no SCAN_REQ are send
* during passive scanning. Not using an non-resolvable address
* here is important so that peer devices using direct
@@ -1413,6 +1419,25 @@ int hci_passive_scan_sync(struct hci_dev *hdev)
return 0;
bt_dev_dbg(hdev, "interleave state %d", hdev->interleave_scan_state);
+
+ /* Stop advertising if resolving list can be used as controllers are
+ * cannot accept resolving list modifications while advertising.
+ */
+ if (use_ll_privacy(hdev) && hci_dev_test_flag(hdev, HCI_LE_ADV)) {
+ err = hci_disable_advertising_sync(hdev);
+ if (err) {
+ bt_dev_err(hdev, "disable advertising failed: %d", err);
+ return err;
+ }
+ restart_adv = true;
+ }
+
+ err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
+ if (err) {
+ bt_dev_err(hdev, "Unable to disable LL privacy: %d", err);
+ return err;
+ }
+
/* Adding or removing entries from the accept list must
* happen before enabling scanning. The controller does
* not allow accept list modification while scanning.
@@ -1450,8 +1475,16 @@ int hci_passive_scan_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, "LE passive scan with acceptlist = %d", filter_policy);
- return hci_start_scan_sync(hdev, LE_SCAN_PASSIVE, interval, window,
- own_addr_type, filter_policy, addr_resolv);
+ /* Start scanning, it will also program allowlist and resolvinglist so
+ * it needs to be done before restarting advertising.
+ */
+ err = hci_start_scan_sync(hdev, LE_SCAN_PASSIVE, interval, window,
+ own_addr_type, filter_policy, true);
+ if (err || !restart_adv)
+ return err;
+
+ /* Restart advertising if it was stopped */
+ return hci_enable_advertising_sync(hdev);
}
/* This function controls the background scanning based on hdev->pend_le_conns
@@ -1500,7 +1533,7 @@ int hci_update_background_scan_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, "stopping background scanning");
- err = hci_scan_disable_sync(hdev, false);
+ err = hci_scan_disable_sync(hdev);
if (err)
bt_dev_err(hdev, "stop background scanning failed: %d",
err);
@@ -1516,13 +1549,6 @@ int hci_update_background_scan_sync(struct hci_dev *hdev)
if (hci_lookup_le_connect(hdev))
return 0;
- err = hci_scan_disable_sync(hdev, false);
- if (err) {
- bt_dev_err(hdev, "stop background scanning failed: %d",
- err);
- return err;
- }
-
bt_dev_dbg(hdev, "start background scanning");
err = hci_passive_scan_sync(hdev);
@@ -840,12 +840,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
settings |= MGMT_SETTING_SECURE_CONN;
settings |= MGMT_SETTING_PRIVACY;
settings |= MGMT_SETTING_STATIC_ADDRESS;
-
- /* When the experimental feature for LL Privacy support is
- * enabled, then advertising is no longer supported.
- */
- if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
- settings |= MGMT_SETTING_ADVERTISING;
+ settings |= MGMT_SETTING_ADVERTISING;
}
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
@@ -3835,7 +3830,7 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
idx++;
}
- if (hdev && use_ll_privacy(hdev)) {
+ if (hdev && ll_privacy_capable(hdev)) {
if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
flags = BIT(0) | BIT(1);
else
@@ -3911,7 +3906,8 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
}
#endif
- if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
+ if (hdev && ll_privacy_capable(hdev) &&
+ !hdev_is_powered(hdev)) {
bool changed = hci_dev_test_flag(hdev,
HCI_ENABLE_LL_PRIVACY);
@@ -5394,13 +5390,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
status);
- /* Enabling the experimental LL Privay support disables support for
- * advertising.
- */
- if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
- MGMT_STATUS_NOT_SUPPORTED);
-
if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);
@@ -7491,13 +7480,6 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
MGMT_STATUS_REJECTED);
- /* Enabling the experimental LL Privay support disables support for
- * advertising.
- */
- if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
- MGMT_STATUS_NOT_SUPPORTED);
-
hci_dev_lock(hdev);
rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
@@ -7737,13 +7719,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
status);
- /* Enabling the experimental LL Privay support disables support for
- * advertising.
- */
- if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
- MGMT_STATUS_NOT_SUPPORTED);
-
if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);
@@ -8248,13 +8223,6 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
bt_dev_dbg(hdev, "sock %p", sk);
- /* Enabling the experimental LL Privay support disables support for
- * advertising.
- */
- if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
- MGMT_STATUS_NOT_SUPPORTED);
-
hci_dev_lock(hdev);
if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {