/* Grab a reference if command needs to be associated with a sock (e.g. * likely mgmt socket that initiated the command).
*/ if (sk) {
hci_skb_sk(skb) = sk;
sock_hold(sk);
}
/* If an error occurred during request building, remove all HCI * commands queued on the HCI request queue.
*/ if (req->err) {
skb_queue_purge(&req->cmd_q); return req->err;
}
/* Do not allow empty requests */ if (skb_queue_empty(&req->cmd_q)) return -ENODATA;
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) goto _return;
status = hci_cmd_sync_queue(hdev, scan_disable_sync, NULL, NULL); if (status) {
bt_dev_err(hdev, "failed to disable LE scan: %d", status); goto _return;
}
/* If we were running LE only scan, change discovery state. If * we were running both LE and BR/EDR inquiry simultaneously, * and BR/EDR inquiry is already finished, stop discovery, * otherwise BR/EDR inquiry will stop discovery when finished. * If we will resolve remote device name, do not change * discovery state.
*/
if (hdev->discovery.type == DISCOV_TYPE_LE) goto discov_stopped;
if (hdev->discovery.type != DISCOV_TYPE_INTERLEAVED) goto _return;
if (hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY)) { if (!test_bit(HCI_INQUIRY, &hdev->flags) &&
hdev->discovery.state != DISCOVERY_RESOLVING) goto discov_stopped;
goto _return;
}
status = hci_cmd_sync_queue(hdev, interleaved_inquiry_sync, NULL, NULL); if (status) {
bt_dev_err(hdev, "inquiry failed: status %d", status); goto discov_stopped;
}
/* For a single instance: * - force == true: The instance will be removed even when its remaining * lifetime is not zero. * - force == false: the instance will be deactivated but kept stored unless * the remaining lifetime is zero. * * For instance == 0x00: * - force == true: All instances will be removed regardless of their timeout * setting. * - force == false: Only instances that have a timeout will be removed.
*/ int hci_clear_adv_instance_sync(struct hci_dev *hdev, struct sock *sk,
u8 instance, bool force)
{ struct adv_info *adv_instance, *n, *next_instance = NULL; int err;
u8 rem_inst;
/* Cancel any timeout concerning the removed instance(s). */ if (!instance || hdev->cur_adv_instance == instance)
cancel_adv_timeout(hdev);
/* Get the next instance to advertise BEFORE we remove * the current one. This can be the same instance again * if there is only one instance.
*/ if (instance && hdev->cur_adv_instance == instance)
next_instance = hci_get_next_instance(hdev, instance);
if (instance == 0x00) {
list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances,
list) { if (!(force || adv_instance->timeout)) continue;
switch (hdev->interleave_scan_state) { case INTERLEAVE_SCAN_ALLOWLIST:
bt_dev_dbg(hdev, "next state: allowlist");
hdev->interleave_scan_state = INTERLEAVE_SCAN_NO_FILTER; break; case INTERLEAVE_SCAN_NO_FILTER:
bt_dev_dbg(hdev, "next state: no filter");
hdev->interleave_scan_state = INTERLEAVE_SCAN_ALLOWLIST; break; case INTERLEAVE_SCAN_NONE:
bt_dev_err(hdev, "unexpected error");
}
hci_dev_unlock(hdev);
/* Don't continue interleaving if it was canceled */ if (is_interleave_scanning(hdev))
queue_delayed_work(hdev->req_workqueue,
&hdev->interleave_scan, timeout);
}
/* Cancel ongoing command request synchronously: * * - Set result and mark status to HCI_REQ_CANCELED * - Wakeup command sync thread
*/ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) { /* req_result is __u32 so error must be positive to be properly * propagated.
*/
hdev->req_result = err < 0 ? -err : err;
hdev->req_status = HCI_REQ_CANCELED;
/* Submit HCI command to be run in as cmd_sync_work: * * - hdev must _not_ be unregistered
*/ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ struct hci_cmd_sync_work_entry *entry; int err = 0;
/* Queue HCI command: * * - hdev must be running
*/ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ /* Only queue command if hdev is running which means it had been opened * and is either on init phase or is already up.
*/ if (!test_bit(HCI_RUNNING, &hdev->flags)) return -ENETDOWN;
if (destroy && entry->destroy != destroy) continue;
return entry;
}
return NULL;
}
/* Queue HCI command entry once: * * - Lookup if an entry already exist and only if it doesn't creates a new entry * and queue it.
*/ int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) return 0;
/* Run HCI command: * * - hdev must be running * - if on cmd_sync_work then run immediately otherwise queue
*/ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ /* Only queue command if hdev is running which means it had been opened * and is either on init phase or is already up.
*/ if (!test_bit(HCI_RUNNING, &hdev->flags)) return -ENETDOWN;
/* If on cmd_sync_work then run immediately otherwise queue */ if (current_work() == &hdev->cmd_sync_work) return func(hdev, data);
/* Run HCI command entry once: * * - Lookup if an entry already exist and only if it doesn't creates a new entry * and run it. * - if on cmd_sync_work then run immediately otherwise queue
*/ int hci_cmd_sync_run_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) return 0;
/* Dequeue HCI command entry: * * - Lookup and cancel any entry that matches by function callback or data or * destroy callback.
*/ bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy)
{ struct hci_cmd_sync_work_entry *entry; bool ret = false;
mutex_lock(&hdev->cmd_sync_work_lock); while ((entry = _hci_cmd_sync_lookup_entry(hdev, func, data,
destroy))) {
_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
ret = true;
}
mutex_unlock(&hdev->cmd_sync_work_lock);
staticbool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
{ /* If there is no connection we are OK to advertise. */ if (hci_conn_num(hdev, LE_LINK) == 0) returntrue;
/* Check le_states if there is any connection in peripheral role. */ if (hdev->conn_hash.le_num_peripheral > 0) { /* Peripheral connection state and non connectable mode * bit 20.
*/ if (!connectable && !(hdev->le_states[2] & 0x10)) returnfalse;
/* Peripheral connection state and connectable mode bit 38 * and scannable bit 21.
*/ if (connectable && (!(hdev->le_states[4] & 0x40) ||
!(hdev->le_states[2] & 0x20))) returnfalse;
}
/* Check le_states if there is any connection in central role. */ if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_peripheral) { /* Central connection state and non connectable mode bit 18. */ if (!connectable && !(hdev->le_states[2] & 0x02)) returnfalse;
/* Central connection state and connectable mode bit 35 and * scannable 19.
*/ if (connectable && (!(hdev->le_states[4] & 0x08) ||
!(hdev->le_states[2] & 0x08))) returnfalse;
}
returntrue;
}
staticbool 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)) returnfalse;
/* If basic privacy mode is enabled use RPA */ if (!hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) returntrue;
/* 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)) returnfalse;
/* We're neither bondable nor discoverable in the limited * privacy mode, therefore use RPA.
*/ returntrue;
}
staticint hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)
{ /* If a random_addr has been set we're advertising or initiating an LE * connection we can't go ahead and change the random address at this * time. This is because the eventual initiator address used for the * subsequently created connection will be undefined (some * controllers use the new address and others the one we had * when the operation started). * * In this kind of scenario skip the update and let the random * address be updated at the next cycle.
*/ if (bacmp(&hdev->random_addr, BDADDR_ANY) &&
(hci_dev_test_flag(hdev, HCI_LE_ADV) ||
hci_lookup_le_connect(hdev))) {
bt_dev_dbg(hdev, "Deferring random address update");
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED); return 0;
}
int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy, bool rpa, u8 *own_addr_type)
{ int err;
/* If privacy is enabled use a resolvable private address. If * current RPA has expired or there is something else than * the current RPA in use, then generate a new one.
*/ if (rpa) { /* If Controller supports LL Privacy use own address type is * 0x03
*/ if (ll_privacy_capable(hdev))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED; else
*own_addr_type = ADDR_LE_DEV_RANDOM;
/* Check if RPA is valid */ if (rpa_valid(hdev)) return 0;
err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa); if (err < 0) {
bt_dev_err(hdev, "failed to generate new RPA"); return err;
}
err = hci_set_random_addr_sync(hdev, &hdev->rpa); if (err) return err;
return 0;
}
/* In case of required privacy without resolvable private address, * use an non-resolvable private address. This is useful for active * scanning and non-connectable advertising.
*/ if (require_privacy) {
bdaddr_t nrpa;
while (true) { /* The non-resolvable private address is generated * from random six bytes with the two most significant * bits cleared.
*/
get_random_bytes(&nrpa, 6);
nrpa.b[5] &= 0x3f;
/* The non-resolvable private address shall not be * equal to the public address.
*/ if (bacmp(&hdev->bdaddr, &nrpa)) break;
}
*own_addr_type = ADDR_LE_DEV_RANDOM;
return hci_set_random_addr_sync(hdev, &nrpa);
}
/* If forcing static address is in use or there is no public * address use the static address as random address (but skip * the HCI command if the current random address is already the * static one. * * In case BR/EDR has been disabled on a dual-mode controller * and a static address has been configured, then use that * address instead of the public BR/EDR address.
*/ if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
!bacmp(&hdev->bdaddr, BDADDR_ANY) ||
(!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
bacmp(&hdev->static_addr, BDADDR_ANY))) {
*own_addr_type = ADDR_LE_DEV_RANDOM; if (bacmp(&hdev->static_addr, &hdev->random_addr)) return hci_set_random_addr_sync(hdev,
&hdev->static_addr); return 0;
}
/* Neither privacy nor static address is being used so use a * public address.
*/
*own_addr_type = ADDR_LE_DEV_PUBLIC;
/* If request specifies an instance that doesn't exist, fail */ if (instance > 0) {
adv = hci_find_adv_instance(hdev, instance); if (!adv) return -EINVAL;
/* If not enabled there is nothing to do */ if (!adv->enabled) return 0;
}
memset(data, 0, sizeof(data));
cp = (void *)data;
set = (void *)cp->data;
/* Instance 0x00 indicates all advertising instances will be disabled */
cp->num_of_sets = !!instance;
cp->enable = 0x00;
if (!instance) { /* Instance 0x00 doesn't have an adv_info, instead it uses * hdev->random_addr to track its address so whenever it needs * to be updated this also set the random address since * hdev->random_addr is shared with scan state machine.
*/
err = hci_set_random_addr_sync(hdev, random_addr); if (err) return err;
}
if (instance > 0) {
adv = hci_find_adv_instance(hdev, instance); if (!adv) return -EINVAL;
} else {
adv = NULL;
}
/* Updating parameters of an active instance will return a * Command Disallowed error, so we must first disable the * instance if it is active.
*/ if (adv) {
err = hci_disable_ext_adv_instance_sync(hdev, instance); if (err) return err;
}
flags = hci_adv_instance_flags(hdev, instance);
/* If the "connectable" instance flag was not set, then choose between * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
*/
connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
mgmt_get_connectable(hdev);
if (!is_advertising_allowed(hdev, connectable)) return -EPERM;
/* Set require_privacy to true only when non-connectable * advertising is used and it is not periodic. * In that case it is fine to use a non-resolvable private address.
*/
require_privacy = !connectable && !(adv && adv->periodic);
/* If Own_Address_Type equals 0x02 or 0x03, the Peer_Address parameter * contains the peer’s Identity Address and the Peer_Address_Type * parameter contains the peer’s Identity Type (i.e., 0x00 or 0x01). * These parameters are used to locate the corresponding local IRK in * the resolving list; this IRK is used to generate their own address * used in the advertisement.
*/ if (own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED)
hci_copy_identity_address(hdev, &cp.peer_addr,
&cp.peer_addr_type);
if (flags & MGMT_ADV_FLAG_SEC_2M) {
cp.primary_phy = HCI_ADV_PHY_1M;
cp.secondary_phy = HCI_ADV_PHY_2M;
} elseif (flags & MGMT_ADV_FLAG_SEC_CODED) {
cp.primary_phy = HCI_ADV_PHY_CODED;
cp.secondary_phy = HCI_ADV_PHY_CODED;
} else { /* In all other cases use 1M */
cp.primary_phy = HCI_ADV_PHY_1M;
cp.secondary_phy = HCI_ADV_PHY_1M;
}
err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp); if (err) return err;
/* Update adv data as tx power is known now */
err = hci_set_ext_adv_data_sync(hdev, cp.handle); if (err) return err;
if ((own_addr_type == ADDR_LE_DEV_RANDOM ||
own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) &&
bacmp(&random_addr, BDADDR_ANY)) { /* Check if random address need to be updated */ if (adv) { if (!bacmp(&random_addr, &adv->random_addr)) return 0;
} else { if (!bacmp(&random_addr, &hdev->random_addr)) return 0;
}
if (instance > 0) {
adv = hci_find_adv_instance(hdev, instance); if (!adv) return -EINVAL; /* If already enabled there is nothing to do */ if (adv->enabled) return 0;
} else {
adv = NULL;
}
cp = (void *)data;
set = (void *)cp->data;
memset(cp, 0, sizeof(*cp));
cp->enable = 0x01;
cp->num_of_sets = 0x01;
memset(set, 0, sizeof(*set));
set->handle = adv ? adv->handle : instance;
/* Set duration per instance since controller is responsible for * scheduling it.
*/ if (adv && adv->timeout) {
u16 duration = adv->timeout * MSEC_PER_SEC;
/* Time = N * 10 ms */
set->duration = cpu_to_le16(duration / 10);
}
/* If periodic advertising already disabled there is nothing to do. */
adv = hci_find_adv_instance(hdev, instance); if (!adv || !adv->periodic_enabled) return 0;
/* If periodic advertising already enabled there is nothing to do. */
adv = hci_find_adv_instance(hdev, instance); if (adv && adv->periodic_enabled) return 0;
/* Checks if periodic advertising data contains a Basic Announcement and if it * does generates a Broadcast ID and add Broadcast Announcement.
*/ staticint hci_adv_bcast_annoucement(struct hci_dev *hdev, struct adv_info *adv)
{
u8 bid[3];
u8 ad[HCI_MAX_EXT_AD_LENGTH];
u8 len;
/* Skip if NULL adv as instance 0x00 is used for general purpose * advertising so it cannot used for the likes of Broadcast Announcement * as it can be overwritten at any point.
*/ if (!adv) return 0;
/* Check if PA data doesn't contains a Basic Audio Announcement then * there is nothing to do.
*/ if (!eir_get_service_data(adv->per_adv_data, adv->per_adv_data_len,
0x1851, NULL)) return 0;
/* Check if advertising data already has a Broadcast Announcement since * the process may want to control the Broadcast ID directly and in that * case the kernel shall no interfere.
*/ if (eir_get_service_data(adv->adv_data, adv->adv_data_len, 0x1852,
NULL)) return 0;
/* Generate Broadcast ID */
get_random_bytes(bid, sizeof(bid));
len = eir_append_service_data(ad, 0, 0x1852, bid, sizeof(bid));
memcpy(ad + len, adv->adv_data, adv->adv_data_len);
hci_set_adv_instance_data(hdev, adv->instance, len + adv->adv_data_len,
ad, 0, NULL);
if (instance) {
adv = hci_find_adv_instance(hdev, instance); if (adv) { if (sid != HCI_SID_INVALID && adv->sid != sid) { /* If the SID don't match attempt to find by * SID.
*/
adv = hci_find_adv_sid(hdev, sid); if (!adv) {
bt_dev_err(hdev, "Unable to find adv_info"); return -EINVAL;
}
}
/* Turn it into periodic advertising */
adv->periodic = true;
adv->per_adv_data_len = data_len; if (data)
memcpy(adv->per_adv_data, data, data_len);
adv->flags = flags;
} elseif (!adv) { /* Create an instance if that could not be found */
adv = hci_add_per_instance(hdev, instance, sid, flags,
data_len, data,
sync_interval,
sync_interval); if (IS_ERR(adv)) return PTR_ERR(adv);
adv->pending = false;
added = true;
}
}
/* If the "connectable" instance flag was not set, then choose between * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
*/
connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
mgmt_get_connectable(hdev);
if (!is_advertising_allowed(hdev, connectable)) return -EINVAL;
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 * and write a new random address. The flag will be set back on * as soon as the SET_ADV_ENABLE HCI command completes.
*/
hci_dev_clear_flag(hdev, HCI_LE_ADV);
/* Set require_privacy to true only when non-connectable * advertising is used. In that case it is fine to use a * non-resolvable private address.
*/
status = hci_update_random_address_sync(hdev, !connectable,
adv_use_rpa(hdev, flags),
&own_addr_type); if (status) return status;
if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev)) return -EPERM;
if (hdev->adv_instance_timeout) return -EBUSY;
adv = hci_find_adv_instance(hdev, instance); if (!adv) return -ENOENT;
/* A zero timeout means unlimited advertising. As long as there is * only one instance, duration should be ignored. We still set a timeout * in case further instances are being added later on. * * If the remaining lifetime of the instance is more than the duration * then the timeout corresponds to the duration, otherwise it will be * reduced to the remaining instance lifetime.
*/ if (adv->timeout == 0 || adv->duration <= adv->remaining_time)
timeout = adv->duration; else
timeout = adv->remaining_time;
/* The remaining time is being reduced unless the instance is being * advertised without time limit.
*/ if (adv->timeout)
adv->remaining_time = adv->remaining_time - timeout;
/* Only use work for scheduling instances with legacy advertising */ if (!ext_adv_capable(hdev)) {
hdev->adv_instance_timeout = timeout;
queue_delayed_work(hdev->req_workqueue,
&hdev->adv_instance_expire,
secs_to_jiffies(timeout));
}
/* If we're just re-scheduling the same instance again then do not * execute any HCI commands. This happens when a single instance is * being advertised.
*/ if (!force && hdev->cur_adv_instance == instance &&
hci_dev_test_flag(hdev, HCI_LE_ADV)) return 0;
hdev->cur_adv_instance = instance;
return hci_start_adv_sync(hdev, instance);
}
staticint hci_clear_adv_sets_sync(struct hci_dev *hdev, struct sock *sk)
{ int err;
if (!ext_adv_capable(hdev)) return 0;
/* Disable instance 0x00 to disable all instances */
err = hci_disable_ext_adv_instance_sync(hdev, 0x00); if (err) return err;
/* If we use extended advertising, instance has to be removed first. */ if (ext_adv_capable(hdev)) return hci_remove_ext_adv_instance_sync(hdev, instance, sk);
/* This is safe as long as there is no command send while the lock is * held.
*/
hci_dev_lock(hdev);
err = hci_remove_adv_instance(hdev, instance); if (!err)
mgmt_advertising_removed(sk, hdev, instance);
hci_dev_unlock(hdev);
return err;
}
/* For a single instance: * - force == true: The instance will be removed even when its remaining * lifetime is not zero. * - force == false: the instance will be deactivated but kept stored unless * the remaining lifetime is zero. * * For instance == 0x00: * - force == true: All instances will be removed regardless of their timeout * setting. * - force == false: Only instances that have a timeout will be removed.
*/ int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
u8 instance, bool force)
{ struct adv_info *next = NULL; int err;
/* Cancel any timeout concerning the removed instance(s). */ if (!instance || hdev->cur_adv_instance == instance)
cancel_adv_timeout(hdev);
/* Get the next instance to advertise BEFORE we remove * the current one. This can be the same instance again * if there is only one instance.
*/ if (hdev->cur_adv_instance == instance)
next = hci_get_next_instance(hdev, instance);
/* Return true if interleave_scan wasn't started until exiting this function, * otherwise, return false
*/ staticbool hci_update_interleaved_scan_sync(struct hci_dev *hdev)
{ /* Do interleaved scan only if all of the following are true: * - There is at least one ADV monitor * - At least one pending LE connection or one device to be scanned for * - Monitor offloading is not supported * If so, we should alternate between allowlist scan and one without * any filters to save power.
*/ bool use_interleaving = hci_is_adv_monitoring(hdev) &&
!(list_empty(&hdev->pend_le_conns) &&
list_empty(&hdev->pend_le_reports)) &&
hci_get_adv_monitor_offload_ext(hdev) ==
HCI_ADV_MONITOR_EXT_NONE; bool is_interleaving = is_interleave_scanning(hdev);
/* Ignore errors when removing from resolving list as that is likely * that the device was never added.
*/
hci_le_del_resolve_list_sync(hdev, &cp.bdaddr, cp.bdaddr_type);
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_DEL_FROM_ACCEPT_LIST, sizeof(cp), &cp, HCI_CMD_TIMEOUT); if (err) {
bt_dev_err(hdev, "Unable to remove from allow list: %d", err); return err;
}
bt_dev_dbg(hdev, "Remove %pMR (0x%x) from allow list", &cp.bdaddr,
cp.bdaddr_type);
irk = hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type); if (!irk) return 0;
/* Check if the IK has _not_ been programmed yet. */
entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
¶ms->addr,
params->addr_type); if (entry) return 0;
rcu_read_lock();
p = hci_pend_le_action_lookup(&hdev->pend_le_conns,
¶ms->addr, params->addr_type); if (!p)
p = hci_pend_le_action_lookup(&hdev->pend_le_reports,
¶ms->addr, params->addr_type); if (p)
WRITE_ONCE(p->privacy_mode, HCI_NETWORK_PRIVACY);
rcu_read_unlock();
if (!ll_privacy_capable(hdev) ||
!(params->flags & HCI_CONN_FLAG_ADDRESS_RESOLUTION)) return 0;
/* If device privacy mode has already been set there is nothing to do */ if (params->privacy_mode == HCI_DEVICE_PRIVACY) return 0;
/* Check if HCI_CONN_FLAG_DEVICE_PRIVACY has been set as it also * indicates that LL Privacy has been enabled and * HCI_OP_LE_SET_PRIVACY_MODE is supported.
*/ if (!(params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)) return 0;
irk = hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type); if (!irk) return 0;
/* Adds connection to allow list if needed, if the device uses RPA (has IRK) * this attempts to program the device in the resolving list as well and * properly set the privacy mode.
*/ staticint hci_le_add_accept_list_sync(struct hci_dev *hdev, struct conn_params *params,
u8 *num_entries)
{ struct hci_cp_le_add_to_accept_list cp; int err;
/* During suspend, only wakeable devices can be in acceptlist */ if (hdev->suspended &&
!(params->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)) {
hci_le_del_accept_list_sync(hdev, ¶ms->addr,
params->addr_type); return 0;
}
/* Select filter policy to accept all advertising */ if (*num_entries >= hdev->le_accept_list_size) return -ENOSPC;
/* Attempt to program the device in the resolving list first to avoid * having to rollback in case it fails since the resolving list is * dynamic it can probably be smaller than the accept list.
*/
err = hci_le_add_resolve_list_sync(hdev, params); if (err) {
bt_dev_err(hdev, "Unable to add to resolve list: %d", err); return err;
}
/* Set Privacy Mode */
err = hci_le_set_privacy_mode_sync(hdev, params); if (err) {
bt_dev_err(hdev, "Unable to set privacy mode: %d", err); return err;
}
/* Check if already in accept list */ if (hci_bdaddr_list_lookup(&hdev->le_accept_list, ¶ms->addr,
params->addr_type)) return 0;
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST, sizeof(cp), &cp, HCI_CMD_TIMEOUT); if (err) {
bt_dev_err(hdev, "Unable to add to allow list: %d", err); /* Rollback the device from the resolving list */
hci_le_del_resolve_list_sync(hdev, &cp.bdaddr, cp.bdaddr_type); return err;
}
bt_dev_dbg(hdev, "Add %pMR (0x%x) to allow list", &cp.bdaddr,
cp.bdaddr_type);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.