Пример #1
0
bool
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
    /*
     * Use a helper function from the Nordic SDK to test whether the BLE
     * address can be generated using the IRK.
     */
    return im_address_resolve(p_addr, p_irk);
}
Пример #2
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);
    }
}
Пример #3
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);
        }
    }
    }
}
Пример #4
0
void pm_handler(pm_evt_t const *p_event)
{
    nRF5xn               &ble             = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
    nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
    ret_code_t            err_code;
    SecurityManager::SecurityMode_t resolvedSecurityMode;

    switch (p_event->evt_id) {
        case PM_EVT_CONN_SEC_START: /* started */ {
            const ble_gap_sec_params_t *peerParams = &securityParameters;
            securityManager.processSecuritySetupInitiatedEvent(p_event->conn_handle,
                                                                                   peerParams->bond,
                                                                                   peerParams->mitm,
                                                                                   (SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps);
            _enc_in_progress = true;
            break;
        }
        case PM_EVT_CONN_SEC_SUCCEEDED:
            // Update the rank of the peer.
            if (p_event->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING)
            {
                err_code = pm_peer_rank_highest(p_event->peer_id);
            }
        
            securityManager.
                processSecuritySetupCompletedEvent(p_event->conn_handle,
                                                    SecurityManager::SEC_STATUS_SUCCESS);// SEC_STATUS_SUCCESS of SecurityCompletionStatus_t
                                                    
            ble_gap_conn_sec_t conn_sec;
            sd_ble_gap_conn_sec_get(p_event->conn_handle, &conn_sec);
            
            resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS;
            
            switch (conn_sec.sec_mode.sm) {
                case 1:
                    switch (conn_sec.sec_mode.lv) {
                        case 1:
                            resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
                            break;
                        case 2:
                            resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
                            break;
                        case 3:
                            resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
                            break;
                    }
                    break;
                case 2:
                    switch (conn_sec.sec_mode.lv) {
                        case 1:
                            resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM;
                            break;
                        case 2:
                            resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM;
                            break;
                    }
                    break;
            }

            securityManager.processLinkSecuredEvent(p_event->conn_handle, resolvedSecurityMode);

            _enc_in_progress = false;
            break;
            
        case PM_EVT_CONN_SEC_FAILED:
            SecurityManager::SecurityCompletionStatus_t securityCompletionStatus;
            
            if ((uint32_t)p_event->params.conn_sec_failed.error >= PM_CONN_SEC_ERROR_BASE ) {
                securityCompletionStatus = SecurityManager::SEC_STATUS_UNSPECIFIED;
            } else {
                 securityCompletionStatus = 
                    (SecurityManager::SecurityCompletionStatus_t)p_event->params.conn_sec_failed.error;
            }
                
            securityManager.
                processSecuritySetupCompletedEvent(p_event->conn_handle, securityCompletionStatus);

            _enc_in_progress = false;
            break;
            
        case PM_EVT_BONDED_PEER_CONNECTED:
            pm_peer_rank_highest(p_event->peer_id);
            break;
        
        case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            if (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
            {
                securityManager.processSecurityContextStoredEvent(p_event->conn_handle);
            }
            break;
            
        case PM_EVT_PEER_DATA_UPDATE_FAILED:
            break;
            
        case PM_EVT_PEERS_DELETE_SUCCEEDED:
            async_ret_code = NRF_SUCCESS;        // respond SUCCESS to the busy-loop in f. btle_purgeAllBondingState
            break;
        
        case PM_EVT_PEERS_DELETE_FAILED:
            async_ret_code = NRF_ERROR_INTERNAL; // respond FAILURE to the busy-loop in f. btle_purgeAllBondingState
            break;

        case PM_EVT_STORAGE_FULL:
            // Run garbage collection on the flash.
            err_code = fds_gc();
            if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
            {
                // Retry.
            }
            else
            {
                APP_ERROR_CHECK(err_code);
            }
            break;//PM_EVT_STORAGE_FULL
            
        case PM_EVT_CONN_SEC_CONFIG_REQ:{
            // A connected peer (central) is trying to pair, but the Peer Manager already has a bond
            // for that peer. Setting allow_repairing to false rejects the pairing request.
            // If this event is ignored (pm_conn_sec_config_reply is not called in the event
            // handler), the Peer Manager assumes allow_repairing to be false.
            pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
            pm_conn_sec_config_reply(p_event->conn_handle, &conn_sec_config);
            }
            break;//PM_EVT_CONN_SEC_CONFIG_REQ
            
        default:
            break;
    }
}

#if  (NRF_SD_BLE_API_VERSION <= 2)
ble_error_t
btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist)
{
    if (!btle_hasInitializedSecurity()) {
        return BLE_ERROR_INITIALIZATION_INCOMPLETE;
    }
    ret_code_t err = pm_whitelist_create( NULL, BLE_GAP_WHITELIST_ADDR_MAX_COUNT, p_whitelist);
    if (err == NRF_SUCCESS) {
        return BLE_ERROR_NONE;
    } else if (err == NRF_ERROR_NULL) {
        return BLE_ERROR_PARAM_OUT_OF_RANGE;
    } else {
        return BLE_ERROR_INVALID_STATE;
    }
}
#endif

bool
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
    /*
     * Use a helper function from the Nordic SDK to test whether the BLE
     * address can be generated using the IRK.
     */
    return im_address_resolve(p_addr, p_irk);
}

void
btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address)
{
    /* Set type to resolvable */
    address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;

    /*
     * Assign a random number to the most significant 3 bytes
     * of the address.
     */
    address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E;
    address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F;
    address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C;

    /* Calculate the hash and store it in the top half of the address */
    ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr);
}