Beispiel #1
0
uint32_t conn_mw_ble_gap_conn_sec_get(uint8_t const * const p_rx_buf,
                                     uint32_t              rx_buf_len,
                                     uint8_t * const       p_tx_buf,
                                     uint32_t * const      p_tx_buf_len)
{
   SER_ASSERT_NOT_NULL(p_rx_buf);
   SER_ASSERT_NOT_NULL(p_tx_buf);
   SER_ASSERT_NOT_NULL(p_tx_buf_len);

   uint32_t err_code = NRF_SUCCESS;
   uint32_t sd_err_code;

   uint16_t conn_handle;

   ble_gap_conn_sec_t   conn_sec;
   ble_gap_conn_sec_t * p_conn_sec = &conn_sec;

   err_code = ble_gap_conn_sec_get_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &p_conn_sec);
   SER_ASSERT(err_code == NRF_SUCCESS, err_code);

   sd_err_code = sd_ble_gap_conn_sec_get(conn_handle, p_conn_sec);

   err_code = ble_gap_conn_sec_get_rsp_enc(sd_err_code, p_conn_sec, p_tx_buf, p_tx_buf_len);
   SER_ASSERT(err_code == NRF_SUCCESS, err_code);

   return err_code;
}
ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
{
    ble_error_t returnValue = BLE_ERROR_NONE;

    ble_gatts_value_t value = {
        /* .len     = */ len,
        /* .offset  = */ 0,
        /* .p_value = */ const_cast<uint8_t *>(buffer),
    };

    if (localOnly) {
        /* Only update locally regardless of notify/indicate */
        ASSERT_INT( ERROR_NONE,
                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                    BLE_ERROR_PARAM_OUT_OF_RANGE );
        return BLE_ERROR_NONE;
    }

    int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
    if ((characteristicIndex != -1) &&
        (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
        /* HVX update for the characteristic value */
        ble_gatts_hvx_params_t hvx_params;

        hvx_params.handle = attributeHandle;
        hvx_params.type   =
            (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
        hvx_params.offset = 0;
        hvx_params.p_data = const_cast<uint8_t *>(buffer);
        hvx_params.p_len  = &len;

        if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
            nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
            connectionHandle = gap.getConnectionHandle();
        }

        bool updatesEnabled = false;
        if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
            ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);

            // FIXME: The softdevice allocates and populates CCCD when the client
            // interract with them. Checking for updates may return an out of
            // range error in such case.
            if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
                return err;
            }
        }

        bool updates_permitted = false;
        ble_gap_conn_sec_t connection_security;
        uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security);
        if (!err &&
            (connection_security.sec_mode.sm == 1) &&
            (connection_security.sec_mode.lv >=  p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) {
            updates_permitted = true;
        }

        if (updatesEnabled && updates_permitted) {
            error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
            if (error != ERROR_NONE) {
                switch (error) {
                    case ERROR_BLE_NO_TX_BUFFERS: /*  Notifications consume application buffers. The return value can be used for resending notifications. */
                    case ERROR_BUSY:
                        returnValue = BLE_STACK_BUSY;
                        break;

                    case ERROR_INVALID_STATE:
                    case ERROR_BLEGATTS_SYS_ATTR_MISSING:
                        returnValue = BLE_ERROR_INVALID_STATE;
                        break;

                    default :
                        ASSERT_INT( ERROR_NONE,
                                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                                    BLE_ERROR_PARAM_OUT_OF_RANGE );

                        /* Notifications consume application buffers. The return value can
                        * be used for resending notifications. */
                        returnValue = BLE_STACK_BUSY;
                        break;
                }
            }
        } else {
            returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
        }
    } else {
        returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
    }

    return returnValue;
}
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);
}