/**
 * @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;
}
예제 #2
0
/**@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;
}
예제 #3
0
/**@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;
}
예제 #4
0
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);
    }
}
예제 #5
0
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);
        }
    }
    }
}