ret_code_t pds_space_reserve(pm_peer_data_const_t const * p_peer_data, pm_prepare_token_t * p_prepare_token) { ret_code_t ret; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_peer_data != NULL); NRF_PM_DEBUG_CHECK(p_prepare_token != NULL); VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id); ret = fds_reserve((fds_reserve_token_t*)p_prepare_token, p_peer_data->length_words); switch (ret) { case FDS_SUCCESS: return NRF_SUCCESS; case FDS_ERR_RECORD_TOO_LARGE: return NRF_ERROR_INVALID_LENGTH; case FDS_ERR_NO_SPACE_IN_FLASH: return NRF_ERROR_STORAGE_FULL; default: return NRF_ERROR_INTERNAL; } }
static ret_code_t peer_data_find(pm_peer_id_t peer_id, pm_peer_data_id_t data_id, fds_record_desc_t * const p_desc) { ret_code_t ret; fds_find_token_t ftok; NRF_PM_DEBUG_CHECK(peer_id < PM_PEER_ID_N_AVAILABLE_IDS); NRF_PM_DEBUG_CHECK(peer_data_id_is_valid(data_id)); NRF_PM_DEBUG_CHECK(p_desc != NULL); memset(&ftok, 0x00, sizeof(fds_find_token_t)); uint16_t file_id = peer_id_to_file_id(peer_id); uint16_t record_key = peer_data_id_to_record_key(data_id); ret = fds_record_find(file_id, record_key, p_desc, &ftok); if (ret != FDS_SUCCESS) { return NRF_ERROR_NOT_FOUND; } return NRF_SUCCESS; }
/**@brief Event handler for events from the Peer Database module. * This function is extern in Peer Database. * * @param[in] p_event The event that has happend with peer id and flags. */ void im_pdb_evt_handler(pdb_evt_t const * p_event) { ret_code_t ret; pm_peer_id_t peer_id; pm_peer_data_flash_t peer_data; pm_peer_data_flash_t peer_data_duplicate; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_event != NULL); if ((p_event->evt_id != PDB_EVT_WRITE_BUF_STORED) || (p_event->data_id != PM_PEER_DATA_ID_BONDING)) { return; } // If new data about peer id has been stored it is compared to other peers peer ids in // search of duplicates. ret = pdb_peer_data_ptr_get(p_event->peer_id, PM_PEER_DATA_ID_BONDING, &peer_data); if (ret != NRF_SUCCESS) { // @note emdi: this shouldn't happen, since the data was just stored, right? NRF_PM_DEBUG_CHECK(false); return; } pds_peer_data_iterate_prepare(); while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data_duplicate)) { if (p_event->peer_id == peer_id) { // Skip the iteration if the bonding data retrieved is for a peer // with the same ID as the one contained in the event. continue; } if (im_is_duplicate_bonding_data(peer_data.p_bonding_data, peer_data_duplicate.p_bonding_data)) { im_evt_t im_evt; im_evt.conn_handle = im_conn_handle_get(p_event->peer_id); im_evt.evt_id = IM_EVT_DUPLICATE_ID; im_evt.params.duplicate_id.peer_id_1 = p_event->peer_id; im_evt.params.duplicate_id.peer_id_2 = peer_id; evt_send(&im_evt); break; } } }
// @note emdi: unused.. ret_code_t pds_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id) { ret_code_t ret; fds_record_desc_t record_desc; NRF_PM_DEBUG_CHECK(m_module_initialized); VERIFY_PEER_ID_IN_RANGE(peer_id); VERIFY_PEER_DATA_ID_IN_RANGE(data_id); ret = peer_data_find(peer_id, data_id, &record_desc); if (ret != NRF_SUCCESS) { return NRF_ERROR_NOT_FOUND; } ret = fds_record_delete(&record_desc); switch (ret) { case FDS_SUCCESS: return NRF_SUCCESS; case FDS_ERR_NO_SPACE_IN_QUEUES: return NRF_ERROR_BUSY; default: return NRF_ERROR_INTERNAL; } }
ret_code_t pds_space_reserve_cancel(pm_prepare_token_t prepare_token) { ret_code_t ret; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(prepare_token != PDS_PREPARE_TOKEN_INVALID); ret = fds_reserve_cancel((fds_reserve_token_t*)&prepare_token); if (ret != FDS_SUCCESS) { return NRF_ERROR_INTERNAL; } return NRF_SUCCESS; }
ret_code_t pds_init() { ret_code_t ret; // Check for re-initialization if debugging. NRF_PM_DEBUG_CHECK(!m_module_initialized); ret = fds_register(fds_evt_handler); if (ret != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } ret = fds_init(); if (ret != NRF_SUCCESS) { return NRF_ERROR_STORAGE_FULL; } peer_id_init(); peer_ids_load(); m_module_initialized = true; return NRF_SUCCESS; }
ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr) { uint8_t conn_index; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_ble_addr != NULL); conn_index = get_connection_by_conn_handle(conn_handle); if (conn_index != IM_NO_INVALID_CONN_HANDLES) { *p_ble_addr = m_connections[conn_index].peer_address; return NRF_SUCCESS; } return NRF_ERROR_NOT_FOUND; }
bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1, ble_gap_master_id_t const * p_master_id2) { NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_master_id1 != NULL); NRF_PM_DEBUG_CHECK(p_master_id2 != NULL); if (!im_master_id_is_valid(p_master_id1)) { return false; } if (p_master_id1->ediv != p_master_id2->ediv) { return false; } return (memcmp(p_master_id1->rand, p_master_id2->rand, BLE_GAP_SEC_RAND_LEN) == 0); }
ret_code_t pds_peer_id_free(pm_peer_id_t peer_id) { NRF_PM_DEBUG_CHECK(m_module_initialized); VERIFY_PEER_ID_IN_RANGE(peer_id); (void)peer_id_delete(peer_id); peer_data_delete(); return NRF_SUCCESS; }
/**@brief Function to compare two sets of bonding data to check if they belong to the same device. * @note Invalid irks will never match even though they are identical. * * @param[in] p_bonding_data1 First bonding data for comparison * @param[in] p_bonding_data2 Second bonding data for comparison * * @return True if the input matches, false if it does not. */ bool im_is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1, pm_peer_data_bonding_t const * p_bonding_data2) { NRF_PM_DEBUG_CHECK(p_bonding_data1 != NULL); NRF_PM_DEBUG_CHECK(p_bonding_data2 != NULL); if (!is_valid_irk(&p_bonding_data1->peer_id.id_info)) { return false; } bool duplicate_irk = (memcmp(p_bonding_data1->peer_id.id_info.irk, p_bonding_data2->peer_id.id_info.irk, BLE_GAP_SEC_KEY_LEN) == 0); bool duplicate_addr = addr_compare(&p_bonding_data1->peer_id.id_addr_info, &p_bonding_data2->peer_id.id_addr_info); return duplicate_irk || duplicate_addr; }
ret_code_t im_id_addr_get(ble_gap_addr_t * p_addr) { NRF_PM_DEBUG_CHECK(p_addr != NULL); #if (NRF_SD_BLE_API_VERSION == 2) memcpy(p_addr, &m_current_id_addr, sizeof(ble_gap_addr_t)); return NRF_SUCCESS; #else return sd_ble_gap_addr_get(p_addr); #endif }
bool pds_peer_data_iterate(pm_peer_data_id_t data_id, pm_peer_id_t * const p_peer_id, pm_peer_data_flash_t * const p_data) { ret_code_t ret; uint16_t rec_key; fds_record_desc_t rec_desc; fds_flash_record_t rec_flash; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_peer_id != NULL); NRF_PM_DEBUG_CHECK(p_data != NULL); // @note emdi: should we check the data_id ? rec_key = peer_data_id_to_record_key(data_id); if (fds_record_find_by_key(rec_key, &rec_desc, &m_fds_ftok) != NRF_SUCCESS) { return false; } ret = fds_record_open(&rec_desc, &rec_flash); if (ret != NRF_SUCCESS) { // It can only happen if the record was deleted after the call to fds_record_find_by_key(), // before we could open it, or if CRC support was enabled in Flash Data Storage at compile // time and the CRC check failed. return false; } p_data->data_id = data_id; p_data->length_words = rec_flash.p_header->tl.length_words; p_data->p_all_data = rec_flash.p_data; *p_peer_id = file_id_to_peer_id(rec_flash.p_header->ic.file_id); (void)fds_record_close(&rec_desc); return true; }
/**@brief Function checking the validity of an IRK * * @detail An all-zero IRK is not valid. This function will check if a given IRK is valid. * * @param[in] p_irk The IRK for which the validity is going to be checked. * * @retval true The IRK is valid. * @retval false The IRK is invalid. */ bool is_valid_irk(ble_gap_irk_t const * p_irk) { NRF_PM_DEBUG_CHECK(p_irk != NULL); for (uint32_t i = 0; i < BLE_GAP_SEC_KEY_LEN; i++) { if (p_irk->irk[i] != 0) { return true; } } return false; }
uint16_t im_conn_handle_get(pm_peer_id_t peer_id) { NRF_PM_DEBUG_CHECK(m_module_initialized); for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++) { if (peer_id == m_connections[i].peer_id) { return m_connections[i].conn_handle; } } return BLE_CONN_HANDLE_INVALID; }
ret_code_t im_privacy_get(pm_privacy_params_t * p_privacy_params) { #if (NRF_SD_BLE_API_VERSION == 2) ble_gap_addr_t cur_addr; ble_opt_t cur_privacy_opt; NRF_PM_DEBUG_CHECK(p_privacy_params != NULL); NRF_PM_DEBUG_CHECK(p_privacy_params->p_device_irk != NULL); cur_privacy_opt.gap_opt.privacy.p_irk = p_privacy_params->p_device_irk; // Can not fail. (void) sd_ble_gap_address_get(&cur_addr); if ( cur_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE || cur_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) { p_privacy_params->privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY; p_privacy_params->private_addr_type = cur_addr.addr_type; } else { p_privacy_params->privacy_mode = BLE_GAP_PRIVACY_MODE_OFF; } // Can not fail. (void) sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, &cur_privacy_opt); p_privacy_params->private_addr_cycle_s = cur_privacy_opt.gap_opt.privacy.interval_s; return NRF_SUCCESS; #else return sd_ble_gap_privacy_get(p_privacy_params); #endif }
/* Create a whitelist for the user using the cached list of peers. * This whitelist is meant to be provided by the application to the Advertising module. */ ret_code_t im_whitelist_get(ble_gap_addr_t * p_addrs, uint32_t * p_addr_cnt, ble_gap_irk_t * p_irks, uint32_t * p_irk_cnt) { // One of the two buffers has to be provided. NRF_PM_DEBUG_CHECK((p_addrs != NULL) || (p_irks != NULL)); NRF_PM_DEBUG_CHECK((p_addr_cnt != NULL) || (p_irk_cnt != NULL)); if (((p_addr_cnt != NULL) && (m_wlisted_peer_cnt > *p_addr_cnt)) || ((p_irk_cnt != NULL) && (m_wlisted_peer_cnt > *p_irk_cnt))) { // The size of the cached list of peers is larger than the provided buffers. return NRF_ERROR_NO_MEM; } // NRF_SUCCESS or // NRF_ERROR_NOT_FOUND, if a peer or its data were not found. // BLE_ERROR_GAP_INVALID_BLE_ADDR, if a peer address can not be used for whitelisting. return peers_id_keys_get(m_wlisted_peers, m_wlisted_peer_cnt, p_addrs, p_addr_cnt, p_irks, p_irk_cnt); }
pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle) { uint8_t conn_index; NRF_PM_DEBUG_CHECK(m_module_initialized); conn_index = get_connection_by_conn_handle(conn_handle); if (conn_index != IM_NO_INVALID_CONN_HANDLES) { return m_connections[conn_index].peer_id; } return PM_PEER_ID_INVALID; }
pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t * p_master_id) { pm_peer_id_t peer_id; pm_peer_data_flash_t peer_data; NRF_PM_DEBUG_CHECK(m_module_initialized); NRF_PM_DEBUG_CHECK(p_master_id != NULL); pds_peer_data_iterate_prepare(); // For each stored peer, check if the master_id matches p_master_id while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data)) { if (im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->own_ltk.master_id) || im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->peer_ltk.master_id)) { // If a matching master ID is found then return the peer ID. return peer_id; } } // If no matching master ID is found return PM_PEER_ID_INVALID. return PM_PEER_ID_INVALID; }
ret_code_t im_peer_free(pm_peer_id_t peer_id) { uint16_t conn_handle; ret_code_t ret; NRF_PM_DEBUG_CHECK(m_module_initialized); conn_handle = im_conn_handle_get(peer_id); ret = pdb_peer_free(peer_id); if ((conn_handle != BLE_CONN_HANDLE_INVALID) && (ret == NRF_SUCCESS)) { peer_id_set(conn_handle, PM_PEER_ID_INVALID); } return ret; }
ret_code_t im_privacy_set(pm_privacy_params_t const * p_privacy_params) { #if (NRF_SD_BLE_API_VERSION == 2) ret_code_t ret; ble_gap_addr_t privacy_addr; ble_gap_irk_t current_irk; ble_opt_t privacy_options; ble_opt_t current_privacy_options; NRF_PM_DEBUG_CHECK(p_privacy_params != NULL); privacy_addr.addr_type = p_privacy_params->private_addr_type; privacy_options.gap_opt.privacy.p_irk = p_privacy_params->p_device_irk; privacy_options.gap_opt.privacy.interval_s = p_privacy_params->private_addr_cycle_s; current_privacy_options.gap_opt.privacy.p_irk = ¤t_irk; // Can not fail. (void) sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, ¤t_privacy_options); (void) sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, &privacy_options); if (p_privacy_params->privacy_mode == BLE_GAP_PRIVACY_MODE_OFF) { ret = address_set_v2(BLE_GAP_ADDR_CYCLE_MODE_NONE, &m_current_id_addr); } else { ret = address_set_v2(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &privacy_addr); } if (ret != NRF_SUCCESS) { // Restore previous settings. (void) sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, ¤t_privacy_options); } // NRF_ERROR_BUSY, // NRF_ERROR_INVALID_STATE, // NRF_ERROR_INVALID_PARAM, if address type is not valid. return ret; #else return sd_ble_gap_privacy_set(p_privacy_params); #endif }
bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id) { NRF_PM_DEBUG_CHECK(m_module_initialized); if (p_master_id->ediv != 0) { return true; } for (uint32_t i = 0; i < BLE_GAP_SEC_RAND_LEN; i++) { if (p_master_id->rand[i] != 0) { return true; } } return false; }
static ret_code_t address_set_v2(uint8_t cycle_mode, ble_gap_addr_t * p_addr) { NRF_PM_DEBUG_CHECK(p_addr != NULL); ret_code_t ret = sd_ble_gap_address_set(cycle_mode, p_addr); switch (ret) { case NRF_SUCCESS: case NRF_ERROR_BUSY: case NRF_ERROR_INVALID_STATE: case NRF_ERROR_INVALID_PARAM: // If cycle_mode is not AUTO or NONE. case BLE_ERROR_GAP_INVALID_BLE_ADDR: // If the GAP address is not valid. return ret; default: return NRF_ERROR_INTERNAL; } }
bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) { NRF_PM_DEBUG_CHECK(m_module_initialized); uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH]; uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH]; uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH]; if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) { return false; } memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH); memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH); ah(p_irk->irk, prand, local_hash); return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0); }
ret_code_t im_id_addr_set(ble_gap_addr_t const * p_addr) { #if (NRF_SD_BLE_API_VERSION == 2) ret_code_t ret; ble_gap_addr_t current_addr; NRF_PM_DEBUG_CHECK(p_addr != NULL); (void) sd_ble_gap_address_get(¤t_addr); ret = address_set_v2(BLE_GAP_ADDR_CYCLE_MODE_NONE, (ble_gap_addr_t *)p_addr); if (ret != NRF_SUCCESS) { return ret; } if ( current_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE || current_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) { // If currently using privacy, it must be re-enabled. // We force AUTO when privacy is enabled. ret = address_set_v2(BLE_GAP_ADDR_CYCLE_MODE_AUTO, ¤t_addr); if (ret != NRF_SUCCESS) { return ret; } } memcpy(&m_current_id_addr, p_addr, sizeof(ble_gap_addr_t)); return NRF_SUCCESS; #else return sd_ble_gap_addr_set(p_addr); #endif }
ret_code_t im_init(void) { NRF_PM_DEBUG_CHECK(!m_module_initialized); internal_state_reset(); m_conn_state_user_flag_id = ble_conn_state_user_flag_acquire(); if (m_conn_state_user_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID) { return NRF_ERROR_INTERNAL; } #if (NRF_SD_BLE_API_VERSION == 2) ret_code_t ret_code = sd_ble_gap_address_get(&m_current_id_addr); if (ret_code != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } #endif m_module_initialized = true; return NRF_SUCCESS; }
pm_peer_id_t pds_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id) { NRF_PM_DEBUG_CHECK(m_module_initialized); return peer_id_get_next_deleted(prev_peer_id); }
uint32_t pds_peer_count_get(void) { NRF_PM_DEBUG_CHECK(m_module_initialized); return peer_id_n_ids(); }
/**@brief Given a list of peers, loads their GAP address and IRK into the provided buffers. */ static ret_code_t peers_id_keys_get(pm_peer_id_t const * p_peers, uint32_t peer_cnt, ble_gap_addr_t * p_gap_addrs, uint32_t * p_addr_cnt, ble_gap_irk_t * p_gap_irks, uint32_t * p_irk_cnt) { ret_code_t ret; pm_peer_data_bonding_t bond_data; pm_peer_data_t peer_data; uint32_t const buf_size = sizeof(bond_data); bool copy_addrs = false; bool copy_irks = false; NRF_PM_DEBUG_CHECK(p_peers != NULL); // One of these two has to be provided. NRF_PM_DEBUG_CHECK((p_gap_addrs != NULL) || (p_gap_irks != NULL)); if ((p_gap_addrs != NULL) && (p_addr_cnt != NULL)) { NRF_PM_DEBUG_CHECK((*p_addr_cnt) >= peer_cnt); copy_addrs = true; *p_addr_cnt = 0; } if ((p_gap_irks != NULL) && (p_irk_cnt != NULL)) { NRF_PM_DEBUG_CHECK((*p_irk_cnt) >= peer_cnt); copy_irks = true; *p_irk_cnt = 0; } memset(&peer_data, 0x00, sizeof(peer_data)); peer_data.p_bonding_data = &bond_data; // Read through flash memory and look for peers ID keys. for (uint32_t i = 0; i < peer_cnt; i++) { memset(&bond_data, 0x00, sizeof(bond_data)); // Read peer data from flash. ret = pds_peer_data_read(p_peers[i], PM_PEER_DATA_ID_BONDING, &peer_data, &buf_size); if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM)) { // Peer data coulnd't be found in flash or peer ID is not valid. return NRF_ERROR_NOT_FOUND; } uint8_t const addr_type = bond_data.peer_id.id_addr_info.addr_type; if ((addr_type != BLE_GAP_ADDR_TYPE_PUBLIC) && (addr_type != BLE_GAP_ADDR_TYPE_RANDOM_STATIC)) { // The address shared by the peer during bonding can't be used for whitelisting. return BLE_ERROR_GAP_INVALID_BLE_ADDR; } // Copy the GAP address. if (copy_addrs) { memcpy(&p_gap_addrs[i], &bond_data.peer_id.id_addr_info, sizeof(ble_gap_addr_t)); (*p_addr_cnt)++; } // Copy the IRK. if (copy_irks) { memcpy(&p_gap_irks[i], bond_data.peer_id.id_info.irk, BLE_GAP_SEC_KEY_LEN); (*p_irk_cnt)++; } } return NRF_SUCCESS; }
void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id) { NRF_PM_DEBUG_CHECK(m_module_initialized); peer_id_set(conn_handle, peer_id); }
void im_ble_evt_handler(ble_evt_t * ble_evt) { ble_gap_evt_t gap_evt; pm_peer_id_t bonded_matching_peer_id; NRF_PM_DEBUG_CHECK(m_module_initialized); if (ble_evt->header.evt_id != BLE_GAP_EVT_CONNECTED) { // Nothing to do. return; } gap_evt = ble_evt->evt.gap_evt; bonded_matching_peer_id = PM_PEER_ID_INVALID; if ( gap_evt.params.connected.peer_addr.addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) { /* Search the database for bonding data matching the one that triggered the event. * Public and static addresses can be matched on address alone, while resolvable * random addresses can be resolved agains known IRKs. Non-resolvable random addresses * are never matching because they are not longterm form of identification. */ pm_peer_id_t peer_id; pm_peer_data_flash_t peer_data; pds_peer_data_iterate_prepare(); switch (gap_evt.params.connected.peer_addr.addr_type) { case BLE_GAP_ADDR_TYPE_PUBLIC: case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: { while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data)) { if (addr_compare(&gap_evt.params.connected.peer_addr, &peer_data.p_bonding_data->peer_id.id_addr_info)) { bonded_matching_peer_id = peer_id; break; } } } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: { while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data)) { if (im_address_resolve(&gap_evt.params.connected.peer_addr, &peer_data.p_bonding_data->peer_id.id_info)) { bonded_matching_peer_id = peer_id; break; } } } break; default: NRF_PM_DEBUG_CHECK(false); break; } } uint8_t new_index = new_connection(gap_evt.conn_handle, &gap_evt.params.connected.peer_addr); UNUSED_VARIABLE(new_index); if (bonded_matching_peer_id != PM_PEER_ID_INVALID) { im_new_peer_id(gap_evt.conn_handle, bonded_matching_peer_id); // Send a bonded peer event im_evt_t im_evt; im_evt.conn_handle = gap_evt.conn_handle; im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED; evt_send(&im_evt); } }