/** * @brief Perform a binary search for an address in a list of addresses. * * @param[in] p_addr Pointer to an address that is searched for. * @param[in] p_addr_array Pointer to a list of addresses to be searched. * @param[out] p_location If the address @p p_addr appears in the list, this is its index in the address list. * Otherwise, it is the index which @p p_addr would have if it was placed in the list * (ascending order assumed). * @param[in] extended Indication if @p p_addr is an extended or a short addresses. * * @retval true Address @p p_addr is in the list. * @retval false Address @p p_addr is not in the list. */ static bool addr_binary_search(const uint8_t * p_addr, const uint8_t * p_addr_array, uint8_t * p_location, bool extended) { uint8_t addr_array_len = extended ? m_num_of_pending_extended : m_num_of_pending_short; uint8_t entry_size = extended ? EXTENDED_ADDRESS_SIZE : SHORT_ADDRESS_SIZE; int8_t low = 0; int8_t midpoint = 0; int8_t high = addr_array_len; while (high >= low) { midpoint = low + (high - low) / 2; if (midpoint >= addr_array_len) { break; } switch (addr_compare(p_addr, p_addr_array + entry_size * midpoint, extended)) { case -1: high = midpoint - 1; break; case 0: *p_location = midpoint; return true; case 1: low = midpoint + 1; break; default: break; } } /* If in the last iteration of the loop the last case was utilized, it means that the midpoint * found by the algorithm is less than the address to be added. The midpoint should be therefore * shifted to the next position. As a simplified example, a { 1, 3, 4 } array can be considered. * Suppose that a number equal to 2 is about to be added to the array. At the beginning of the * last iteration, midpoint is equal to 1 and low and high are equal to 0. Midpoint is then set * to 0 and with last case being utilized, low is set to 1. However, midpoint equal to 0 is * incorrect, as in the last iteration first element of the array proves to be less than the * element to be added to the array. With the below code, midpoint is then shifted to 1. */ if (low == midpoint + 1) { midpoint++; } *p_location = midpoint; return false; }
/**@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 is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1, pm_peer_data_bonding_t const * p_bonding_data2) { bool valid_irk = is_valid_irk(&p_bonding_data1->peer_id.id_info); bool duplicate_irk = valid_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; }
/**@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; }
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); } }
void im_ble_evt_handler(ble_evt_t * ble_evt) { ret_code_t err_code; switch (ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: { pm_peer_id_t bonded_matching_peer_id = PM_PEER_ID_INVALID; if (ble_evt->evt.gap_evt.params.connected.irk_match == 1) { // The peer was matched using a whitelist. bonded_matching_peer_id = m_im.irk_whitelist_peer_ids[ble_evt->evt.gap_evt.params.connected.irk_match_idx]; } else if ( ble_evt->evt.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 compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID); while ( (compared_peer_id != PM_PEER_ID_INVALID) && (bonded_matching_peer_id == PM_PEER_ID_INVALID)) { pm_peer_data_flash_t compared_data; switch (ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type) { case BLE_GAP_ADDR_TYPE_PUBLIC: /* fall-through */ case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL); if ((err_code == NRF_SUCCESS) && addr_compare(&ble_evt->evt.gap_evt.params.connected.peer_addr, &compared_data.p_bonding_data->peer_id.id_addr_info) ) { bonded_matching_peer_id = compared_peer_id; } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL); if (err_code == NRF_SUCCESS && im_address_resolve(&ble_evt->evt.gap_evt.params.connected.peer_addr, &compared_data.p_bonding_data->peer_id.id_info) ) { bonded_matching_peer_id = compared_peer_id; } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE: // Should not happen. break; default: break; } compared_peer_id = pdb_next_peer_id_get(compared_peer_id); } } uint8_t new_index = new_connection(ble_evt->evt.gap_evt.conn_handle, &ble_evt->evt.gap_evt.params.connected.peer_addr); UNUSED_VARIABLE(new_index); if (bonded_matching_peer_id != PM_PEER_ID_INVALID) { im_new_peer_id(ble_evt->evt.gap_evt.conn_handle, bonded_matching_peer_id); // Send a bonded peer event im_evt_t im_evt; im_evt.conn_handle = ble_evt->evt.gap_evt.conn_handle; im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED; evt_send(&im_evt); } } } }