/****************************************************************************** * * Copyright 1999-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This file contains functions for BLE controller based privacy. * ******************************************************************************/ #include #include "bt_target.h" #include "ble_advertiser.h" #include "bt_types.h" #include "btm_int.h" #include "btu.h" #include "device/include/controller.h" #include "hcimsgs.h" #include "stack/btm/btm_dev.h" #include "vendor_hcidefs.h" extern tBTM_CB btm_cb; /* RPA offload VSC specifics */ #define BTM_BLE_META_IRK_ENABLE 0x01 #define BTM_BLE_META_ADD_IRK_ENTRY 0x02 #define BTM_BLE_META_REMOVE_IRK_ENTRY 0x03 #define BTM_BLE_META_CLEAR_IRK_LIST 0x04 #define BTM_BLE_META_READ_IRK_ENTRY 0x05 #define BTM_BLE_META_CS_RESOLVE_ADDR 0x00000001 #define BTM_BLE_IRK_ENABLE_LEN 2 #define BTM_BLE_META_ADD_IRK_LEN 24 #define BTM_BLE_META_REMOVE_IRK_LEN 8 #define BTM_BLE_META_CLEAR_IRK_LEN 1 #define BTM_BLE_META_READ_IRK_LEN 2 #define BTM_BLE_META_ADD_WL_ATTR_LEN 9 /******************************************************************************* * Functions implemented controller based privacy using Resolving List ******************************************************************************/ /******************************************************************************* * * Function btm_ble_enq_resolving_list_pending * * Description add target address into resolving pending operation queue * * Parameters target_bda: target device address * add_entry: true for add entry, false for remove entry * * Returns void * ******************************************************************************/ static void btm_ble_enq_resolving_list_pending(const RawAddress& pseudo_bda, uint8_t op_code) { tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; p_q->resolve_q_random_pseudo[p_q->q_next] = pseudo_bda; p_q->resolve_q_action[p_q->q_next] = op_code; p_q->q_next++; p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size(); } /******************************************************************************* * * Function btm_ble_brcm_find_resolving_pending_entry * * Description check to see if the action is in pending list * * Parameters true: action pending; * false: new action * * Returns void * ******************************************************************************/ static bool btm_ble_brcm_find_resolving_pending_entry( const RawAddress& pseudo_addr, uint8_t action) { tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; for (uint8_t i = p_q->q_pending; i != p_q->q_next;) { if (p_q->resolve_q_random_pseudo[i] == pseudo_addr && action == p_q->resolve_q_action[i]) return true; i++; i %= controller_get_interface()->get_ble_resolving_list_max_size(); } return false; } /******************************************************************************* * * Function btm_ble_deq_resolving_pending * * Description dequeue target address from resolving pending operation * queue * * Parameters pseudo_addr: pseudo_addr device address * * Returns void * ******************************************************************************/ static bool btm_ble_deq_resolving_pending(RawAddress& pseudo_addr) { tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; if (p_q->q_next != p_q->q_pending) { pseudo_addr = p_q->resolve_q_random_pseudo[p_q->q_pending]; p_q->resolve_q_random_pseudo[p_q->q_pending] = RawAddress::kEmpty; p_q->q_pending++; p_q->q_pending %= controller_get_interface()->get_ble_resolving_list_max_size(); return true; } return false; } /******************************************************************************* * * Function btm_ble_clear_irk_index * * Description clear IRK list index mask for availability * * Returns none * ******************************************************************************/ static void btm_ble_clear_irk_index(uint8_t index) { uint8_t byte; uint8_t bit; if (index < controller_get_interface()->get_ble_resolving_list_max_size()) { byte = index / 8; bit = index % 8; btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit)); } } /******************************************************************************* * * Function btm_ble_find_irk_index * * Description find the first available IRK list index * * Returns index from 0 ~ max (127 default) * ******************************************************************************/ static uint8_t btm_ble_find_irk_index(void) { uint8_t i = 0; uint8_t byte; uint8_t bit; while (i < controller_get_interface()->get_ble_resolving_list_max_size()) { byte = i / 8; bit = i % 8; if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0) { btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit); return i; } i++; } BTM_TRACE_ERROR("%s failed, list full", __func__); return i; } /******************************************************************************* * * Function btm_ble_update_resolving_list * * Description update resolving list entry in host maintained record * * Returns void * ******************************************************************************/ static void btm_ble_update_resolving_list(const RawAddress& pseudo_bda, bool add) { tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(pseudo_bda); if (p_dev_rec == NULL) return; if (add) { p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT; if (!controller_get_interface()->supports_ble_privacy()) p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index(); } else { p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT; if (!controller_get_interface()->supports_ble_privacy()) { /* clear IRK list index mask */ btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index); p_dev_rec->ble.resolving_list_index = 0; } } } static bool clear_resolving_list_bit(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev_rec = static_cast(data); p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT; return true; } /******************************************************************************* * * Function btm_ble_clear_resolving_list_complete * * Description This function is called when command complete for * clear resolving list * * Returns void * ******************************************************************************/ void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len) { uint8_t status = 0; if (evt_len < 1) { BTM_TRACE_ERROR("malformatted event packet: containing zero bytes"); return; } STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status=%d", __func__, status); if (status == HCI_SUCCESS) { if (evt_len >= 3) { /* VSC complete has one extra byte for op code and list size, skip it here */ p++; /* updated the available list size, and current list size */ uint8_t irk_list_sz_max = 0; STREAM_TO_UINT8(irk_list_sz_max, p); if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) btm_ble_resolving_list_init(irk_list_sz_max); uint8_t irk_mask_size = (irk_list_sz_max % 8) ? (irk_list_sz_max / 8 + 1) : (irk_list_sz_max / 8); memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size); } btm_cb.ble_ctr_cb.resolving_list_avail_size = controller_get_interface()->get_ble_resolving_list_max_size(); BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d", __func__, btm_cb.ble_ctr_cb.resolving_list_avail_size); list_foreach(btm_cb.sec_dev_rec, clear_resolving_list_bit, NULL); } } /******************************************************************************* * * Function btm_ble_add_resolving_list_entry_complete * * Description This function is called when command complete for * add resolving list entry * * Returns void * ******************************************************************************/ void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) { uint8_t status; if (evt_len < 1) { BTM_TRACE_ERROR("malformatted event packet: containing zero bytes"); return; } STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status = %d", __func__, status); RawAddress pseudo_bda; if (!btm_ble_deq_resolving_pending(pseudo_bda)) { BTM_TRACE_DEBUG("no pending resolving list operation"); return; } if (status == HCI_SUCCESS) { /* privacy 1.2 command complete does not have these extra byte */ if (evt_len > 2) { /* VSC complete has one extra byte for op code, skip it here */ p++; STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p); } else btm_cb.ble_ctr_cb.resolving_list_avail_size--; } else if (status == HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */ { btm_cb.ble_ctr_cb.resolving_list_avail_size = 0; BTM_TRACE_DEBUG("%s Resolving list Full ", __func__); } } /******************************************************************************* * * Function btm_ble_remove_resolving_list_entry_complete * * Description This function is called when command complete for * remove resolving list entry * * Returns void * ******************************************************************************/ void btm_ble_remove_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) { RawAddress pseudo_bda; uint8_t status; STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status = %d", __func__, status); if (!btm_ble_deq_resolving_pending(pseudo_bda)) { BTM_TRACE_ERROR("%s no pending resolving list operation", __func__); return; } if (status == HCI_SUCCESS) { /* proprietary: spec does not have these extra bytes */ if (evt_len > 2) { p++; /* skip opcode */ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p); } else btm_cb.ble_ctr_cb.resolving_list_avail_size++; } } /******************************************************************************* * * Function btm_ble_read_resolving_list_entry_complete * * Description This function is called when command complete for * remove resolving list entry * * Returns void * ******************************************************************************/ void btm_ble_read_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) { uint8_t status; RawAddress rra, pseudo_bda; STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status = %d", __func__, status); if (!btm_ble_deq_resolving_pending(pseudo_bda)) { BTM_TRACE_ERROR("no pending resolving list operation"); return; } if (status == HCI_SUCCESS) { /* proprietary spec has extra bytes */ if (evt_len > 8) { /* skip subcode, index, IRK value, address type, identity addr type */ p += (2 + 16 + 1 + 6); STREAM_TO_BDADDR(rra, p); VLOG(2) << __func__ << " peer_addr: " << rra; } else { STREAM_TO_BDADDR(rra, p); } btm_ble_refresh_peer_resolvable_private_addr( pseudo_bda, rra, tBTM_SEC_BLE::tADDRESS_TYPE::BTM_BLE_ADDR_PSEUDO); } } /******************************************************************************* VSC that implement controller based privacy ******************************************************************************/ /******************************************************************************* * * Function btm_ble_resolving_list_vsc_op_cmpl * * Description IRK operation VSC complete handler * * Parameters * * Returns void * ******************************************************************************/ static void btm_ble_resolving_list_vsc_op_cmpl(tBTM_VSC_CMPL* p_params) { uint8_t *p = p_params->p_param_buf, op_subcode; uint16_t evt_len = p_params->param_len; op_subcode = *(p + 1); BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode); if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST) { btm_ble_clear_resolving_list_complete(p, evt_len); } else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY) { btm_ble_add_resolving_list_entry_complete(p, evt_len); } else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY) { btm_ble_remove_resolving_list_entry_complete(p, evt_len); } else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY) { btm_ble_read_resolving_list_entry_complete(p, evt_len); } else if (op_subcode == BTM_BLE_META_IRK_ENABLE) { /* RPA offloading enable/disabled */ } } /******************************************************************************* * * Function btm_ble_remove_resolving_list_entry * * Description This function to remove an IRK entry from the list * * Parameters ble_addr_type: address type * ble_addr: LE adddress * * Returns status * ******************************************************************************/ tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { /* if controller does not support RPA offloading or privacy 1.2, skip */ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) return BTM_WRONG_MODE; if (controller_get_interface()->supports_ble_privacy()) { btsnd_hcic_ble_rm_device_resolving_list( p_dev_rec->ble.identity_address_with_type.type, p_dev_rec->ble.identity_address_with_type.bda); } else { uint8_t param[20] = {0}; uint8_t* p = param; UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY); UINT8_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.type); BDADDR_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.bda); BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_REMOVE_IRK_LEN, param, btm_ble_resolving_list_vsc_op_cmpl); } btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY); return BTM_CMD_STARTED; } /******************************************************************************* * * Function btm_ble_clear_resolving_list * * Description This function clears the resolving list * * Parameters None. * ******************************************************************************/ void btm_ble_clear_resolving_list(void) { if (controller_get_interface()->supports_ble_privacy()) { btsnd_hcic_ble_clear_resolving_list(); } else { uint8_t param[20] = {0}; uint8_t* p = param; UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST); BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_CLEAR_IRK_LEN, param, btm_ble_resolving_list_vsc_op_cmpl); } } /******************************************************************************* * * Function btm_ble_read_resolving_list_entry * * Description This function read an IRK entry by index * * Parameters entry index. * * Returns true if command successfully sent, false otherwise * ******************************************************************************/ bool btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) { if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)) { LOG_INFO("%s Unable to read resolving list entry as resolving bit not set", __func__); return false; } if (controller_get_interface()->supports_ble_privacy()) { btsnd_hcic_ble_read_resolvable_addr_peer( p_dev_rec->ble.identity_address_with_type.type, p_dev_rec->ble.identity_address_with_type.bda); } else { uint8_t param[20] = {0}; uint8_t* p = param; UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY); UINT8_TO_STREAM(p, p_dev_rec->ble.resolving_list_index); BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_READ_IRK_LEN, param, btm_ble_resolving_list_vsc_op_cmpl); } btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, BTM_BLE_META_READ_IRK_ENTRY); return true; } /******************************************************************************* * * Function btm_ble_suspend_resolving_list_activity * * Description This function suspends all resolving list activity, * including scanning, initiating, and advertising, if * resolving list is being enabled. * * Parameters * * Returns true if suspended; false otherwise * ******************************************************************************/ static bool btm_ble_suspend_resolving_list_activity(void) { tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb; /* if resolving list is not enabled, do not need to terminate any activity */ /* if asking for stop all activity */ /* if already suspended */ if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE) return true; p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE; if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) { btm_ble_stop_adv(); p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV; } // If it's non-VSC implementation, suspend if (BleAdvertisingManager::IsInitialized() && (controller_get_interface()->supports_ble_extended_advertising() || BTM_BleMaxMultiAdvInstanceCount() == 0)) { BleAdvertisingManager::Get()->Suspend(); } if (p_ble_cb->is_ble_scan_active()) { btm_ble_stop_scan(); p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN; } if (btm_ble_suspend_bg_conn()) p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT; return true; } /******************************************************************************* * * Function btm_ble_resume_resolving_list_activity * * Description This function resumes the resolving list activity, including * scanning, initiating, and advertising, if any of these * activities has been suspended earlier. * * Returns none * ******************************************************************************/ static void btm_ble_resume_resolving_list_activity(void) { tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb; if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV) { btm_ble_start_adv(); LOG_DEBUG("Started ble advertising"); } // If it's non-VSC implementation, resume if (BleAdvertisingManager::IsInitialized() && (controller_get_interface()->supports_ble_extended_advertising() || BTM_BleMaxMultiAdvInstanceCount() == 0)) { BleAdvertisingManager::Get()->Resume(); LOG_DEBUG("Resumed ble advertising manager"); } if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN) { btm_ble_start_scan(); LOG_DEBUG("Started resolving list scan"); } if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT) { btm_ble_resume_bg_conn(); LOG_DEBUG("Resumed background connections"); } p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE; } /******************************************************************************* * * Function btm_ble_vendor_enable_irk_feature * * Description This function is called to enable or disable the RRA * offloading feature. * * Parameters enable: enable or disable the RRA offloading feature * ******************************************************************************/ static void btm_ble_vendor_enable_irk_feature(bool enable) { uint8_t param[20], *p; p = param; memset(param, 0, 20); /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE); UINT8_TO_STREAM(p, enable ? 0x01 : 0x00); BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN, param, btm_ble_resolving_list_vsc_op_cmpl); } /******************************************************************************* * * Function btm_ble_exe_disable_resolving_list * * Description execute resolving list disable * * Returns none * ******************************************************************************/ static bool btm_ble_exe_disable_resolving_list(void) { if (!btm_ble_suspend_resolving_list_activity()) return false; if (!controller_get_interface()->supports_ble_privacy()) btm_ble_vendor_enable_irk_feature(false); else btsnd_hcic_ble_set_addr_resolution_enable(false); return true; } /******************************************************************************* * * Function btm_ble_exe_enable_resolving_list * * Description enable LE resolve address list * * Returns none * ******************************************************************************/ static void btm_ble_exe_enable_resolving_list(void) { if (!btm_ble_suspend_resolving_list_activity()) return; if (!controller_get_interface()->supports_ble_privacy()) btm_ble_vendor_enable_irk_feature(true); else btsnd_hcic_ble_set_addr_resolution_enable(true); } /******************************************************************************* * * Function btm_ble_disable_resolving_list * * Description Disable LE Address resolution * * Returns none * ******************************************************************************/ bool btm_ble_disable_resolving_list(uint8_t rl_mask, bool to_resume) { uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state; /* if controller does not support RPA offloading or privacy 1.2, skip */ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) return false; btm_cb.ble_ctr_cb.rl_state &= ~rl_mask; if (rl_state != BTM_BLE_RL_IDLE && btm_cb.ble_ctr_cb.rl_state == BTM_BLE_RL_IDLE) { if (btm_ble_exe_disable_resolving_list()) { if (to_resume) btm_ble_resume_resolving_list_activity(); return true; } else return false; } return true; } /******************************************************************************* * * Function btm_ble_resolving_list_load_dev * * Description This function adds a device which is using RPA into the * acceptlist. * * Parameters pointer to device security record * * Returns true if device added, otherwise falase. * ******************************************************************************/ bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec) { const uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state; if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) { BTM_TRACE_DEBUG( "%s: Controller does not support RPA offloading or privacy 1.2", __func__); return false; } BTM_TRACE_DEBUG("%s: btm_cb.ble_ctr_cb.privacy_mode = %d", __func__, btm_cb.ble_ctr_cb.privacy_mode); if (!p_dev_rec) { BTM_TRACE_DEBUG("%s: No device security record", __func__); return false; } /* only add RPA enabled device into resolving list */ if (controller_get_interface()->supports_ble_privacy()) { if ((p_dev_rec->ble.key_type & (BTM_LE_KEY_PID | BTM_LE_KEY_LID)) == 0) { BTM_TRACE_DEBUG("%s: privacy 1.2: Device not a RPA enabled device", __func__); return false; } } else if ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) == 0) { BTM_TRACE_DEBUG("%s: RPA offloading: Device not a RPA enabled device", __func__); return false; } if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) || btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr, BTM_BLE_META_ADD_IRK_ENTRY)) { BTM_TRACE_ERROR("%s: Device already in Resolving list", __func__); return true; } if (btm_cb.ble_ctr_cb.resolving_list_avail_size == 0) { return false; } if (rl_state && !btm_ble_disable_resolving_list(rl_state, false)) { return false; } btm_ble_update_resolving_list(p_dev_rec->bd_addr, true); if (controller_get_interface()->supports_ble_privacy()) { const Octet16& peer_irk = p_dev_rec->ble.keys.irk; const Octet16& local_irk = btm_cb.devcb.id_keys.irk; if (p_dev_rec->ble.identity_address_with_type.bda.IsEmpty()) { p_dev_rec->ble.identity_address_with_type.bda = p_dev_rec->bd_addr; p_dev_rec->ble.identity_address_with_type.type = p_dev_rec->ble.ble_addr_type; } BTM_TRACE_DEBUG( "%s: adding device %s to controller resolving list", __func__, p_dev_rec->ble.identity_address_with_type.bda.ToString().c_str()); // use identical IRK for now btsnd_hcic_ble_add_device_resolving_list( p_dev_rec->ble.identity_address_with_type.type, p_dev_rec->ble.identity_address_with_type.bda, peer_irk, local_irk); if (controller_get_interface()->supports_ble_set_privacy_mode()) { BTM_TRACE_DEBUG("%s: adding device privacy mode", __func__); btsnd_hcic_ble_set_privacy_mode( p_dev_rec->ble.identity_address_with_type.type, p_dev_rec->ble.identity_address_with_type.bda, 0x01); } } else { uint8_t param[40] = {0}; uint8_t* p = param; UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY); ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, OCTET16_LEN); UINT8_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.type); BDADDR_TO_STREAM(p, p_dev_rec->ble.identity_address_with_type.bda); BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_ADD_IRK_LEN, param, btm_ble_resolving_list_vsc_op_cmpl); } btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, BTM_BLE_META_ADD_IRK_ENTRY); /* if resolving list has been turned on, re-enable it */ if (rl_state) btm_ble_enable_resolving_list(rl_state); else btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); return true; } /******************************************************************************* * * Function btm_ble_resolving_list_remove_dev * * Description This function removes the device from resolving list * * Parameters * * Returns status * ******************************************************************************/ void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) { uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state; BTM_TRACE_EVENT("%s", __func__); if (rl_mask) { if (!btm_ble_disable_resolving_list(rl_mask, false)) return; } if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && !btm_ble_brcm_find_resolving_pending_entry( p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY)) { btm_ble_update_resolving_list(p_dev_rec->bd_addr, false); btm_ble_remove_resolving_list_entry(p_dev_rec); } else { BTM_TRACE_DEBUG("Device not in resolving list"); } /* if resolving list has been turned on, re-enable it */ if (rl_mask) btm_ble_enable_resolving_list(rl_mask); } /******************************************************************************* * * Function btm_ble_enable_resolving_list * * Description enable LE resolve address list * * Returns none * ******************************************************************************/ void btm_ble_enable_resolving_list(uint8_t rl_mask) { uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state; btm_cb.ble_ctr_cb.rl_state |= rl_mask; if (rl_state == BTM_BLE_RL_IDLE && btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE && controller_get_interface()->get_ble_resolving_list_max_size() != 0) { btm_ble_exe_enable_resolving_list(); btm_ble_resume_resolving_list_activity(); } } static bool is_on_resolving_list(void* data, void* context) { tBTM_SEC_DEV_REC* p_dev = static_cast(data); if ((p_dev->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && (p_dev->ble.in_controller_list & BTM_ACCEPTLIST_BIT)) return false; return true; } /******************************************************************************* * * Function btm_ble_enable_resolving_list_for_platform * * Description enable/disable resolving list feature depending on if any * resolving list is empty and acceptlist is involoved in the * operation. * * Returns none * ******************************************************************************/ void btm_ble_enable_resolving_list_for_platform(uint8_t rl_mask) { /* if controller does not support, skip */ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) return; if (btm_cb.ble_ctr_cb.wl_state == BTM_BLE_WL_IDLE) { if (controller_get_interface()->get_ble_resolving_list_max_size() > btm_cb.ble_ctr_cb.resolving_list_avail_size) btm_ble_enable_resolving_list(rl_mask); else btm_ble_disable_resolving_list(rl_mask, true); return; } list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_on_resolving_list, NULL); if (n) btm_ble_enable_resolving_list(rl_mask); else btm_ble_disable_resolving_list(rl_mask, true); } /******************************************************************************* * * Function btm_ble_resolving_list_init * * Description Initialize resolving list in host stack * * Parameters Max resolving list size * * Returns void * ******************************************************************************/ void btm_ble_resolving_list_init(uint8_t max_irk_list_sz) { tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; uint8_t irk_mask_size = (max_irk_list_sz % 8) ? (max_irk_list_sz / 8 + 1) : (max_irk_list_sz / 8); if (max_irk_list_sz > 0) { p_q->resolve_q_random_pseudo = (RawAddress*)osi_malloc(sizeof(RawAddress) * max_irk_list_sz); p_q->resolve_q_action = (uint8_t*)osi_malloc(max_irk_list_sz); /* RPA offloading feature */ if (btm_cb.ble_ctr_cb.irk_list_mask == NULL) btm_cb.ble_ctr_cb.irk_list_mask = (uint8_t*)osi_malloc(irk_mask_size); BTM_TRACE_DEBUG("%s max_irk_list_sz = %d", __func__, max_irk_list_sz); } controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz); btm_ble_clear_resolving_list(); btm_cb.ble_ctr_cb.resolving_list_avail_size = max_irk_list_sz; }