mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(ble/bluedroid): Support bluedroid dual identity
(cherry picked from commit 2358786647)
Co-authored-by: zhiweijian <zhiweijian@espressif.com>
This commit is contained in:
@@ -345,6 +345,12 @@ if(CONFIG_BT_BLE_FEAT_CTE_EN)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND)
|
||||
list(APPEND bluedroid_host_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/stack/btm/btm_ble_pseudo.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
# TODO: Added this file in the ble mesh cmake file
|
||||
if(CONFIG_BLE_MESH)
|
||||
list(APPEND bluedroid_host_srcs "${CMAKE_CURRENT_LIST_DIR}/../../esp_ble_mesh/core/bluedroid_host/adapter.c")
|
||||
|
||||
@@ -404,6 +404,24 @@ config BT_BLE_SMP_BOND_NVS_FLASH
|
||||
help
|
||||
This select can save SMP bonding keys to nvs flash
|
||||
|
||||
config BT_BLE_PERIPH_PSEUDO_ADDR_BOND
|
||||
bool "Peripheral dual local-identity bond isolation (pseudo address)"
|
||||
depends on BT_BLE_SMP_ENABLE && BT_BLE_50_EXTEND_ADV_EN
|
||||
default n
|
||||
help
|
||||
Enable Host-internal pseudo address derivation so that one peer phone
|
||||
connecting through two distinct local identities (e.g. Public and a
|
||||
fixed Static Random advertising set) is treated as two independent
|
||||
peers. Each connection gets its own device record, LTK and NVS bond
|
||||
section keyed by pseudo = f(local_identity, peer). The over-the-air
|
||||
and SMP cryptography keep using the real peer and the real local
|
||||
identity; the pseudo address never leaves the Host.
|
||||
|
||||
This is intended for BLE 5.0 Extended Advertising peripherals that need
|
||||
simultaneous dual-identity connections with isolated bonds. Requires
|
||||
BT_BLE_50_EXTEND_ADV_EN. When disabled (default) the stack behaves
|
||||
exactly as before.
|
||||
|
||||
config BT_BLE_RPA_SUPPORTED
|
||||
bool "Update RPA to Controller"
|
||||
depends on (BT_BLE_SMP_ENABLE && ((BT_CONTROLLER_ENABLED && !SOC_BLE_DEVICE_PRIVACY_SUPPORTED) || BT_CONTROLLER_DISABLED)) # NOERROR
|
||||
|
||||
@@ -516,6 +516,59 @@ esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if (CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND)
|
||||
esp_err_t esp_ble_gap_get_real_peer_addr(esp_bd_addr_t pseudo, esp_bd_addr_t real_peer)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
LOG_ERROR("%s, bluedroid status error", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (pseudo == NULL || real_peer == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!BTM_BleGetRealPeerByPseudo(pseudo, real_peer)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_get_conn_identity(esp_bd_addr_t pseudo, esp_ble_conn_identity_t *identity)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
LOG_ERROR("%s, bluedroid status error", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (pseudo == NULL || identity == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
UINT8 peer_type = 0, local_type = 0;
|
||||
if (!BTM_BleGetConnIdentityByPseudo(pseudo, identity->peer_addr, identity->local_addr,
|
||||
&peer_type, &local_type)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
identity->peer_addr_type = peer_type;
|
||||
identity->local_addr_type = local_type;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_remove_bond_for_identity(esp_bd_addr_t local_addr,
|
||||
esp_ble_addr_type_t local_addr_type,
|
||||
esp_bd_addr_t peer_addr,
|
||||
esp_ble_addr_type_t peer_addr_type)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
LOG_ERROR("%s, bluedroid status error", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (local_addr == NULL || peer_addr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_bd_addr_t pseudo;
|
||||
BTM_BleComputePseudoForIdentity(local_addr, local_addr_type, peer_addr, peer_addr_type, pseudo);
|
||||
return esp_ble_remove_bond_device(pseudo);
|
||||
}
|
||||
#endif // CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND
|
||||
#if ((BLE_42_SCAN_EN == TRUE) || (BLE_50_EXTEND_SCAN_EN == TRUE))
|
||||
uint8_t *esp_ble_resolve_adv_data_by_type( uint8_t *adv_data, uint16_t adv_data_len, esp_ble_adv_data_type type, uint8_t *length)
|
||||
{
|
||||
|
||||
@@ -3610,6 +3610,94 @@ esp_err_t esp_ble_gap_set_key_material(const uint8_t session_key[16], const uint
|
||||
*/
|
||||
esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t * addr_type);
|
||||
|
||||
#if (CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND)
|
||||
/**
|
||||
* @brief Reverse-map a Host pseudo address to the real peer identity.
|
||||
*
|
||||
* When CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND is enabled, the
|
||||
* remote_bda reported to the application for a dual local
|
||||
* identity link is a Host-internal pseudo address (one peer
|
||||
* phone connected through two local identities shows up as two
|
||||
* different pseudo addresses). This helper returns the actual
|
||||
* over-the-air peer identity for UI / diagnostics.
|
||||
*
|
||||
* **Must be called while the link is connected.** The mapping
|
||||
* lives in a Host-side connection table that is cleared on
|
||||
* disconnect. If there is no active link for `pseudo`, the call
|
||||
* returns `ESP_FAIL` and `real_peer` is not modified.
|
||||
*
|
||||
* For offline bond information, use
|
||||
* `esp_ble_get_bond_device_list()` and read
|
||||
* `bond_key.pid_key.static_addr` for the real peer identity.
|
||||
*
|
||||
* @param[in] pseudo - the pseudo address as seen in remote_bda
|
||||
* @param[out] real_peer - filled with the real peer identity on success
|
||||
*
|
||||
* @return - ESP_OK : success (link connected and pseudo known)
|
||||
* - ESP_FAIL : Bluedroid not enabled, or pseudo not found /
|
||||
* not connected
|
||||
* - ESP_ERR_INVALID_ARG : NULL pointer argument
|
||||
*/
|
||||
esp_err_t esp_ble_gap_get_real_peer_addr(esp_bd_addr_t pseudo, esp_bd_addr_t real_peer);
|
||||
|
||||
/**
|
||||
* @brief Full identity of a dual local-identity connection.
|
||||
*/
|
||||
typedef struct {
|
||||
esp_bd_addr_t peer_addr; /*!< real over-the-air peer identity */
|
||||
esp_bd_addr_t local_addr; /*!< local identity used for this link */
|
||||
esp_ble_addr_type_t peer_addr_type; /*!< peer identity address type */
|
||||
esp_ble_addr_type_t local_addr_type; /*!< local identity address type */
|
||||
} esp_ble_conn_identity_t;
|
||||
|
||||
/**
|
||||
* @brief Get the full (peer, local) identity of a dual local-identity
|
||||
* link, keyed by the pseudo address the application sees as
|
||||
* remote_bda.
|
||||
*
|
||||
* **Must be called while the link is connected.** The mapping
|
||||
* is kept in a Host-side connection table that is registered at
|
||||
* connection complete and cleared on disconnect. If there is no
|
||||
* active link for `pseudo`, or the local identity is not yet
|
||||
* finalized (`local_ready`), the call returns `ESP_FAIL` and
|
||||
* `identity` is not modified.
|
||||
*
|
||||
* For offline bond information (no connection), use
|
||||
* `esp_ble_get_bond_device_list()` and read
|
||||
* `bond_key.pid_key.static_addr` for the real peer identity.
|
||||
* The bond list key is the stored pseudo address; local identity
|
||||
* is not exposed by this API offline.
|
||||
*
|
||||
* @param[in] pseudo - the pseudo address as seen in remote_bda
|
||||
* @param[out] identity - filled with the peer/local identity on success
|
||||
*
|
||||
* @return - ESP_OK : success (link connected and pseudo known)
|
||||
* - ESP_FAIL : Bluedroid not enabled, or pseudo not found /
|
||||
* not connected / local identity not yet ready
|
||||
* - ESP_ERR_INVALID_ARG : NULL pointer argument
|
||||
*/
|
||||
esp_err_t esp_ble_gap_get_conn_identity(esp_bd_addr_t pseudo, esp_ble_conn_identity_t *identity);
|
||||
|
||||
/**
|
||||
* @brief Remove the stored bond for one specific (local, peer)
|
||||
* identity pair. The pseudo bond section is recomputed from the
|
||||
* identity, so this only deletes that one local identity's bond
|
||||
* and never affects the same phone's other local identity.
|
||||
*
|
||||
* @param[in] local_addr - local identity used when bonding
|
||||
* @param[in] local_addr_type - local identity address type
|
||||
* @param[in] peer_addr - real peer identity
|
||||
* @param[in] peer_addr_type - peer identity address type
|
||||
*
|
||||
* @return - ESP_OK : request accepted
|
||||
* - other : invalid arguments / not enabled
|
||||
*/
|
||||
esp_err_t esp_ble_gap_remove_bond_for_identity(esp_bd_addr_t local_addr,
|
||||
esp_ble_addr_type_t local_addr_type,
|
||||
esp_bd_addr_t peer_addr,
|
||||
esp_ble_addr_type_t peer_addr_type);
|
||||
#endif // CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND
|
||||
|
||||
/**
|
||||
* @brief This function is called to get ADV data for a specific type.
|
||||
*
|
||||
|
||||
@@ -3815,17 +3815,55 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
|
||||
bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC *)&conn);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < bta_dm_cb.device_list.count; i++) {
|
||||
if (bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda)
|
||||
#if BLE_INCLUDED == TRUE
|
||||
|| bta_dm_cb.device_list.peer_device[i].transport != p_data->acl_change.transport
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BOOLEAN handle_only_match = FALSE;
|
||||
BD_ADDR op_bda;
|
||||
|
||||
bdcpy(op_bda, p_bda);
|
||||
#endif
|
||||
) {
|
||||
for (i = 0; i < bta_dm_cb.device_list.count; i++) {
|
||||
BOOLEAN entry_match = (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda) == 0)
|
||||
#if BLE_INCLUDED == TRUE
|
||||
&& (bta_dm_cb.device_list.peer_device[i].transport == p_data->acl_change.transport)
|
||||
#endif
|
||||
;
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* The peripheral pseudo-address bond feature may re-key an LE link's
|
||||
* address (RPA -> pseudo) AFTER link-up was recorded, so the stored
|
||||
* peer_bdaddr no longer matches the address reported at link-down.
|
||||
* Match by the stable connection handle for LE to avoid leaking
|
||||
* device_list entries (which would eventually exhaust the list). */
|
||||
if (!entry_match &&
|
||||
p_data->acl_change.transport == BT_TRANSPORT_LE &&
|
||||
bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_LE &&
|
||||
bta_dm_cb.device_list.peer_device[i].conn_handle == p_data->acl_change.handle) {
|
||||
entry_match = TRUE;
|
||||
handle_only_match = TRUE;
|
||||
}
|
||||
#endif
|
||||
if (!entry_match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if (handle_only_match) {
|
||||
tBTM_SEC_DEV_REC *p_rec = btm_find_dev_by_handle(p_data->acl_change.handle);
|
||||
if (p_rec) {
|
||||
bdcpy(op_bda, p_rec->bd_addr);
|
||||
} else {
|
||||
APPL_TRACE_WARNING("%s: handle-matched entry but no BTM record (handle=0x%x),"
|
||||
" falling back to event addr",
|
||||
__func__, p_data->acl_change.handle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING ) {
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if (BTM_SecDeleteDevice(op_bda, bta_dm_cb.device_list.peer_device[i].transport)) {
|
||||
#else
|
||||
if (BTM_SecDeleteDevice(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, bta_dm_cb.device_list.peer_device[i].transport)) {
|
||||
#endif
|
||||
issue_unpair_cb = TRUE;
|
||||
}
|
||||
|
||||
@@ -3880,10 +3918,18 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
|
||||
}
|
||||
}
|
||||
if (conn.link_down.is_removed) {
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BTM_SecDeleteDevice(op_bda, p_data->acl_change.transport);
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
/* need to remove all pending background connection */
|
||||
BTA_GATTC_CancelOpen(0, op_bda, FALSE);
|
||||
#endif
|
||||
#else
|
||||
BTM_SecDeleteDevice(p_bda, p_data->acl_change.transport);
|
||||
#if (BLE_INCLUDED == TRUE && GATTC_INCLUDED == TRUE)
|
||||
/* need to remove all pending background connection */
|
||||
BTA_GATTC_CancelOpen(0, p_bda, FALSE);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3892,6 +3938,11 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data)
|
||||
if ( bta_dm_cb.p_sec_cback ) {
|
||||
bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);
|
||||
if ( issue_unpair_cb ) {
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if (handle_only_match) {
|
||||
bdcpy(conn.link_down.bd_addr, op_bda);
|
||||
}
|
||||
#endif
|
||||
if (p_data->acl_change.transport == BT_TRANSPORT_LE) {
|
||||
bta_dm_cb.p_sec_cback(BTA_DM_BLE_DEV_UNPAIRED_EVT, &conn);
|
||||
} else {
|
||||
@@ -5127,7 +5178,19 @@ void bta_dm_add_ble_device (tBTA_DM_MSG *p_data)
|
||||
(p_data->add_ble_device.bd_addr[0] << 24) + (p_data->add_ble_device.bd_addr[1] << 16) + \
|
||||
(p_data->add_ble_device.bd_addr[2] << 8) + p_data->add_ble_device.bd_addr[3],
|
||||
(p_data->add_ble_device.bd_addr[4] << 8) + p_data->add_ble_device.bd_addr[5]);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if (p_data->add_ble_device.is_pseudo_bond) {
|
||||
if (!BTM_BleMarkPseudoBond(p_data->add_ble_device.bd_addr)) {
|
||||
APPL_TRACE_WARNING("BTA_DM: failed to mark pseudo bond for device %08x%04x",
|
||||
(p_data->add_ble_device.bd_addr[0] << 24) + (p_data->add_ble_device.bd_addr[1] << 16) + \
|
||||
(p_data->add_ble_device.bd_addr[2] << 8) + p_data->add_ble_device.bd_addr[3],
|
||||
(p_data->add_ble_device.bd_addr[4] << 8) + p_data->add_ble_device.bd_addr[5]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -1261,10 +1261,32 @@ void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, tBTA_LE_KEY_
|
||||
** dev_type - Remote device's device type.
|
||||
** auth_mode - auth mode
|
||||
** addr_type - LE device address type.
|
||||
** is_pseudo_bond - (pseudo bond only) TRUE when NVS section is
|
||||
** keyed by a Host pseudo; tagged on BTU thread.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode,
|
||||
tBT_DEVICE_TYPE dev_type, BOOLEAN is_pseudo_bond)
|
||||
{
|
||||
tBTA_DM_API_ADD_BLE_DEVICE *p_msg;
|
||||
|
||||
if ((p_msg = (tBTA_DM_API_ADD_BLE_DEVICE *) osi_malloc(sizeof(tBTA_DM_API_ADD_BLE_DEVICE))) != NULL) {
|
||||
memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLE_DEVICE));
|
||||
|
||||
p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
|
||||
bdcpy(p_msg->bd_addr, bd_addr);
|
||||
p_msg->addr_type = addr_type;
|
||||
p_msg->auth_mode = auth_mode;
|
||||
p_msg->dev_type = dev_type;
|
||||
p_msg->is_pseudo_bond = is_pseudo_bond;
|
||||
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode, tBT_DEVICE_TYPE dev_type)
|
||||
{
|
||||
tBTA_DM_API_ADD_BLE_DEVICE *p_msg;
|
||||
@@ -1281,6 +1303,7 @@ void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBlePasskeyReply
|
||||
|
||||
@@ -807,6 +807,9 @@ typedef struct {
|
||||
tBT_DEVICE_TYPE dev_type ;
|
||||
UINT32 auth_mode;
|
||||
tBLE_ADDR_TYPE addr_type;
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BOOLEAN is_pseudo_bond;
|
||||
#endif
|
||||
|
||||
} tBTA_DM_API_ADD_BLE_DEVICE;
|
||||
|
||||
|
||||
@@ -2531,12 +2531,19 @@ extern void BTA_DmBleConfirmReply(BD_ADDR bd_addr, BOOLEAN accept);
|
||||
** dev_type - Remote device's device type.
|
||||
** auth_mode - auth mode
|
||||
** addr_type - LE device address type.
|
||||
** is_pseudo_bond - (pseudo bond only) TRUE when NVS section is
|
||||
** keyed by a Host pseudo; tagged on BTU thread.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode,
|
||||
tBT_DEVICE_TYPE dev_type, BOOLEAN is_pseudo_bond);
|
||||
#else
|
||||
extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, int auth_mode,
|
||||
tBT_DEVICE_TYPE dev_type);
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "btc/btc_ble_storage.h"
|
||||
#include "bta/bta_gatts_co.h"
|
||||
#include "btc/btc_util.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "stack/btm_ble_api.h"
|
||||
#endif
|
||||
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
|
||||
@@ -134,6 +137,21 @@ static bt_status_t _btc_storage_add_ble_bonding_key(bt_bdaddr_t *remote_bd_addr,
|
||||
}
|
||||
|
||||
int ret = btc_config_set_bin(bdstr, name, (const uint8_t *)key, key_length);
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* If this bond's section is keyed by a Host pseudo address (dual local
|
||||
* identity link, still connected at save time), flag the section so the
|
||||
* identity-based NVS de-dup never deletes it as a "duplicate" of the other
|
||||
* local identity's bond (which shares the same peer Identity). Normal /
|
||||
* RPA-keyed bonds are NOT flagged and keep the native cleanup behavior. */
|
||||
{
|
||||
BD_ADDR real_peer;
|
||||
if (BTM_BleGetRealPeerByPseudo(remote_bd_addr->address, real_peer)) {
|
||||
btc_config_set_int(bdstr, BTC_BLE_STORAGE_PSEUDO_BOND_STR, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_btc_storage_save();
|
||||
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
|
||||
}
|
||||
@@ -256,6 +274,14 @@ static bt_status_t _btc_storage_remove_all_ble_keys(const char *name)
|
||||
if (btc_config_exist(name, BTC_BLE_STORAGE_LE_KEY_LID_STR)) {
|
||||
ret |= btc_config_remove(name, BTC_BLE_STORAGE_LE_KEY_LID_STR);
|
||||
}
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Clear the dual-identity pseudo-bond marker together with the LE keys so
|
||||
* a removed bond does not leave a stale flag that would shield an empty
|
||||
* section from cleanup. */
|
||||
if (btc_config_exist(name, BTC_BLE_STORAGE_PSEUDO_BOND_STR)) {
|
||||
ret |= btc_config_remove(name, BTC_BLE_STORAGE_PSEUDO_BOND_STR);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -273,6 +299,22 @@ void btc_storage_remove_unused_sections(uint8_t *cur_addr, tBTM_LE_PID_KEYS *del
|
||||
return;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Never use a pseudo-keyed bond as the de-dup baseline: it legitimately
|
||||
* shares the peer Identity with a normal bond on another local identity.
|
||||
* Symmetric with btc_storage_delete_duplicate_ble_devices() skipping pseudo
|
||||
* baselines. The flag is only set when keys are saved, so use the live
|
||||
* pseudo mapping rather than BTC_BLE_STORAGE_PSEUDO_BOND_STR on cur_addr.
|
||||
* Orphan cleanup below still runs; only identity de-dup is skipped. */
|
||||
BOOLEAN skip_identity_dedup = FALSE;
|
||||
{
|
||||
BD_ADDR dummy;
|
||||
if (BTM_BleGetRealPeerByPseudo(cur_addr, dummy)) {
|
||||
skip_identity_dedup = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
btc_config_lock();
|
||||
|
||||
const btc_config_section_iter_t *iter = btc_config_section_begin();
|
||||
@@ -303,6 +345,13 @@ void btc_storage_remove_unused_sections(uint8_t *cur_addr, tBTM_LE_PID_KEYS *del
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if (skip_identity_dedup) {
|
||||
iter = btc_config_section_next(iter);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
string_to_bdaddr(section, &bd_addr);
|
||||
|
||||
char buffer[sizeof(tBTM_LE_KEY_VALUE)] = {0};
|
||||
@@ -319,7 +368,14 @@ void btc_storage_remove_unused_sections(uint8_t *cur_addr, tBTM_LE_PID_KEYS *del
|
||||
if (del_pid_key->addr_type == pid_key->addr_type &&
|
||||
!btc_storage_is_all_zeros(pid_key->static_addr, sizeof(pid_key->static_addr)) &&
|
||||
memcmp(del_pid_key->static_addr, pid_key->static_addr, sizeof(pid_key->static_addr)) == 0 &&
|
||||
memcmp(cur_addr, bd_addr.address, sizeof(bd_addr.address)) != 0) {
|
||||
memcmp(cur_addr, bd_addr.address, sizeof(bd_addr.address)) != 0
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Dual local-identity bond isolation: a section keyed by a Host
|
||||
* pseudo legitimately shares the peer Identity with another
|
||||
* local identity's bond; never delete it as a "duplicate". */
|
||||
&& !btc_config_exist(section, BTC_BLE_STORAGE_PSEUDO_BOND_STR)
|
||||
#endif
|
||||
) {
|
||||
if (device_type == BT_DEVICE_TYPE_DUMO) {
|
||||
btc_config_set_int(section, BTC_BLE_STORAGE_DEV_TYPE_STR, BT_DEVICE_TYPE_BREDR);
|
||||
_btc_storage_remove_all_ble_keys(section);
|
||||
@@ -360,6 +416,19 @@ void btc_storage_delete_duplicate_ble_devices(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Dual local-identity bond isolation: never use a pseudo-keyed section
|
||||
* as the de-dup baseline. The inner check below only protects pseudo
|
||||
* candidates, so without this an order-dependent case remains: if a
|
||||
* pseudo bond is visited first and becomes the baseline, a normal bond
|
||||
* that legitimately shares the same peer Identity (no PseudoBond flag)
|
||||
* would match and be deleted. Skipping pseudo baselines makes the
|
||||
* protection symmetric. */
|
||||
if (btc_config_exist(name, BTC_BLE_STORAGE_PSEUDO_BOND_STR)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
string_to_bdaddr(name, &bd_addr);
|
||||
size_t pid_len = sizeof(tBTM_LE_PID_KEYS);
|
||||
bool pid_ok = btc_config_get_bin(name, BTC_BLE_STORAGE_LE_KEY_PID_STR, (uint8_t *)buffer, &pid_len);
|
||||
@@ -388,7 +457,13 @@ void btc_storage_delete_duplicate_ble_devices(void)
|
||||
temp_pid_key = (tBTM_LE_PID_KEYS *) temp_buffer;
|
||||
if (pid_key->addr_type == temp_pid_key->addr_type &&
|
||||
!btc_storage_is_all_zeros(temp_pid_key->static_addr, sizeof(temp_pid_key->static_addr)) &&
|
||||
memcmp(pid_key->static_addr, temp_pid_key->static_addr, sizeof(pid_key->static_addr)) == 0) {
|
||||
memcmp(pid_key->static_addr, temp_pid_key->static_addr, sizeof(pid_key->static_addr)) == 0
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Skip pseudo-keyed sections: a dual local-identity bond
|
||||
* shares the peer Identity with another bond on purpose. */
|
||||
&& !btc_config_exist(temp_name, BTC_BLE_STORAGE_PSEUDO_BOND_STR)
|
||||
#endif
|
||||
) {
|
||||
temp_iter = btc_config_section_next(temp_iter);
|
||||
if (temp_device_type == BT_DEVICE_TYPE_DUMO) {
|
||||
btc_config_set_int(temp_name, BTC_BLE_STORAGE_DEV_TYPE_STR, BT_DEVICE_TYPE_BREDR);
|
||||
@@ -915,8 +990,17 @@ bt_status_t btc_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr,
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
#if (SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#define BTC_BLE_FETCH_PSEUDO_BOND_PARAM , bool is_pseudo_bond
|
||||
#define BTC_BLE_FETCH_PSEUDO_BOND_ARG , is_pseudo_bond
|
||||
#else
|
||||
#define BTC_BLE_FETCH_PSEUDO_BOND_PARAM
|
||||
#define BTC_BLE_FETCH_PSEUDO_BOND_ARG
|
||||
#endif
|
||||
|
||||
static void _btc_read_le_key(const uint8_t key_type, const size_t key_len, bt_bdaddr_t bd_addr,
|
||||
const uint8_t addr_type, const bool add_key, bool *device_added, bool *key_found)
|
||||
const uint8_t addr_type, const bool add_key BTC_BLE_FETCH_PSEUDO_BOND_PARAM,
|
||||
bool *device_added, bool *key_found)
|
||||
{
|
||||
assert(device_added);
|
||||
assert(key_found);
|
||||
@@ -936,7 +1020,12 @@ static void _btc_read_le_key(const uint8_t key_type, const size_t key_len, bt_bd
|
||||
if(_btc_storage_get_ble_dev_auth_mode(&bd_addr, &auth_mode) != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_WARNING("%s Failed to get auth mode from flash, please erase flash and download the firmware again", __func__);
|
||||
}
|
||||
#if (SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BTA_DmAddBleDevice(bta_bd_addr, addr_type, auth_mode, BT_DEVICE_TYPE_BLE,
|
||||
is_pseudo_bond ? TRUE : FALSE);
|
||||
#else
|
||||
BTA_DmAddBleDevice(bta_bd_addr, addr_type, auth_mode, BT_DEVICE_TYPE_BLE);
|
||||
#endif
|
||||
*device_added = true;
|
||||
}
|
||||
|
||||
@@ -956,9 +1045,11 @@ bt_status_t _btc_storage_in_fetch_bonded_ble_device(const char *remote_bd_addr,
|
||||
uint32_t device_type = 0;
|
||||
int addr_type = BLE_ADDR_PUBLIC;
|
||||
bt_bdaddr_t bd_addr;
|
||||
BD_ADDR bta_bd_addr;
|
||||
bool device_added = false;
|
||||
bool key_found = false;
|
||||
#if (SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
const bool is_pseudo_bond = add && btc_config_exist(remote_bd_addr, BTC_BLE_STORAGE_PSEUDO_BOND_STR);
|
||||
#endif
|
||||
|
||||
if (!btc_config_get_int(remote_bd_addr, BTC_BLE_STORAGE_DEV_TYPE_STR, (int *)&device_type)) {
|
||||
BTC_TRACE_ERROR("%s, device_type = %x", __func__, device_type);
|
||||
@@ -966,7 +1057,6 @@ bt_status_t _btc_storage_in_fetch_bonded_ble_device(const char *remote_bd_addr,
|
||||
}
|
||||
|
||||
string_to_bdaddr(remote_bd_addr, &bd_addr);
|
||||
bdcpy(bta_bd_addr, bd_addr.address);
|
||||
|
||||
if (_btc_storage_get_remote_addr_type(&bd_addr, &addr_type) != BT_STATUS_SUCCESS) {
|
||||
addr_type = BLE_ADDR_PUBLIC;
|
||||
@@ -974,22 +1064,22 @@ bt_status_t _btc_storage_in_fetch_bonded_ble_device(const char *remote_bd_addr,
|
||||
}
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_LID, sizeof(tBTM_LE_PID_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_PCSRK, sizeof(tBTM_LE_PCSRK_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
_btc_read_le_key(BTM_LE_KEY_LCSRK, sizeof(tBTM_LE_LCSRK_KEYS),
|
||||
bd_addr, addr_type, add, &device_added, &key_found);
|
||||
bd_addr, addr_type, add BTC_BLE_FETCH_PSEUDO_BOND_ARG, &device_added, &key_found);
|
||||
|
||||
if (key_found) {
|
||||
return BT_STATUS_SUCCESS;
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
#define BTC_BLE_STORAGE_LE_KEY_LID_STR "LE_KEY_LID"
|
||||
#define BTC_BLE_STORAGE_LE_KEY_LCSRK_STR "LE_KEY_LCSRK"
|
||||
#define BTC_BLE_STORAGE_LE_AUTH_MODE_STR "AuthMode"
|
||||
/* Marks a bond whose section is keyed by a Host pseudo address (dual local
|
||||
* identity feature). Such sections legitimately share the peer Identity with
|
||||
* another (local,peer) bond and must be exempt from identity-based de-dup. */
|
||||
#define BTC_BLE_STORAGE_PSEUDO_BOND_STR "PseudoBond"
|
||||
|
||||
#define BTC_BLE_STORAGE_LOCAL_ADAPTER_STR "Adapter"
|
||||
#define BTC_BLE_STORAGE_LE_LOCAL_KEY_IR_STR "LE_LOCAL_KEY_IR"
|
||||
|
||||
@@ -161,6 +161,12 @@
|
||||
#define UC_BT_BLE_50_FEATURES_SUPPORTED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND
|
||||
#define UC_BT_BLE_PERIPH_PSEUDO_ADDR_BOND CONFIG_BT_BLE_PERIPH_PSEUDO_ADDR_BOND
|
||||
#else
|
||||
#define UC_BT_BLE_PERIPH_PSEUDO_ADDR_BOND FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLE_42_FEATURES_SUPPORTED
|
||||
#define UC_BT_BLE_42_FEATURES_SUPPORTED CONFIG_BT_BLE_42_FEATURES_SUPPORTED
|
||||
#else
|
||||
|
||||
@@ -208,6 +208,14 @@
|
||||
#define BLE_50_FEATURE_SUPPORT FALSE
|
||||
#endif
|
||||
|
||||
/* Peripheral dual local-identity bond isolation via Host-internal pseudo
|
||||
* address. Guarded so default builds keep the legacy single-bond behavior. */
|
||||
#if (UC_BT_BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#define BLE_PERIPH_PSEUDO_ADDR_BOND TRUE
|
||||
#else
|
||||
#define BLE_PERIPH_PSEUDO_ADDR_BOND FALSE
|
||||
#endif
|
||||
|
||||
#if (UC_BT_BLE_ENABLED ==TRUE)
|
||||
#if (UC_BT_BLE_42_FEATURES_SUPPORTED == TRUE || BLE_50_FEATURE_SUPPORT == FALSE)
|
||||
#define BLE_42_FEATURE_SUPPORT TRUE
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
#include "stack/btu.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "btm_int.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "btm_ble_int.h"
|
||||
#include "btm_ble_pseudo.h"
|
||||
#endif
|
||||
#include "stack/acl_hci_link_interface.h"
|
||||
#include "l2c_int.h"
|
||||
#include "stack/l2cap_hci_link_interface.h"
|
||||
@@ -571,12 +575,6 @@ void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport)
|
||||
btm_cb.ble_ctr_cb.inq_var.connectable_mode,
|
||||
p->link_role);
|
||||
|
||||
if (p->transport == BT_TRANSPORT_LE) {
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE)
|
||||
btm_ble_clear_ext_adv_ter_con_handle(p->hci_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
p_dev_rec = btm_find_dev(bda);
|
||||
if ( p_dev_rec) {
|
||||
BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x\n", p_dev_rec->sec_flags);
|
||||
@@ -603,6 +601,11 @@ void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport)
|
||||
#if (CLASSIC_BT_INCLUDED == TRUE)
|
||||
list_remove(btm_cb.p_pm_mode_db_list, p->p_pm_mode_db);
|
||||
#endif // #if (CLASSIC_BT_INCLUDED == TRUE)
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE)
|
||||
if (p->transport == BT_TRANSPORT_LE) {
|
||||
btm_ble_clear_ext_adv_ter_con_handle(p->hci_handle);
|
||||
}
|
||||
#endif
|
||||
/* Remove and free the ACL connection data */
|
||||
list_remove(btm_cb.p_acl_db_list, p);
|
||||
p = NULL;
|
||||
@@ -2920,5 +2923,16 @@ BOOLEAN btm_acl_disconnected(UINT16 handle, UINT8 reason)
|
||||
|
||||
#endif /* SMP_INCLUDED == TRUE */
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Drop the per-connection pseudo identity mapping for this handle. */
|
||||
BLE_PSEUDO_DBG("disconnect: handle=0x%x reason=0x%x -> cleanup", handle, reason);
|
||||
btm_ble_conn_identity_unregister(handle);
|
||||
#endif
|
||||
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE)
|
||||
/* Unbind ext-adv sets so a reused handle cannot leak into another inst. */
|
||||
btm_ble_clear_ext_adv_ter_con_handle(handle);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#include "stack/gap_api.h"
|
||||
//#include "bt_utils.h"
|
||||
#include "device/controller.h"
|
||||
#include "btm_ble_pseudo.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "gatt_int.h"
|
||||
#endif
|
||||
|
||||
//#define LOG_TAG "bt_btm_ble"
|
||||
//#include "osi/include/log.h"
|
||||
@@ -51,6 +55,21 @@ extern void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable);
|
||||
extern BOOLEAN smp_proc_ltk_request(BD_ADDR bda);
|
||||
#endif
|
||||
extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
static BOOLEAN btm_ble_make_conn_pseudo(UINT16 handle, BD_ADDR real_peer,
|
||||
tBLE_ADDR_TYPE peer_type, BD_ADDR pseudo_out);
|
||||
static void btm_ble_pseudo_bringup_conn(UINT16 handle, UINT8 role,
|
||||
const BD_ADDR hash_peer, UINT8 hash_peer_type,
|
||||
const BD_ADDR fallback_bda, UINT8 bda_type,
|
||||
UINT16 conn_interval, UINT16 conn_latency,
|
||||
UINT16 conn_timeout, BOOLEAN match,
|
||||
const UINT8 *air_peer, UINT8 air_peer_type,
|
||||
const char *tag, BD_ADDR conn_index_bda_out);
|
||||
static void btm_ble_pseudo_pick_peer_identity(tBTM_SEC_DEV_REC *p_rec, const BD_ADDR on_air,
|
||||
UINT8 on_air_type,
|
||||
BD_ADDR peer_out, UINT8 *p_peer_type);
|
||||
extern tBTM_SEC_DEV_REC *btm_find_dev_by_identity_addr(BD_ADDR bd_addr, UINT8 addr_type);
|
||||
#endif
|
||||
/*******************************************************************************/
|
||||
/* External Function to be called by other modules */
|
||||
/*******************************************************************************/
|
||||
@@ -281,6 +300,90 @@ void BTM_GetDeviceDHK (BT_OCTET16 dhk)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleGetRealPeerByPseudo
|
||||
**
|
||||
** Description Reverse map a Host pseudo address (as seen by the app in
|
||||
** remote_bda for a dual-identity link) to the real peer
|
||||
** identity. Returns TRUE if the pseudo is currently known.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleGetRealPeerByPseudo(BD_ADDR pseudo, BD_ADDR real_peer)
|
||||
{
|
||||
return btm_ble_pseudo_to_real_peer(pseudo, real_peer);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleGetConnIdentityByPseudo
|
||||
**
|
||||
** Description Return the full identity (real peer + local identity and
|
||||
** their address types) for a connected dual-identity link,
|
||||
** keyed by the pseudo address the application sees.
|
||||
**
|
||||
** Returns TRUE if the pseudo belongs to a finalized link.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleGetConnIdentityByPseudo(BD_ADDR pseudo, BD_ADDR peer, BD_ADDR local,
|
||||
UINT8 *peer_type, UINT8 *local_type)
|
||||
{
|
||||
tBTM_BLE_CONN_IDENTITY ent;
|
||||
|
||||
if (!btm_ble_conn_identity_get_by_pseudo(pseudo, &ent) || !ent.local_ready) {
|
||||
return FALSE;
|
||||
}
|
||||
if (peer) {
|
||||
memcpy(peer, ent.id.peer, BD_ADDR_LEN);
|
||||
}
|
||||
if (local) {
|
||||
memcpy(local, ent.id.local, BD_ADDR_LEN);
|
||||
}
|
||||
if (peer_type) {
|
||||
*peer_type = ent.id.peer_type;
|
||||
}
|
||||
if (local_type) {
|
||||
*local_type = ent.id.local_type;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleComputePseudoForIdentity
|
||||
**
|
||||
** Description Recompute the deterministic Host pseudo for a (local, peer)
|
||||
** identity pair. Lets the app target a bond section by its
|
||||
** identity even when the link is no longer connected.
|
||||
*******************************************************************************/
|
||||
void BTM_BleComputePseudoForIdentity(BD_ADDR local, UINT8 local_type,
|
||||
BD_ADDR peer, UINT8 peer_type, BD_ADDR pseudo)
|
||||
{
|
||||
tBLE_CONN_IDENTITY id;
|
||||
memset(&id, 0, sizeof(id));
|
||||
memcpy(id.local, local, BD_ADDR_LEN);
|
||||
memcpy(id.peer, peer, BD_ADDR_LEN);
|
||||
id.local_type = local_type;
|
||||
id.peer_type = peer_type;
|
||||
btm_ble_identity_to_pseudo(&id, pseudo);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleMarkPseudoBond
|
||||
**
|
||||
** Description Tag the device record for bd_addr as a pseudo-address bond
|
||||
** so the BTM_LE_KEY_PID handler keeps its pseudo bd_addr and
|
||||
** skips consolidation while loading bonds from NVS.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleMarkPseudoBond(BD_ADDR bd_addr)
|
||||
{
|
||||
tBTM_SEC_DEV_REC *p_rec = btm_find_dev(bd_addr);
|
||||
if (p_rec == NULL) {
|
||||
BLE_PSEUDO_DBG("mark pseudo bond: no rec for " BLE_PSEUDO_BDA_FMT, BLE_PSEUDO_BDA(bd_addr));
|
||||
return FALSE;
|
||||
}
|
||||
p_rec->ble.is_pseudo_bond = TRUE;
|
||||
BLE_PSEUDO_DBG("mark pseudo bond: " BLE_PSEUDO_BDA_FMT, BLE_PSEUDO_BDA(bd_addr));
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, tBLE_ADDR_TYPE *p_addr_type)
|
||||
{
|
||||
tACL_CONN *p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
|
||||
@@ -1295,10 +1398,36 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
|
||||
p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
|
||||
p_rec->ble.key_type |= BTM_LE_KEY_PID;
|
||||
BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type);
|
||||
/* update device record address as static address */
|
||||
memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
|
||||
/* combine DUMO device security record if needed */
|
||||
btm_consolidate_dev(p_rec);
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* A pseudo bond record must NEVER be consolidated onto the peer
|
||||
* Identity, otherwise two local identities of the same phone (which
|
||||
* share the peer IRK / static_addr) collapse into a single device
|
||||
* record and overwrite each other's LTK. Detect it two ways:
|
||||
* 1) an active dual-identity link: the side table has this handle;
|
||||
* 2) an NVS-loaded bond marked as pseudo: BTA_DmAddBleDevice queued
|
||||
* is_pseudo_bond=TRUE and bta_dm_add_ble_device called
|
||||
* BTM_BleMarkPseudoBond() before this PID was added. This is the
|
||||
* authoritative signal (no live connection exists at boot). */
|
||||
if (!btm_ble_conn_identity_exists_by_handle(p_rec->ble_hci_handle) &&
|
||||
!p_rec->ble.is_pseudo_bond)
|
||||
#endif
|
||||
{
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BLE_PSEUDO_DBG("PID: handle=0x%x NOT a pseudo bond -> overwrite bd_addr + consolidate (default)",
|
||||
p_rec->ble_hci_handle);
|
||||
#endif
|
||||
/* update device record address as static address */
|
||||
memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
|
||||
/* combine DUMO device security record if needed */
|
||||
btm_consolidate_dev(p_rec);
|
||||
}
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
else {
|
||||
BLE_PSEUDO_DBG("PID: handle=0x%x IS a pseudo bond -> keep bd_addr=" BLE_PSEUDO_BDA_FMT
|
||||
", skip consolidate (LTK isolated)",
|
||||
p_rec->ble_hci_handle, BLE_PSEUDO_BDA(p_rec->bd_addr));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case BTM_LE_KEY_PCSRK:
|
||||
@@ -1876,12 +2005,13 @@ UINT8 btm_ble_br_keys_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
|
||||
** air for THIS connection and causes SMP c1 / f5 / f6
|
||||
** to compute the wrong local address (pair fail 0x04).
|
||||
**
|
||||
** RPA paths (own_addr_type 0x02, or 0x03 with a valid
|
||||
** RPA paths (own_addr_type 0x02 or 0x03 with a valid
|
||||
** local RPA in the LE Enhanced Connection Complete event)
|
||||
** are left untouched. For 0x03 when the controller falls
|
||||
** back to per-set identity (zero local_rpa), replace the
|
||||
** global private_addr written by
|
||||
** btm_ble_refresh_local_resolvable_private_addr().
|
||||
** are left untouched. When the controller falls back to
|
||||
** identity (zero local_rpa) the global private_addr written
|
||||
** by btm_ble_refresh_local_resolvable_private_addr() is
|
||||
** replaced: for 0x03 with the per-set static random, and for
|
||||
** 0x02 with the public identity address.
|
||||
**
|
||||
** No-op when no ext-adv instance matches the handle
|
||||
** (initiator role or legacy adv).
|
||||
@@ -1926,6 +2056,15 @@ void btm_ble_adjust_conn_addr_for_ext_adv(UINT16 handle)
|
||||
memcpy(p_acl->conn_addr,
|
||||
extend_adv_cb.inst[inst].rand_addr,
|
||||
BD_ADDR_LEN);
|
||||
} else if (on_air_type == BLE_ADDR_PUBLIC_ID &&
|
||||
!BTM_BLE_IS_RESOLVE_BDA(p_acl->conn_addr)) {
|
||||
/* Identity fallback: controller used the public identity, not an RPA.
|
||||
* The RPA path (conn_addr already holds a valid local RPA) is left
|
||||
* untouched by the IS_RESOLVE_BDA guard, mirroring the 0x03 case. */
|
||||
p_acl->conn_addr_type = BLE_ADDR_PUBLIC;
|
||||
memcpy(p_acl->conn_addr,
|
||||
controller_get_interface()->get_address()->address,
|
||||
BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
BTM_TRACE_DEBUG("%s: handle=0x%04x inst=%u type=%u addr=%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
@@ -1935,6 +2074,69 @@ void btm_ble_adjust_conn_addr_for_ext_adv(UINT16 handle)
|
||||
}
|
||||
#endif /* (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE) && (CONTROLLER_RPA_LIST_ENABLE == TRUE) */
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_bringup_conn
|
||||
**
|
||||
** Description Shared peripheral connection-completion path for the
|
||||
** pseudo-address bond feature, used by both the synchronous
|
||||
** btm_ble_conn_complete() branch and the asynchronous RPA
|
||||
** resolution callback. It derives the Host pseudo from the
|
||||
** (local, peer-identity) pair and brings the link up on that
|
||||
** pseudo, or keeps the real peer (fallback_bda) when the local
|
||||
** identity is not yet resolvable (deferred to adv-terminate).
|
||||
**
|
||||
** When air_peer is non-NULL the ACL active_remote_addr is
|
||||
** restored to the real on-air RPA so SC pairing f5/f6 stays
|
||||
** valid after host RPA resolution rewrote bda to the pseudo.
|
||||
**
|
||||
** The address actually used to index the ACL / device record
|
||||
** is written to conn_index_bda_out. tag only labels the trace.
|
||||
*******************************************************************************/
|
||||
static void btm_ble_pseudo_bringup_conn(UINT16 handle, UINT8 role,
|
||||
const BD_ADDR hash_peer, UINT8 hash_peer_type,
|
||||
const BD_ADDR fallback_bda, UINT8 bda_type,
|
||||
UINT16 conn_interval, UINT16 conn_latency,
|
||||
UINT16 conn_timeout, BOOLEAN match,
|
||||
const UINT8 *air_peer, UINT8 air_peer_type,
|
||||
const char *tag, BD_ADDR conn_index_bda_out)
|
||||
{
|
||||
BD_ADDR pseudo;
|
||||
|
||||
if (role == HCI_ROLE_SLAVE &&
|
||||
btm_ble_make_conn_pseudo(handle, (UINT8 *)hash_peer, hash_peer_type, pseudo)) {
|
||||
memcpy(conn_index_bda_out, pseudo, BD_ADDR_LEN);
|
||||
BLE_PSEUDO_DBG("conn_complete[%s]: keyed handle=0x%x peer=" BLE_PSEUDO_BDA_FMT
|
||||
" -> pseudo=" BLE_PSEUDO_BDA_FMT,
|
||||
tag, handle, BLE_PSEUDO_BDA(hash_peer), BLE_PSEUDO_BDA(pseudo));
|
||||
} else {
|
||||
memcpy(conn_index_bda_out, fallback_bda, BD_ADDR_LEN);
|
||||
if (role == HCI_ROLE_SLAVE) {
|
||||
BLE_PSEUDO_DBG("conn_complete[%s]: local NOT ready, defer to adv-terminate; handle=0x%x peer="
|
||||
BLE_PSEUDO_BDA_FMT, tag, handle, BLE_PSEUDO_BDA(fallback_bda));
|
||||
}
|
||||
}
|
||||
|
||||
btm_ble_connected(conn_index_bda_out, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
|
||||
l2cble_conn_comp(handle, role, conn_index_bda_out, bda_type, conn_interval,
|
||||
conn_latency, conn_timeout);
|
||||
|
||||
/* Host RPA resolution replaced the on-air RPA with a stored pseudo on the
|
||||
* ACL. Restore the real on-air peer address so SC pairing f5/f6 uses what
|
||||
* the peer actually put on air (otherwise the DHKey check fails on a
|
||||
* resolved reconnect). The pseudo stays the dev_rec index. */
|
||||
if (air_peer != NULL && role == HCI_ROLE_SLAVE) {
|
||||
tACL_CONN *p_air = btm_handle_to_acl(handle);
|
||||
if (p_air != NULL && BTM_BLE_IS_RESOLVE_BDA(air_peer)) {
|
||||
memcpy(p_air->active_remote_addr, air_peer, BD_ADDR_LEN);
|
||||
p_air->active_remote_addr_type = air_peer_type;
|
||||
BLE_PSEUDO_DBG("force air addr: handle=0x%x active_remote=" BLE_PSEUDO_BDA_FMT " type %u",
|
||||
handle, BLE_PSEUDO_BDA(air_peer), air_peer_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* BLE_PERIPH_PSEUDO_ADDR_BOND */
|
||||
|
||||
#if (BLE_PRIVACY_SPT == TRUE )
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -1954,6 +2156,10 @@ static void btm_ble_resolve_random_addr_on_conn_cmpl(void *p_rec, void *p_data)
|
||||
BD_ADDR bda, local_rpa, peer_rpa;
|
||||
UINT16 conn_interval, conn_latency, conn_timeout;
|
||||
BOOLEAN match = FALSE;
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BD_ADDR air_peer; /* on-air peer address (RPA) before resolution rewrite */
|
||||
UINT8 air_peer_type;
|
||||
#endif
|
||||
|
||||
++p;
|
||||
STREAM_TO_UINT16 (handle, p);
|
||||
@@ -1973,6 +2179,14 @@ static void btm_ble_resolve_random_addr_on_conn_cmpl(void *p_rec, void *p_data)
|
||||
handle = HCID_GET_HANDLE (handle);
|
||||
BTM_TRACE_EVENT ("%s\n", __func__);
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Snapshot the real on-air peer address (the RPA the controller reported)
|
||||
* BEFORE host RPA resolution rewrites bda to a stored pseudo_addr. SC
|
||||
* pairing f5/f6 must use this real on-air address, not the pseudo. */
|
||||
memcpy(air_peer, bda, BD_ADDR_LEN);
|
||||
air_peer_type = bda_type;
|
||||
#endif
|
||||
|
||||
if (match_rec) {
|
||||
BTM_TRACE_DEBUG("%s matched and resolved random address", __func__);
|
||||
match = TRUE;
|
||||
@@ -1988,10 +2202,38 @@ static void btm_ble_resolve_random_addr_on_conn_cmpl(void *p_rec, void *p_data)
|
||||
BTM_TRACE_DEBUG("%s unable to match and resolve random address", __func__);
|
||||
}
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
{
|
||||
BD_ADDR conn_bda;
|
||||
BD_ADDR hash_peer;
|
||||
UINT8 hash_peer_type = air_peer_type;
|
||||
|
||||
/* Derive the pseudo from the PEER IDENTITY, never from a transient RPA
|
||||
* or the stored pseudo_addr. bda may have been rewritten to the old
|
||||
* pseudo above; use air_peer as the on-air fallback. */
|
||||
btm_ble_pseudo_pick_peer_identity(match_rec, air_peer, air_peer_type, hash_peer, &hash_peer_type);
|
||||
|
||||
/* Bring the link up on the real on-air address (air_peer), NOT the
|
||||
* possibly-rewritten bda. When the peer is already bonded under another
|
||||
* local identity, btm_ble_init_pseudo_addr() above rewrites bda to that
|
||||
* other identity's stored pseudo; using it as the deferred fallback
|
||||
* would make this second link collide with the first link's LCB / GATT
|
||||
* TCB (same remote_bd_addr) instead of getting its own, so the app would
|
||||
* never receive a CONNECT event for the second identity. air_peer is the
|
||||
* unique on-air address; finalize re-keys it to f(local, peer) at
|
||||
* adv-terminate. air_peer is also passed (last two real args) so the ACL
|
||||
* active_remote_addr is restored to the real on-air RPA for SC f5/f6. */
|
||||
btm_ble_pseudo_bringup_conn(handle, role, hash_peer, hash_peer_type,
|
||||
air_peer, air_peer_type, conn_interval, conn_latency,
|
||||
conn_timeout, match, air_peer, air_peer_type,
|
||||
"rpa", conn_bda);
|
||||
}
|
||||
#else
|
||||
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
|
||||
|
||||
l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
|
||||
conn_latency, conn_timeout);
|
||||
#endif
|
||||
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE) && (CONTROLLER_RPA_LIST_ENABLE == TRUE)
|
||||
/* Multi-ADV: fix up p_acl->conn_addr / conn_addr_type from per-set state. */
|
||||
@@ -2038,11 +2280,44 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Dual local-identity: a phone connecting through a SECOND local identity
|
||||
* exposes the SAME peer IRK, so btm_find_dev(bda) resolves the on-air RPA to
|
||||
* the FIRST identity's record, which belongs to a different, still-connected
|
||||
* handle. Reusing it here would steal that live link's record (overwrite its
|
||||
* ble_hci_handle and pseudo_addr) and break its encrypted session. Allocate a
|
||||
* fresh record instead; this deferred link is re-keyed to its own
|
||||
* f(local, peer) pseudo at adv-terminate finalize. */
|
||||
tBTM_SEC_DEV_REC *no_hijack_exclude = NULL;
|
||||
if (role == HCI_ROLE_SLAVE && p_dev_rec &&
|
||||
p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE &&
|
||||
p_dev_rec->ble_hci_handle != handle &&
|
||||
btm_handle_to_acl(p_dev_rec->ble_hci_handle) != NULL) {
|
||||
BLE_PSEUDO_DBG("connected: " BLE_PSEUDO_BDA_FMT " resolves to live handle 0x%x (rec %p);"
|
||||
" alloc fresh rec for handle 0x%x (no hijack)",
|
||||
BLE_PSEUDO_BDA(bda), p_dev_rec->ble_hci_handle, p_dev_rec, handle);
|
||||
/* Keep the live record we just refused to hijack out of the recycle
|
||||
* pool: when the device table is full btm_sec_alloc_dev() would call
|
||||
* btm_find_oldest_dev_ex(NULL) and could pick this very record (it does
|
||||
* not check for an active ACL), memset it and destroy the first
|
||||
* identity's keys/handle. Exclude it explicitly, mirroring
|
||||
* btm_ble_pseudo_finalize_local(). */
|
||||
no_hijack_exclude = p_dev_rec;
|
||||
p_dev_rec = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!p_dev_rec) {
|
||||
/* There is no device record for new connection. Allocate one */
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
if ((p_dev_rec = btm_sec_alloc_dev_ex (bda, no_hijack_exclude)) == NULL) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if ((p_dev_rec = btm_sec_alloc_dev (bda)) == NULL) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else { /* Update the timestamp for this device */
|
||||
p_dev_rec->timestamp = btm_cb.dev_rec_count++;
|
||||
}
|
||||
@@ -2074,6 +2349,356 @@ void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role,
|
||||
return;
|
||||
}
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_resolve_conn_local
|
||||
**
|
||||
** Description Resolve the local identity (Public or fixed Static Random)
|
||||
** that produced this peripheral connection from its ext-adv
|
||||
** instance. Returns TRUE and fills id->local / local_type
|
||||
** when the ext-adv instance is resolvable for the handle.
|
||||
*******************************************************************************/
|
||||
static BOOLEAN btm_ble_resolve_conn_local(UINT16 handle, tBLE_CONN_IDENTITY *id)
|
||||
{
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE) && (BLE_50_EXTEND_ADV_EN == TRUE)
|
||||
UINT8 inst = BTM_BleGetExtAdvInstByConHandle(handle);
|
||||
if (inst < MAX_BLE_ADV_INSTANCE) {
|
||||
tBLE_ADDR_TYPE own = extend_adv_cb.inst[inst].own_addr_type;
|
||||
if (own == BLE_ADDR_PUBLIC || own == BLE_ADDR_PUBLIC_ID) {
|
||||
memcpy(id->local, controller_get_interface()->get_address()->address, BD_ADDR_LEN);
|
||||
id->local_type = BLE_ADDR_PUBLIC;
|
||||
return TRUE;
|
||||
} else if ((own == BLE_ADDR_RANDOM || own == BLE_ADDR_RANDOM_ID) &&
|
||||
extend_adv_cb.inst[inst].rand_addr_set) {
|
||||
memcpy(id->local, extend_adv_cb.inst[inst].rand_addr, BD_ADDR_LEN);
|
||||
id->local_type = BLE_ADDR_RANDOM;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED(handle);
|
||||
UNUSED(id);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_make_conn_pseudo
|
||||
**
|
||||
** Description Resolve the local identity, derive the Host pseudo and
|
||||
** register the (handle -> pseudo, identity) side table.
|
||||
** Returns TRUE and fills pseudo_out when a usable local
|
||||
** identity is known; FALSE if the ext-adv instance is not
|
||||
** yet resolvable (the connection then keeps using the real
|
||||
** peer until btm_ble_pseudo_finalize_local() at adv-terminate).
|
||||
*******************************************************************************/
|
||||
static BOOLEAN btm_ble_make_conn_pseudo(UINT16 handle, BD_ADDR real_peer,
|
||||
tBLE_ADDR_TYPE peer_type, BD_ADDR pseudo_out)
|
||||
{
|
||||
tBLE_CONN_IDENTITY id;
|
||||
|
||||
memset(&id, 0, sizeof(id));
|
||||
memcpy(id.peer, real_peer, BD_ADDR_LEN);
|
||||
id.peer_type = peer_type;
|
||||
|
||||
if (!btm_ble_resolve_conn_local(handle, &id)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
btm_ble_identity_to_pseudo(&id, pseudo_out);
|
||||
/* The pseudo is already traced by btm_ble_identity_to_pseudo() and
|
||||
* btm_ble_conn_identity_register() via BLE_PSEUDO_DBG. */
|
||||
return btm_ble_conn_identity_register(handle, &id, pseudo_out, TRUE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_rekey_link
|
||||
**
|
||||
** Description Re-key the whole per-link chain (GATT TCB, L2CAP LCB, ACL,
|
||||
** device record) from its current index address to the given
|
||||
** pseudo, consistently. ACL active_remote_addr (real on-air
|
||||
** address) is left untouched so SMP cryptography stays valid.
|
||||
*******************************************************************************/
|
||||
static void btm_ble_pseudo_rekey_link(UINT16 handle, tACL_CONN *p_acl, const BD_ADDR pseudo)
|
||||
{
|
||||
if (p_acl == NULL || memcmp(p_acl->remote_addr, pseudo, BD_ADDR_LEN) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLE_PSEUDO_DBG("re-key: handle=0x%x " BLE_PSEUDO_BDA_FMT " -> " BLE_PSEUDO_BDA_FMT,
|
||||
handle, BLE_PSEUDO_BDA(p_acl->remote_addr), BLE_PSEUDO_BDA(pseudo));
|
||||
|
||||
tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(p_acl->remote_addr, BT_TRANSPORT_LE);
|
||||
if (p_tcb) {
|
||||
memcpy(p_tcb->peer_bda, pseudo, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
|
||||
if (p_lcb) {
|
||||
memcpy(p_lcb->remote_bd_addr, pseudo, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
tBTM_SEC_DEV_REC *p_rec = btm_find_dev_by_handle(handle);
|
||||
if (p_rec) {
|
||||
memcpy(p_rec->bd_addr, pseudo, BD_ADDR_LEN);
|
||||
memcpy(p_rec->ble.pseudo_addr, pseudo, BD_ADDR_LEN);
|
||||
|
||||
/* Remove any OTHER device record that still carries this same pseudo
|
||||
* (a stale duplicate left by an earlier pairing of the same
|
||||
* (local,peer)). Keeping it would let btm_find_dev() return the stale
|
||||
* record with an old LTK on a later encrypted reconnect -> MIC failure.
|
||||
* Only exact-pseudo duplicates are removed, so other local identities
|
||||
* (different pseudo) are never touched. */
|
||||
list_node_t *p_node = list_begin(btm_cb.p_sec_dev_rec_list);
|
||||
while (p_node) {
|
||||
tBTM_SEC_DEV_REC *p_dup = list_node(p_node);
|
||||
p_node = list_next(p_node);
|
||||
if (p_dup != p_rec && (p_dup->sec_flags & BTM_SEC_IN_USE) &&
|
||||
memcmp(p_dup->bd_addr, pseudo, BD_ADDR_LEN) == 0) {
|
||||
BLE_PSEUDO_DBG("re-key: drop stale dup rec %p for pseudo " BLE_PSEUDO_BDA_FMT,
|
||||
p_dup, BLE_PSEUDO_BDA(pseudo));
|
||||
/* Use the canonical free path so the stale LTK / BLE keys are
|
||||
* zeroed before the record memory is released; it also removes
|
||||
* the record from the list once BTM_SEC_IN_USE is cleared. */
|
||||
btm_sec_free_dev(p_dup, BT_TRANSPORT_LE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(p_acl->remote_addr, pseudo, BD_ADDR_LEN);
|
||||
BLE_PSEUDO_DBG("re-key: done handle=0x%x tcb=%p lcb=%p rec=%p", handle, p_tcb, p_lcb, p_rec);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_pick_peer_identity
|
||||
**
|
||||
** Description Choose the STABLE peer identity to feed into the pseudo
|
||||
** hash. A phone that connects with an RPA exposes a different
|
||||
** address on every connection, so hashing the on-air address
|
||||
** would make the pseudo (and therefore the bond key) drift on
|
||||
** every reconnect. Prefer the resolved IRK Identity Address
|
||||
** (ble.static_addr, learned from SMP Identity / PID) and only
|
||||
** fall back to the on-air address before pairing.
|
||||
*******************************************************************************/
|
||||
static void btm_ble_pseudo_pick_peer_identity(tBTM_SEC_DEV_REC *p_rec, const BD_ADDR on_air,
|
||||
UINT8 on_air_type,
|
||||
BD_ADDR peer_out, UINT8 *p_peer_type)
|
||||
{
|
||||
const BD_ADDR zero = {0};
|
||||
if (p_rec && (p_rec->ble.key_type & BTM_LE_KEY_PID) &&
|
||||
memcmp(p_rec->ble.static_addr, zero, BD_ADDR_LEN) != 0) {
|
||||
memcpy(peer_out, p_rec->ble.static_addr, BD_ADDR_LEN);
|
||||
*p_peer_type = p_rec->ble.static_addr_type;
|
||||
BLE_PSEUDO_DBG("pick_peer: use IDENTITY " BLE_PSEUDO_BDA_FMT " (type %u, key_type=0x%x)",
|
||||
BLE_PSEUDO_BDA(peer_out), *p_peer_type, p_rec->ble.key_type);
|
||||
} else {
|
||||
memcpy(peer_out, on_air, BD_ADDR_LEN);
|
||||
*p_peer_type = on_air_type;
|
||||
BLE_PSEUDO_DBG("pick_peer: use ON-AIR " BLE_PSEUDO_BDA_FMT " (no PID yet; rec=%p key_type=0x%x)",
|
||||
BLE_PSEUDO_BDA(peer_out), p_rec, p_rec ? p_rec->ble.key_type : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_finalize_local
|
||||
**
|
||||
** Description Second-phase finalize, called from the LE Advertising Set
|
||||
** Terminated handler. When the ext-adv instance was not yet
|
||||
** resolvable at LE Connection Complete, the link was kept on
|
||||
** the real peer address. Now that ter_con_handle is set the
|
||||
** instance is known: derive the pseudo and re-key the link.
|
||||
*******************************************************************************/
|
||||
void btm_ble_pseudo_finalize_local(UINT16 handle)
|
||||
{
|
||||
tBTM_BLE_CONN_IDENTITY ent;
|
||||
|
||||
if (btm_ble_conn_identity_get_by_handle(handle, &ent) && ent.local_ready) {
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x already keyed, skip", handle);
|
||||
return; /* already keyed at connection complete */
|
||||
}
|
||||
|
||||
tACL_CONN *p_acl = btm_handle_to_acl(handle);
|
||||
if (p_acl == NULL || p_acl->transport != BT_TRANSPORT_LE ||
|
||||
p_acl->link_role != HCI_ROLE_SLAVE) {
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x no LE slave ACL, skip (p_acl=%p)", handle, p_acl);
|
||||
return;
|
||||
}
|
||||
|
||||
tBTM_SEC_DEV_REC *p_cur = btm_find_dev_by_handle(handle);
|
||||
|
||||
/* Pick the record that carries the peer Identity. Normally that is p_cur,
|
||||
* but when btm_ble_connected() took the no-hijack path it allocated a FRESH,
|
||||
* key-less record for this handle (because the on-air RPA IRK-resolved to
|
||||
* ANOTHER live identity's bonded record). That fresh record has no PID, so
|
||||
* feeding it to pick_peer would fall back to the transient on-air RPA and
|
||||
* derive the WRONG pseudo - on an already-bonded reconnect there is no SMP
|
||||
* pairing to re-key it, so the stored LTK is never found and the link fails.
|
||||
* Recover the stable Identity by IRK-resolving the on-air RPA against the
|
||||
* bonded records (all of this phone's local-identity bonds share one IRK /
|
||||
* Identity). The local identity still comes from the adv set below, so any
|
||||
* matching bond yields the correct (local, Identity) pseudo. */
|
||||
tBTM_SEC_DEV_REC *p_id_rec = p_cur;
|
||||
if (p_id_rec == NULL || !(p_id_rec->ble.key_type & BTM_LE_KEY_PID)) {
|
||||
list_node_t *p_node = list_begin(btm_cb.p_sec_dev_rec_list);
|
||||
while (p_node) {
|
||||
tBTM_SEC_DEV_REC *p_r = list_node(p_node);
|
||||
p_node = list_next(p_node);
|
||||
if (p_r != p_cur && (p_r->sec_flags & BTM_SEC_IN_USE) &&
|
||||
(p_r->ble.key_type & BTM_LE_KEY_PID) &&
|
||||
btm_ble_addr_resolvable(p_acl->active_remote_addr, p_r)) {
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x recover identity from bonded rec %p (cur %p has no PID)",
|
||||
handle, p_r, p_cur);
|
||||
p_id_rec = p_r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tBLE_CONN_IDENTITY id;
|
||||
memset(&id, 0, sizeof(id));
|
||||
/* Hash on the stable peer identity (static_addr) once known; this keeps the
|
||||
* pseudo constant across the peer's RPA rotation. Before pairing (first
|
||||
* ever connection) only the on-air RPA is known; PID will re-key later. */
|
||||
btm_ble_pseudo_pick_peer_identity(p_id_rec, p_acl->active_remote_addr, p_acl->active_remote_addr_type,
|
||||
id.peer, &id.peer_type);
|
||||
|
||||
if (!btm_ble_resolve_conn_local(handle, &id)) {
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x local STILL unknown, give up", handle);
|
||||
return; /* instance still unknown; nothing we can do */
|
||||
}
|
||||
|
||||
BD_ADDR pseudo;
|
||||
btm_ble_identity_to_pseudo(&id, pseudo);
|
||||
|
||||
if (!btm_ble_conn_identity_register(handle, &id, pseudo, TRUE)) {
|
||||
BTM_TRACE_ERROR("%s: handle=0x%x side-table full, disconnect to avoid re-key without tracking",
|
||||
__func__, handle);
|
||||
btm_sec_disconnect(handle, HCI_ERR_HOST_REJECT_RESOURCES);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Bind this link to the device record that belongs to `pseudo` WITHOUT
|
||||
* hijacking another local identity's bonded record (a phone connecting to
|
||||
* a second local identity resolves to the first identity's record via its
|
||||
* shared IRK, so btm_ble_connected() may have reused the wrong record). At
|
||||
* this point pairing has not started, so no BLE keys can be lost. If the
|
||||
* current record only holds a classic link key, allocate a separate entry
|
||||
* so in-place re-key does not overwrite bd_addr and orphan the BR/EDR bond.
|
||||
*/
|
||||
tBTM_SEC_DEV_REC *p_tgt = btm_find_dev(pseudo);
|
||||
if (p_tgt && p_tgt != p_cur) {
|
||||
if (p_cur) {
|
||||
p_cur->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
|
||||
p_tgt->ble.ble_addr_type = p_cur->ble.ble_addr_type;
|
||||
/* p_cur was a fresh, key-less placeholder allocated by
|
||||
* btm_ble_connected()'s no-hijack path. Now that the link is bound
|
||||
* to the bonded target record, release the placeholder so it does
|
||||
* not linger as an orphan (BTM_SEC_IN_USE with an invalid handle and
|
||||
* a stale on-air RPA) consuming a device-record slot. Its
|
||||
* ble_addr_type was copied to p_tgt above. Guard on "no bond" so a
|
||||
* record that still holds BLE keys or a BR/EDR link key is never
|
||||
* destroyed (that case is handled by the separate-alloc branch). */
|
||||
if (!p_cur->ble.key_type &&
|
||||
!(p_cur->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
|
||||
btm_sec_free_dev(p_cur, BT_TRANSPORT_LE);
|
||||
p_cur = NULL;
|
||||
}
|
||||
} else {
|
||||
p_tgt->ble.ble_addr_type = p_acl->active_remote_addr_type;
|
||||
}
|
||||
p_tgt->ble_hci_handle = handle;
|
||||
p_tgt->device_type |= BT_DEVICE_TYPE_BLE;
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x bind to existing rec for pseudo", handle);
|
||||
} else if (p_tgt == NULL && p_cur &&
|
||||
(p_cur->ble.key_type || (p_cur->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) &&
|
||||
memcmp(p_cur->bd_addr, pseudo, BD_ADDR_LEN) != 0) {
|
||||
UINT8 saved_addr_type = p_cur->ble.ble_addr_type;
|
||||
tBTM_SEC_DEV_REC *p_new = btm_sec_alloc_dev_ex(pseudo, p_cur);
|
||||
if (p_new) {
|
||||
p_new->ble_hci_handle = handle;
|
||||
p_new->device_type |= BT_DEVICE_TYPE_BLE;
|
||||
p_new->ble.ble_addr_type = saved_addr_type;
|
||||
memcpy(p_new->ble.pseudo_addr, pseudo, BD_ADDR_LEN);
|
||||
if (p_new != p_cur) {
|
||||
p_cur->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
|
||||
}
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x alloc separate rec for pseudo (no hijack)", handle);
|
||||
} else {
|
||||
BTM_TRACE_ERROR("%s: handle=0x%x alloc failed, disconnect to avoid cross-identity key corruption",
|
||||
__func__, handle);
|
||||
btm_sec_disconnect(handle, HCI_ERR_HOST_REJECT_RESOURCES);
|
||||
return;
|
||||
}
|
||||
} else if (p_tgt == NULL && p_cur == NULL) {
|
||||
/* A concurrent connection IRK-resolved to the same bonded record and
|
||||
* overwrote ble_hci_handle, orphaning this link. Allocate a fresh entry. */
|
||||
tBTM_SEC_DEV_REC *p_new = btm_sec_alloc_dev(pseudo);
|
||||
if (p_new) {
|
||||
p_new->ble_hci_handle = handle;
|
||||
p_new->device_type |= BT_DEVICE_TYPE_BLE;
|
||||
p_new->ble.ble_addr_type = p_acl->active_remote_addr_type;
|
||||
memcpy(p_new->ble.pseudo_addr, pseudo, BD_ADDR_LEN);
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x alloc rec for orphan link", handle);
|
||||
} else {
|
||||
BTM_TRACE_ERROR("%s: handle=0x%x alloc failed, disconnect to avoid missing sec record",
|
||||
__func__, handle);
|
||||
btm_sec_disconnect(handle, HCI_ERR_HOST_REJECT_RESOURCES);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
BLE_PSEUDO_DBG("finalize: handle=0x%x in-place key cur rec (tgt=%p cur=%p)", handle, p_tgt, p_cur);
|
||||
}
|
||||
|
||||
/* Re-key the address chain (GATT/LCB/ACL + the now-correct dev record). */
|
||||
btm_ble_pseudo_rekey_link(handle, p_acl, pseudo);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_apply_identity
|
||||
**
|
||||
** Description Called from SMP when the peer's Identity Address (PID) is
|
||||
** received during pairing. If the link was keyed earlier from
|
||||
** a transient RPA, re-derive the pseudo from the now known
|
||||
** stable identity and re-key the link in place (the in-flight
|
||||
** pairing keys stay in the same record). Returns TRUE and
|
||||
** fills new_pseudo when the pseudo changed, so the SMP caller
|
||||
** can update smp_cb.pairing_bda to keep pairing consistent.
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_pseudo_apply_identity(UINT16 handle, const BD_ADDR identity,
|
||||
UINT8 id_type, BD_ADDR new_pseudo)
|
||||
{
|
||||
tBTM_BLE_CONN_IDENTITY ent;
|
||||
const BD_ADDR zero = {0};
|
||||
|
||||
if (!btm_ble_conn_identity_get_by_handle(handle, &ent) ||
|
||||
identity == NULL || memcmp(identity, zero, BD_ADDR_LEN) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tBLE_CONN_IDENTITY id = ent.id;
|
||||
memcpy(id.peer, identity, BD_ADDR_LEN);
|
||||
id.peer_type = id_type;
|
||||
|
||||
btm_ble_identity_to_pseudo(&id, new_pseudo);
|
||||
if (memcmp(new_pseudo, ent.pseudo, BD_ADDR_LEN) == 0) {
|
||||
BLE_PSEUDO_DBG("apply_identity: handle=0x%x pseudo unchanged (already on identity)", handle);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BLE_PSEUDO_DBG("apply_identity: handle=0x%x identity=" BLE_PSEUDO_BDA_FMT
|
||||
" re-key " BLE_PSEUDO_BDA_FMT " -> " BLE_PSEUDO_BDA_FMT,
|
||||
handle, BLE_PSEUDO_BDA(identity),
|
||||
BLE_PSEUDO_BDA(ent.pseudo), BLE_PSEUDO_BDA(new_pseudo));
|
||||
|
||||
if (!btm_ble_conn_identity_register(handle, &id, new_pseudo, ent.local_ready)) {
|
||||
BTM_TRACE_ERROR("%s: handle=0x%x side-table update failed, skip re-key", __func__, handle);
|
||||
return FALSE;
|
||||
}
|
||||
btm_ble_pseudo_rekey_link(handle, btm_handle_to_acl(handle), new_pseudo);
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* BLE_PERIPH_PSEUDO_ADDR_BOND */
|
||||
|
||||
/*****************************************************************************
|
||||
** Function btm_ble_conn_complete
|
||||
**
|
||||
@@ -2091,6 +2716,12 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
BD_ADDR local_rpa, peer_rpa;
|
||||
UINT16 conn_interval, conn_latency, conn_timeout;
|
||||
BOOLEAN match = FALSE;
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BD_ADDR pseudo_real_peer; /* controller-reported peer, before any pseudo_addr merge */
|
||||
UINT8 pseudo_peer_type; /* controller-reported peer type, before any rewrite */
|
||||
BOOLEAN pseudo_peer_valid = FALSE;
|
||||
BD_ADDR conn_index_bda; /* address actually used to index ACL/dev_rec (pseudo or real) */
|
||||
#endif
|
||||
UNUSED(evt_len);
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
STREAM_TO_UINT16 (handle, p);
|
||||
@@ -2103,6 +2734,12 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
if (enhanced) {
|
||||
STREAM_TO_BDADDR (local_rpa, p);
|
||||
STREAM_TO_BDADDR (peer_rpa, p);
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BLE_PSEUDO_DBG("conn_complete[enh]: handle=0x%x reported_peer=" BLE_PSEUDO_BDA_FMT
|
||||
" local_rpa=" BLE_PSEUDO_BDA_FMT " peer_rpa(on-air)=" BLE_PSEUDO_BDA_FMT,
|
||||
HCID_GET_HANDLE(handle), BLE_PSEUDO_BDA(bda),
|
||||
BLE_PSEUDO_BDA(local_rpa), BLE_PSEUDO_BDA(peer_rpa));
|
||||
#endif
|
||||
#if (CONTROLLER_RPA_LIST_ENABLE == TRUE)
|
||||
BD_ADDR dummy_bda = {0};
|
||||
/* For controller generates RPA, if resolving list contains no matching entry, it use identity address.
|
||||
@@ -2115,6 +2752,14 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Capture the controller-reported peer now: btm_identity_addr_to_random_pseudo()
|
||||
* may rewrite bda/bda_type for a bonded peer, which would make the
|
||||
* (local, peer) hash drift on reconnect. */
|
||||
pseudo_peer_type = bda_type;
|
||||
memcpy(pseudo_real_peer, bda, BD_ADDR_LEN);
|
||||
pseudo_peer_valid = TRUE;
|
||||
#endif
|
||||
#if (BLE_PRIVACY_SPT == TRUE )
|
||||
peer_addr_type = bda_type;
|
||||
match = btm_identity_addr_to_random_pseudo (bda, &bda_type, FALSE);
|
||||
@@ -2148,17 +2793,63 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
STREAM_TO_UINT16 (conn_timeout, p);
|
||||
handle = HCID_GET_HANDLE (handle);
|
||||
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
{
|
||||
BD_ADDR hash_peer;
|
||||
UINT8 hash_peer_type;
|
||||
tBTM_SEC_DEV_REC *p_rec = NULL;
|
||||
|
||||
#if (BLE_PRIVACY_SPT == TRUE)
|
||||
if (match) {
|
||||
p_rec = btm_find_dev_by_identity_addr(pseudo_real_peer, pseudo_peer_type);
|
||||
}
|
||||
#endif
|
||||
/* Same stable-identity pick as the RPA async path and finalize. */
|
||||
btm_ble_pseudo_pick_peer_identity(p_rec,
|
||||
pseudo_peer_valid ? pseudo_real_peer : bda,
|
||||
pseudo_peer_type,
|
||||
hash_peer, &hash_peer_type);
|
||||
/* Bring the link up on the controller-reported peer captured
|
||||
* BEFORE btm_identity_addr_to_random_pseudo() rewrote bda. For a
|
||||
* peer already bonded under another local identity that rewrite
|
||||
* turns bda into the other identity's stored pseudo; using it as
|
||||
* the deferred fallback would collide this link's LCB / GATT TCB
|
||||
* with the already-connected identity (no CONNECT event, no
|
||||
* encryption). pseudo_real_peer is unique on-air; finalize re-keys
|
||||
* it to f(local, peer). No air_peer restore here: this branch did
|
||||
* not run host RPA resolution, so the index address already is the
|
||||
* real on-air address. */
|
||||
btm_ble_pseudo_bringup_conn(handle, role, hash_peer, hash_peer_type,
|
||||
pseudo_peer_valid ? pseudo_real_peer : bda,
|
||||
pseudo_peer_valid ? pseudo_peer_type : bda_type,
|
||||
conn_interval, conn_latency,
|
||||
conn_timeout, match, NULL, 0,
|
||||
"sync", conn_index_bda);
|
||||
}
|
||||
#else
|
||||
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
|
||||
l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
|
||||
conn_latency, conn_timeout);
|
||||
#endif
|
||||
|
||||
#if (BLE_PRIVACY_SPT == TRUE)
|
||||
if (enhanced) {
|
||||
#if (BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Use the connection index address (pseudo when keyed) so the
|
||||
* ACL / device record lookups inside the refresh helpers hit
|
||||
* the right entry. */
|
||||
btm_ble_refresh_local_resolvable_private_addr(conn_index_bda, local_rpa);
|
||||
|
||||
if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT) {
|
||||
btm_ble_refresh_peer_resolvable_private_addr(conn_index_bda, peer_rpa, BLE_ADDR_RANDOM);
|
||||
}
|
||||
#else
|
||||
btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
|
||||
|
||||
if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT) {
|
||||
btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
|
||||
#include "btm_int.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "btm_ble_pseudo.h"
|
||||
#endif
|
||||
#include "stack/hcimsgs.h"
|
||||
#include "stack/hcidefs.h"
|
||||
#include "osi/allocator.h"
|
||||
@@ -625,7 +628,14 @@ tBTM_STATUS BTM_BleExtAdvSetRemove(UINT8 instance)
|
||||
extend_adv_cb.inst[instance].own_addr_type = BLE_ADDR_PUBLIC;
|
||||
extend_adv_cb.inst[instance].rand_addr_set = FALSE;
|
||||
memset(extend_adv_cb.inst[instance].rand_addr, 0, BD_ADDR_LEN);
|
||||
/* Fully reset the per-set record, consistent with BTM_BleExtAdvSetClear(). */
|
||||
adv_record[instance].ter_con_handle = INVALID_VALUE_16BIT;
|
||||
adv_record[instance].invalid = false;
|
||||
adv_record[instance].enabled = false;
|
||||
adv_record[instance].instance = INVALID_VALUE_8BIT;
|
||||
adv_record[instance].duration = INVALID_VALUE_32BIT;
|
||||
adv_record[instance].max_events = INVALID_VALUE_32BIT;
|
||||
adv_record[instance].retry_count = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
@@ -658,7 +668,18 @@ tBTM_STATUS BTM_BleExtAdvSetClear(void)
|
||||
extend_adv_cb.inst[i].own_addr_type = BLE_ADDR_PUBLIC;
|
||||
extend_adv_cb.inst[i].rand_addr_set = FALSE;
|
||||
memset(extend_adv_cb.inst[i].rand_addr, 0, BD_ADDR_LEN);
|
||||
/* Fully reset the per-set record, consistent with
|
||||
* btm_ble_advrecod_init() and the disable-all path. Resetting only
|
||||
* ter_con_handle would leave 'enabled' (and the rest) stale, making
|
||||
* btm_ble_ext_adv_active_count() report sets that the controller
|
||||
* has already removed. */
|
||||
adv_record[i].ter_con_handle = INVALID_VALUE_16BIT;
|
||||
adv_record[i].invalid = false;
|
||||
adv_record[i].enabled = false;
|
||||
adv_record[i].instance = INVALID_VALUE_8BIT;
|
||||
adv_record[i].duration = INVALID_VALUE_32BIT;
|
||||
adv_record[i].max_events = INVALID_VALUE_32BIT;
|
||||
adv_record[i].retry_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,6 +1293,14 @@ void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params)
|
||||
* after LE (Enhanced) Connection Complete. */
|
||||
#if (CONTROLLER_RPA_LIST_ENABLE == TRUE)
|
||||
btm_ble_adjust_conn_addr_for_ext_adv(adv_record[params->adv_handle].ter_con_handle);
|
||||
#endif
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* The ext-adv instance is now resolvable for this handle. If the link
|
||||
* could not be pseudo-keyed at connection complete (instance not yet
|
||||
* known), finalize it now so bond / LTK storage is isolated. */
|
||||
BLE_PSEUDO_DBG("adv_terminated: adv_handle=%u con_handle=0x%x -> finalize",
|
||||
params->adv_handle, adv_record[params->adv_handle].ter_con_handle);
|
||||
btm_ble_pseudo_finalize_local(adv_record[params->adv_handle].ter_con_handle);
|
||||
#endif
|
||||
} else {
|
||||
adv_record[params->adv_handle].ter_con_handle = INVALID_VALUE_16BIT;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
//#include "bt_utils.h"
|
||||
#include "btm_int.h"
|
||||
#include "stack/btm_ble_api.h"
|
||||
#include "btm_ble_pseudo.h"
|
||||
#include "stack/btu.h"
|
||||
#include "device/controller.h"
|
||||
#include "stack/hcimsgs.h"
|
||||
@@ -3951,6 +3952,10 @@ void btm_ble_init (void)
|
||||
#if (BLE_VENDOR_HCI_EN == TRUE)
|
||||
BTM_RegisterForVSEvents(btm_ble_vs_evt_callback, TRUE);
|
||||
#endif // #if (BLE_VENDOR_HCI_EN == TRUE)
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
btm_ble_pseudo_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -3976,6 +3981,10 @@ void btm_ble_free (void)
|
||||
osi_event_delete(p_cb->adv_rpt_ready);
|
||||
p_cb->adv_rpt_ready = NULL;
|
||||
#endif // #if (BLE_42_SCAN_EN == TRUE)
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
btm_ble_pseudo_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool enable_topology_check_flag = true;
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "btm_int.h"
|
||||
#include "btm_ble_pseudo.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
|
||||
/* The pseudo is derived with AES-CMAC, the same SMP crypto primitive used by
|
||||
* c1/f5/f6. aes_cipher_msg_auth_code() is provided by stack/smp/smp_cmac.c for
|
||||
* ALL three configurable crypto backends (mbedtls/PSA, tinycrypt, stack-native,
|
||||
* selected by SMP_CRYPTO_MBEDTLS / SMP_CRYPTO_TINYCRYPT / SMP_CRYPTO_STACK_NATIVE),
|
||||
* so the derivation automatically follows the configured crypto library and
|
||||
* this module carries no library-specific code. */
|
||||
extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
|
||||
UINT16 tlen, UINT8 *p_signature);
|
||||
|
||||
/* Fixed 16-byte domain-separation key for the pseudo CMAC (not secret; the
|
||||
* pseudo is a Host-internal index, never sent on air). Do not change after
|
||||
* deployment without bumping BLE_PSEUDO_SCHEME_VER and migrating bonds. */
|
||||
static const UINT8 btm_ble_pseudo_cmac_key[16] = {
|
||||
'E', 'S', 'P', '_', 'B', 'L', 'E', '_', 'P', 'S', 'E', 'U', 'D', 'O', 'v', BLE_PSEUDO_SCHEME_VER
|
||||
};
|
||||
|
||||
/* The side table holds one entry per concurrent LE link. BTU updates it from
|
||||
* HCI/SMP paths; BTC and the public esp_ble_gap_* API read it. All accessors
|
||||
* take btm_ble_pseudo_mutex and copy data out before returning. */
|
||||
#define BTM_BLE_PSEUDO_MAX_CONN MAX_ACL_CONNECTIONS
|
||||
|
||||
static osi_mutex_t btm_ble_pseudo_mutex;
|
||||
static tBTM_BLE_CONN_IDENTITY btm_ble_conn_id_tab[BTM_BLE_PSEUDO_MAX_CONN];
|
||||
|
||||
static tBTM_BLE_CONN_IDENTITY *conn_identity_by_handle_locked(UINT16 handle)
|
||||
{
|
||||
for (int i = 0; i < BTM_BLE_PSEUDO_MAX_CONN; i++) {
|
||||
if (btm_ble_conn_id_tab[i].in_use && btm_ble_conn_id_tab[i].handle == handle) {
|
||||
return &btm_ble_conn_id_tab[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static tBTM_BLE_CONN_IDENTITY *conn_identity_by_pseudo_locked(const BD_ADDR pseudo)
|
||||
{
|
||||
for (int i = 0; i < BTM_BLE_PSEUDO_MAX_CONN; i++) {
|
||||
if (btm_ble_conn_id_tab[i].in_use &&
|
||||
memcmp(btm_ble_conn_id_tab[i].pseudo, pseudo, BD_ADDR_LEN) == 0) {
|
||||
return &btm_ble_conn_id_tab[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_identity_to_pseudo
|
||||
*******************************************************************************/
|
||||
void btm_ble_identity_to_pseudo(const tBLE_CONN_IDENTITY *p_id, BD_ADDR pseudo)
|
||||
{
|
||||
uint8_t in[1 + BD_ADDR_LEN + BD_ADDR_LEN];
|
||||
uint8_t cmac[16];
|
||||
BT_OCTET16 key;
|
||||
BOOLEAN hashed;
|
||||
|
||||
if (p_id == NULL || pseudo == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
in[0] = BLE_PSEUDO_SCHEME_VER;
|
||||
memcpy(&in[1], p_id->local, BD_ADDR_LEN);
|
||||
memcpy(&in[1 + BD_ADDR_LEN], p_id->peer, BD_ADDR_LEN);
|
||||
|
||||
/* AES-CMAC(key, version || local || peer); follows the configured SMP
|
||||
* crypto backend (mbedtls/tinycrypt/native). */
|
||||
memcpy(key, btm_ble_pseudo_cmac_key, sizeof(key));
|
||||
hashed = aes_cipher_msg_auth_code(key, in, sizeof(in), sizeof(cmac), cmac);
|
||||
|
||||
if (!hashed) {
|
||||
/* Fall back to a deterministic non-crypto mix so we never emit a
|
||||
* zero / unstable pseudo; bring-up only, should not happen. */
|
||||
for (int i = 0; i < BD_ADDR_LEN; i++) {
|
||||
cmac[i] = in[1 + i] ^ in[1 + BD_ADDR_LEN + i] ^ BLE_PSEUDO_SCHEME_VER;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pseudo, cmac, BD_ADDR_LEN);
|
||||
|
||||
/* Force Static-Random format (top two bits = 11). This is functionally
|
||||
* required: it keeps the pseudo out of the resolvable-RPA space so that
|
||||
* btm_find_dev()/btm_ble_addr_resolvable() can never misresolve it. */
|
||||
pseudo[0] |= 0xC0;
|
||||
|
||||
/* Avoid the all-ones broadcast pattern. */
|
||||
if (pseudo[0] == 0xFF && pseudo[1] == 0xFF && pseudo[2] == 0xFF &&
|
||||
pseudo[3] == 0xFF && pseudo[4] == 0xFF && pseudo[5] == 0xFF) {
|
||||
pseudo[0] = 0xC1;
|
||||
}
|
||||
|
||||
BLE_PSEUDO_DBG("derive: local(t%u) " BLE_PSEUDO_BDA_FMT " + peer(t%u) " BLE_PSEUDO_BDA_FMT
|
||||
" -> pseudo " BLE_PSEUDO_BDA_FMT " (hashed=%d)",
|
||||
p_id->local_type, BLE_PSEUDO_BDA(p_id->local),
|
||||
p_id->peer_type, BLE_PSEUDO_BDA(p_id->peer),
|
||||
BLE_PSEUDO_BDA(pseudo), hashed);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_init / deinit
|
||||
*******************************************************************************/
|
||||
void btm_ble_pseudo_init(void)
|
||||
{
|
||||
/* Bluedroid host init runs during stack bring-up where heap exhaustion is
|
||||
* not a tolerated / recoverable condition: if this single fixed-size mutex
|
||||
* cannot be created the whole host cannot come up, so there is nothing to
|
||||
* gracefully fall back to. The return value is intentionally not checked
|
||||
* here, matching the rest of the host init path (e.g. btm_ble_init()), and
|
||||
* this is not a bug. */
|
||||
osi_mutex_new(&btm_ble_pseudo_mutex);
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
memset(btm_ble_conn_id_tab, 0, sizeof(btm_ble_conn_id_tab));
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
}
|
||||
|
||||
void btm_ble_pseudo_deinit(void)
|
||||
{
|
||||
if (btm_ble_pseudo_mutex == NULL) {
|
||||
return;
|
||||
}
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
memset(btm_ble_conn_id_tab, 0, sizeof(btm_ble_conn_id_tab));
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
osi_mutex_free(&btm_ble_pseudo_mutex);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_get_by_handle
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_get_by_handle(UINT16 handle, tBTM_BLE_CONN_IDENTITY *p_out)
|
||||
{
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
if (p_out == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
tBTM_BLE_CONN_IDENTITY *p_ent = conn_identity_by_handle_locked(handle);
|
||||
if (p_ent) {
|
||||
memcpy(p_out, p_ent, sizeof(tBTM_BLE_CONN_IDENTITY));
|
||||
found = TRUE;
|
||||
}
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_get_by_pseudo
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_get_by_pseudo(const BD_ADDR pseudo, tBTM_BLE_CONN_IDENTITY *p_out)
|
||||
{
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
if (pseudo == NULL || p_out == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
tBTM_BLE_CONN_IDENTITY *p_ent = conn_identity_by_pseudo_locked(pseudo);
|
||||
if (p_ent) {
|
||||
memcpy(p_out, p_ent, sizeof(tBTM_BLE_CONN_IDENTITY));
|
||||
found = TRUE;
|
||||
}
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_exists_by_handle
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_exists_by_handle(UINT16 handle)
|
||||
{
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
found = (conn_identity_by_handle_locked(handle) != NULL);
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_register
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_register(UINT16 handle,
|
||||
const tBLE_CONN_IDENTITY *p_id,
|
||||
const BD_ADDR pseudo,
|
||||
BOOLEAN local_ready)
|
||||
{
|
||||
BOOLEAN ok = FALSE;
|
||||
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
|
||||
tBTM_BLE_CONN_IDENTITY *p_ent = conn_identity_by_handle_locked(handle);
|
||||
if (p_ent == NULL) {
|
||||
for (int i = 0; i < BTM_BLE_PSEUDO_MAX_CONN; i++) {
|
||||
if (!btm_ble_conn_id_tab[i].in_use) {
|
||||
p_ent = &btm_ble_conn_id_tab[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_ent == NULL) {
|
||||
BTM_TRACE_ERROR("%s no free slot for handle 0x%x", __func__, handle);
|
||||
BLE_PSEUDO_DBG("register FAIL: no free slot, handle=0x%x", handle);
|
||||
} else {
|
||||
p_ent->handle = handle;
|
||||
p_ent->in_use = TRUE;
|
||||
p_ent->local_ready = local_ready;
|
||||
if (p_id) {
|
||||
memcpy(&p_ent->id, p_id, sizeof(tBLE_CONN_IDENTITY));
|
||||
}
|
||||
if (pseudo) {
|
||||
memcpy(p_ent->pseudo, pseudo, BD_ADDR_LEN);
|
||||
}
|
||||
BLE_PSEUDO_DBG("register: handle=0x%x slot=%d pseudo=" BLE_PSEUDO_BDA_FMT " local_ready=%d",
|
||||
handle, (int)(p_ent - btm_ble_conn_id_tab),
|
||||
BLE_PSEUDO_BDA(p_ent->pseudo), local_ready);
|
||||
ok = TRUE;
|
||||
}
|
||||
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_unregister
|
||||
*******************************************************************************/
|
||||
void btm_ble_conn_identity_unregister(UINT16 handle)
|
||||
{
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
tBTM_BLE_CONN_IDENTITY *p_ent = conn_identity_by_handle_locked(handle);
|
||||
if (p_ent) {
|
||||
BLE_PSEUDO_DBG("unregister: handle=0x%x pseudo=" BLE_PSEUDO_BDA_FMT,
|
||||
handle, BLE_PSEUDO_BDA(p_ent->pseudo));
|
||||
memset(p_ent, 0, sizeof(tBTM_BLE_CONN_IDENTITY));
|
||||
}
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_to_real_peer
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_pseudo_to_real_peer(const BD_ADDR pseudo, BD_ADDR real_peer)
|
||||
{
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
if (pseudo == NULL || real_peer == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&btm_ble_pseudo_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
tBTM_BLE_CONN_IDENTITY *p_ent = conn_identity_by_pseudo_locked(pseudo);
|
||||
if (p_ent) {
|
||||
memcpy(real_peer, p_ent->id.peer, BD_ADDR_LEN);
|
||||
found = TRUE;
|
||||
}
|
||||
osi_mutex_unlock(&btm_ble_pseudo_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
#endif /* BLE_INCLUDED && SMP_INCLUDED && BLE_PERIPH_PSEUDO_ADDR_BOND */
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "stack/hcidefs.h"
|
||||
#include "stack/l2c_api.h"
|
||||
|
||||
static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void);
|
||||
static tBTM_SEC_DEV_REC *btm_find_oldest_dev_ex (tBTM_SEC_DEV_REC *exclude_rec);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -330,6 +330,22 @@ BOOLEAN btm_find_sec_dev_in_list (void *p_node_data, void *context)
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
|
||||
{
|
||||
return btm_sec_alloc_dev_ex(bd_addr, NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btm_sec_alloc_dev_ex
|
||||
**
|
||||
** Description Same as btm_sec_alloc_dev(), but exclude_rec will never be
|
||||
** recycled when the device table is full and an existing entry
|
||||
** must be reused.
|
||||
**
|
||||
** Returns Pointer to the record or NULL
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_SEC_DEV_REC *btm_sec_alloc_dev_ex (BD_ADDR bd_addr, tBTM_SEC_DEV_REC *exclude_rec)
|
||||
{
|
||||
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
|
||||
tBTM_SEC_DEV_REC *p_dev_new_rec = NULL;
|
||||
@@ -339,7 +355,7 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
|
||||
BOOLEAN new_entry_found = FALSE;
|
||||
BOOLEAN old_entry_found = FALSE;
|
||||
BOOLEAN malloc_new_entry = FALSE;
|
||||
BTM_TRACE_EVENT ("btm_sec_alloc_dev - start alloc for device %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
BTM_TRACE_EVENT ("btm_sec_alloc_dev_ex - start alloc for device %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
|
||||
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
|
||||
p_dev_old_rec = list_node(p_node);
|
||||
@@ -374,13 +390,16 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
|
||||
}
|
||||
}
|
||||
if (!new_entry_found) {
|
||||
p_dev_rec = btm_find_oldest_dev();
|
||||
p_dev_rec = btm_find_oldest_dev_ex(exclude_rec);
|
||||
#if (BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)
|
||||
// If device record exists and contains identity key, remove it from resolving list
|
||||
if (p_dev_rec && (p_dev_rec->ble.key_type & SMP_SEC_KEY_TYPE_ID)) {
|
||||
btm_ble_resolving_list_remove_dev(p_dev_rec);
|
||||
}
|
||||
#endif // (BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)
|
||||
if (p_dev_rec == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* if the old device entry not present go with new entry */
|
||||
if (old_entry_found) {
|
||||
@@ -654,16 +673,17 @@ tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btm_find_oldest_dev
|
||||
** Function btm_find_oldest_dev_ex
|
||||
**
|
||||
** Description Locates the oldest device in use. It first looks for
|
||||
** the oldest non-paired device. If all devices are paired it
|
||||
** deletes the oldest paired device.
|
||||
** deletes the oldest paired device. exclude_rec is never
|
||||
** returned when non-NULL.
|
||||
**
|
||||
** Returns Pointer to the record or NULL
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
|
||||
static tBTM_SEC_DEV_REC *btm_find_oldest_dev_ex (tBTM_SEC_DEV_REC *exclude_rec)
|
||||
{
|
||||
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
|
||||
tBTM_SEC_DEV_REC *p_oldest = NULL;
|
||||
@@ -673,6 +693,9 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
|
||||
/* First look for the non-paired devices for the oldest entry */
|
||||
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
|
||||
p_dev_rec = list_node(p_node);
|
||||
if (p_dev_rec == exclude_rec) {
|
||||
continue;
|
||||
}
|
||||
if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
|
||||
|| ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) != 0)) {
|
||||
continue; /* Device is paired so skip it */
|
||||
@@ -689,8 +712,12 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
|
||||
}
|
||||
|
||||
/* All devices are paired; find the oldest */
|
||||
old_ts = 0xFFFFFFFF;
|
||||
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
|
||||
p_dev_rec = list_node(p_node);
|
||||
if (p_dev_rec == exclude_rec) {
|
||||
continue;
|
||||
}
|
||||
if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Peripheral dual local-identity bond isolation: Host-internal pseudo
|
||||
* address derivation and the per-connection identity side table.
|
||||
*
|
||||
* A pseudo address is a 6-byte Host-only key computed from
|
||||
* (local_identity, peer). It lets one peer phone that connects through two
|
||||
* distinct local identities (e.g. Public and a fixed Static Random adv set)
|
||||
* appear as two independent peers inside the Host (separate device record,
|
||||
* LTK and NVS bond section). The over-the-air and SMP cryptography keep
|
||||
* using the real peer and the real local identity; the pseudo never leaves
|
||||
* the Host.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef BTM_BLE_PSEUDO_H
|
||||
#define BTM_BLE_PSEUDO_H
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/bt_types.h"
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
|
||||
#include "common/bt_trace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Debug logging for the pseudo-address bond feature. Routed through the Host
|
||||
* BTM trace macro so the "[PSEUDO]" lines follow the standard Bluetooth log
|
||||
* level (BT_LOG_LEVEL_BTM) like the rest of the stack. */
|
||||
#define BLE_PSEUDO_DBG(fmt, ...) BTM_TRACE_DEBUG("[PSEUDO] " fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Helper to print a BD_ADDR without a MACSTR dependency. */
|
||||
#define BLE_PSEUDO_BDA(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define BLE_PSEUDO_BDA_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
/* Bump when the pseudo derivation input layout or algorithm changes (e.g. v1
|
||||
* was SHA-256 truncated; v2 is AES-CMAC via the configured SMP crypto backend).
|
||||
* Persisted in the input/key so a mismatch yields a different pseudo. */
|
||||
#define BLE_PSEUDO_SCHEME_VER 2
|
||||
|
||||
/* Identity that produced one connection: the resolved real peer plus the
|
||||
* local identity (Public or fixed Static Random) of the adv set / link. */
|
||||
typedef struct {
|
||||
BD_ADDR local; /* local identity (NOT a transient RPA) */
|
||||
BD_ADDR peer; /* resolved real peer identity */
|
||||
tBLE_ADDR_TYPE local_type;
|
||||
tBLE_ADDR_TYPE peer_type;
|
||||
} tBLE_CONN_IDENTITY;
|
||||
|
||||
/* Per-connection side table entry, keyed by HCI handle. */
|
||||
typedef struct {
|
||||
UINT16 handle;
|
||||
BD_ADDR pseudo;
|
||||
tBLE_CONN_IDENTITY id;
|
||||
BOOLEAN local_ready; /* TRUE once local identity finalized */
|
||||
BOOLEAN in_use;
|
||||
} tBTM_BLE_CONN_IDENTITY;
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_identity_to_pseudo
|
||||
**
|
||||
** Description Deterministically derive a 6-byte Host pseudo address from
|
||||
** (local identity || peer). Same input always yields the same
|
||||
** output. The result is forced to Static-Random format (top
|
||||
** two bits = 11) so it can never be mistaken for a resolvable
|
||||
** RPA by btm_find_dev()/btm_ble_addr_resolvable().
|
||||
*******************************************************************************/
|
||||
void btm_ble_identity_to_pseudo(const tBLE_CONN_IDENTITY *p_id, BD_ADDR pseudo);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_init / btm_ble_pseudo_deinit
|
||||
*******************************************************************************/
|
||||
void btm_ble_pseudo_init(void);
|
||||
void btm_ble_pseudo_deinit(void);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_register
|
||||
**
|
||||
** Description Record (handle -> pseudo, identity). If an entry for the
|
||||
** handle already exists it is updated. Returns FALSE when the
|
||||
** table is full.
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_register(UINT16 handle,
|
||||
const tBLE_CONN_IDENTITY *p_id,
|
||||
const BD_ADDR pseudo,
|
||||
BOOLEAN local_ready);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_unregister
|
||||
*******************************************************************************/
|
||||
void btm_ble_conn_identity_unregister(UINT16 handle);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_get_by_handle / get_by_pseudo
|
||||
**
|
||||
** Description Copy-out snapshot of a side-table entry. Safe from any task.
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_get_by_handle(UINT16 handle, tBTM_BLE_CONN_IDENTITY *p_out);
|
||||
BOOLEAN btm_ble_conn_identity_get_by_pseudo(const BD_ADDR pseudo, tBTM_BLE_CONN_IDENTITY *p_out);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_conn_identity_exists_by_handle
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_conn_identity_exists_by_handle(UINT16 handle);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_to_real_peer
|
||||
**
|
||||
** Description Reverse map a pseudo back to the real peer. Returns TRUE if
|
||||
** the pseudo is known.
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_pseudo_to_real_peer(const BD_ADDR pseudo, BD_ADDR real_peer);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_finalize_local
|
||||
**
|
||||
** Description Second-phase finalize, called from the LE Advertising Set
|
||||
** Terminated handler. Re-keys a link to its pseudo when the
|
||||
** ext-adv instance was not resolvable at connection complete.
|
||||
** Defined in btm_ble.c.
|
||||
*******************************************************************************/
|
||||
void btm_ble_pseudo_finalize_local(UINT16 handle);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function btm_ble_pseudo_apply_identity
|
||||
**
|
||||
** Description Re-key a link from a transient-RPA-derived pseudo to the
|
||||
** stable f(local, peer Identity) pseudo once the peer's
|
||||
** Identity Address (PID) is learned during pairing. Returns
|
||||
** TRUE and fills new_pseudo when the pseudo changed so the
|
||||
** SMP caller can keep smp_cb.pairing_bda consistent.
|
||||
*******************************************************************************/
|
||||
BOOLEAN btm_ble_pseudo_apply_identity(UINT16 handle, const BD_ADDR identity,
|
||||
UINT8 id_type, BD_ADDR new_pseudo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BLE_INCLUDED && SMP_INCLUDED && BLE_PERIPH_PSEUDO_ADDR_BOND */
|
||||
#endif /* BTM_BLE_PSEUDO_H */
|
||||
@@ -624,6 +624,12 @@ typedef struct {
|
||||
BD_ADDR current_addr; /* current adv addr*/
|
||||
bool current_addr_valid; /* current addr info is valid or not*/
|
||||
#endif
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BOOLEAN is_pseudo_bond; /* record is keyed by a Host pseudo
|
||||
* (dual local-identity bond); never
|
||||
* consolidate it onto the peer
|
||||
* Identity or its LTK is lost */
|
||||
#endif
|
||||
} tBTM_SEC_BLE;
|
||||
|
||||
|
||||
@@ -1282,6 +1288,7 @@ void btm_page_to_setup_timeout (void *p_tle);
|
||||
BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
|
||||
|
||||
tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr);
|
||||
tBTM_SEC_DEV_REC *btm_sec_alloc_dev_ex (BD_ADDR bd_addr, tBTM_SEC_DEV_REC *exclude_rec);
|
||||
void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport);
|
||||
tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr);
|
||||
tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr);
|
||||
|
||||
@@ -2635,6 +2635,54 @@ bool BTM_GetLocalIRK(uint8_t *irk);
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleGetCurrentAddress(BD_ADDR addr, uint8_t *addr_type);
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleGetRealPeerByPseudo
|
||||
**
|
||||
** Description Reverse map a Host pseudo address to the real peer identity
|
||||
** for a dual-identity (pseudo-address bond) link.
|
||||
**
|
||||
** Returns TRUE if the pseudo is known, FALSE otherwise.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleGetRealPeerByPseudo(BD_ADDR pseudo, BD_ADDR real_peer);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleGetConnIdentityByPseudo
|
||||
**
|
||||
** Description Return the real peer + local identity (and address types)
|
||||
** for a connected dual-identity link keyed by its pseudo.
|
||||
**
|
||||
** Returns TRUE if the pseudo belongs to a finalized link.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleGetConnIdentityByPseudo(BD_ADDR pseudo, BD_ADDR peer, BD_ADDR local,
|
||||
UINT8 *peer_type, UINT8 *local_type);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleComputePseudoForIdentity
|
||||
**
|
||||
** Description Recompute the deterministic Host pseudo for a (local, peer)
|
||||
** identity pair (e.g. to remove a stored bond by identity).
|
||||
*******************************************************************************/
|
||||
void BTM_BleComputePseudoForIdentity(BD_ADDR local, UINT8 local_type,
|
||||
BD_ADDR peer, UINT8 peer_type, BD_ADDR pseudo);
|
||||
|
||||
/*******************************************************************************
|
||||
** Function BTM_BleMarkPseudoBond
|
||||
**
|
||||
** Description Mark the device record for bd_addr as a pseudo-address bond
|
||||
** (dual local-identity). Normally invoked from bta_dm_add_ble_device
|
||||
** on the BTU thread when BTA_DmAddBleDevice is called with
|
||||
** is_pseudo_bond=TRUE while loading bonds from NVS. There is no live
|
||||
** connection at boot, so the side table cannot be consulted. The mark
|
||||
** prevents the BTM_LE_KEY_PID handler from consolidating two pseudo
|
||||
** bonds (which share the peer IRK / Identity) into one record and
|
||||
** losing one LTK after reboot.
|
||||
**
|
||||
** Returns TRUE if a record was found and marked.
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleMarkPseudoBond(BD_ADDR bd_addr);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM__BLEReadDiscoverability
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "device/interop.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "btm_int.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "btm_ble_pseudo.h"
|
||||
#endif
|
||||
#include "stack/l2c_api.h"
|
||||
#include "smp_int.h"
|
||||
#if (SMP_CRYPTO_MBEDTLS == TRUE)
|
||||
@@ -1215,6 +1218,28 @@ void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||
}
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
/* Dual-identity bond isolation: the link may have been keyed earlier from a
|
||||
* transient RPA. Now that the peer's stable Identity Address is known,
|
||||
* re-derive the pseudo from (local, Identity) and re-key the link so the
|
||||
* stored bond is reproducible across the peer's future RPA rotations. Keep
|
||||
* smp_cb.pairing_bda consistent so the in-flight pairing continues. */
|
||||
{
|
||||
tACL_CONN *p_acl = btm_bda_to_acl(p_cb->pairing_bda, BT_TRANSPORT_LE);
|
||||
BLE_PSEUDO_DBG("smp PID: pairing_bda=" BLE_PSEUDO_BDA_FMT " acl=%p id_addr=" BLE_PSEUDO_BDA_FMT,
|
||||
BLE_PSEUDO_BDA(p_cb->pairing_bda), p_acl, BLE_PSEUDO_BDA(pid_key.static_addr));
|
||||
if (p_acl != NULL) {
|
||||
BD_ADDR new_pseudo;
|
||||
if (btm_ble_pseudo_apply_identity(p_acl->hci_handle, pid_key.static_addr,
|
||||
pid_key.addr_type, new_pseudo)) {
|
||||
memcpy(p_cb->pairing_bda, new_pseudo, BD_ADDR_LEN);
|
||||
BLE_PSEUDO_DBG("smp PID: pairing_bda updated -> " BLE_PSEUDO_BDA_FMT,
|
||||
BLE_PSEUDO_BDA(p_cb->pairing_bda));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
smp_key_distribution_by_transport(p_cb, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include "smp_int.h"
|
||||
#include "device/controller.h"
|
||||
#include "btm_int.h"
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
#include "btm_ble_pseudo.h"
|
||||
#endif
|
||||
#include "common/bte_appl.h"
|
||||
|
||||
#define SMP_PAIRING_REQ_SIZE 7
|
||||
@@ -1530,6 +1533,10 @@ void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb)
|
||||
BTM_ReadConnectionAddr( p_cb->pairing_bda, bda, &addr_type);
|
||||
BDADDR_TO_STREAM(p, bda);
|
||||
UINT8_TO_STREAM(p, addr_type);
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BLE_PSEUDO_DBG("smp local addr for f5/f6 = " BLE_PSEUDO_BDA_FMT " type %u (pairing_bda " BLE_PSEUDO_BDA_FMT ")",
|
||||
BLE_PSEUDO_BDA(bda), addr_type, BLE_PSEUDO_BDA(p_cb->pairing_bda));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1557,6 +1564,10 @@ void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb)
|
||||
|
||||
BDADDR_TO_STREAM(p, bda);
|
||||
UINT8_TO_STREAM(p, addr_type);
|
||||
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE && BLE_PERIPH_PSEUDO_ADDR_BOND == TRUE)
|
||||
BLE_PSEUDO_DBG("smp peer addr for f5/f6 = " BLE_PSEUDO_BDA_FMT " type %u (pairing_bda " BLE_PSEUDO_BDA_FMT ")",
|
||||
BLE_PSEUDO_BDA(bda), addr_type, BLE_PSEUDO_BDA(p_cb->pairing_bda));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Reference in New Issue
Block a user