diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp deleted file mode 100644 index f4b0d393b2..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp +++ /dev/null @@ -1,1427 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "nRF5xn.h" -#ifdef YOTTA_CFG_MBED_OS - #include "mbed-drivers/mbed.h" -#else - #include "mbed.h" -#endif -#include "ble/BLE.h" - -#include "common/common.h" -#include "ble_advdata.h" -#include "headers/nrf_ble_hci.h" -#include "ble/pal/ConnectionEventMonitor.h" -#include "nRF5xPalSecurityManager.h" - -using ble::pal::vendor::nordic::nRF5xSecurityManager; -typedef nRF5xSecurityManager::resolving_list_entry_t resolving_list_entry_t; -using ble::ArrayView; -using ble::pal::advertising_peer_address_type_t; -using ble::peer_address_type_t; - -typedef BLEProtocol::AddressType LegacyAddressType; -typedef BLEProtocol::AddressType_t LegacyAddressType_t; - -namespace { - -nRF5xSecurityManager& get_sm() { - return nRF5xSecurityManager::get_security_manager(); -} - -ble_error_t set_private_resolvable_address() { - ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE }; - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); - return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; -} - -ble_error_t set_private_non_resolvable_address() { - ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE }; - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); - return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; -} - -bool is_advertising_non_connectable(const GapAdvertisingParams ¶ms) { - switch (params.getAdvertisingType()) { - case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED: - case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED: - return true; - default: - return false; - } -} - -bool is_identity_address(peer_address_type_t address_type) { - return address_type == peer_address_type_t::PUBLIC_IDENTITY || - address_type == peer_address_type_t::RANDOM_STATIC_IDENTITY; -} - -peer_address_type_t convert_nordic_address(uint8_t address) { - if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { - return peer_address_type_t::PUBLIC; - } else { - return peer_address_type_t::RANDOM; - } -} - -peer_address_type_t convert_identity_address(advertising_peer_address_type_t address) { - if (address == advertising_peer_address_type_t::PUBLIC) { - return peer_address_type_t::PUBLIC_IDENTITY; - } else { - return peer_address_type_t::RANDOM_STATIC_IDENTITY; - } -} - -} // namespace - -void radioNotificationStaticCallback(bool param) { - nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); - gap.processRadioNotificationEvent(param); -} - -nRF5xGap::nRF5xGap() : Gap(), - advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), - scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), - whitelistAddressesSize(0), - whitelistAddresses(), - radioNotificationCallbackParam(false), - radioNotificationTimeout(), - _connection_event_handler(NULL), - _privacy_enabled(false), - _peripheral_privacy_configuration(default_peripheral_privacy_configuration), - _central_privacy_configuration(default_central_privacy_configuration), - _non_private_address_type(LegacyAddressType::RANDOM_STATIC), - _connections_role() -{ - m_connectionHandle = BLE_CONN_HANDLE_INVALID; -} - -/**************************************************************************/ -/*! - @brief Sets the advertising parameters and payload for the device - - @param[in] params - Basic advertising details, including the advertising - delay, timeout and how the device should be advertised - @params[in] advData - The primary advertising data payload - @params[in] scanResponse - The optional Scan Response payload if the advertising - type is set to \ref GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED - in \ref GapAdveritinngParams - - @returns \ref ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @retval BLE_ERROR_BUFFER_OVERFLOW - The proposed action would cause a buffer overflow. All - advertising payloads must be <= 31 bytes, for example. - - @retval BLE_ERROR_NOT_IMPLEMENTED - A feature was requested that is not yet supported in the - nRF51 firmware or hardware. - - @retval BLE_ERROR_PARAM_OUT_OF_RANGE - One of the proposed values is outside the valid range. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) -{ - /* Make sure we don't exceed the advertising payload length */ - if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { - return BLE_ERROR_BUFFER_OVERFLOW; - } - - /* Make sure we have a payload! */ - if (advData.getPayloadLen() == 0) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Check the scan response payload limits */ - //if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED)) - //{ - // /* Check if we're within the upper limit */ - // if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) - // { - // return BLE_ERROR_BUFFER_OVERFLOW; - // } - // /* Make sure we have a payload! */ - // if (advData.getPayloadLen() == 0) - // { - // return BLE_ERROR_PARAM_OUT_OF_RANGE; - // } - //} - - /* Send advertising data! */ - ASSERT_TRUE(ERROR_NONE == - sd_ble_gap_adv_data_set(advData.getPayload(), - advData.getPayloadLen(), - scanResponse.getPayload(), - scanResponse.getPayloadLen()), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - /* Make sure the GAP Service appearance value is aligned with the - *appearance from GapAdvertisingData */ - ASSERT_TRUE(ERROR_NONE == sd_ble_gap_appearance_set(advData.getAppearance()), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - /* ToDo: Perform some checks on the payload, for example the Scan Response can't */ - /* contains a flags AD type, etc. */ - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Starts the BLE HW, initialising any services that were - added before this function was called. - - @note All services must be added before calling this function! - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) -{ - uint32_t err; - ble_gap_adv_params_t adv_para = {0}; - - /* Make sure we support the advertising type */ - if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) { - /* ToDo: This requires a propery security implementation, etc. */ - return BLE_ERROR_NOT_IMPLEMENTED; - } - - /* Check interval range */ - if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) { - /* Min delay is slightly longer for unconnectable devices */ - if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) || - (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } else { - if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) || - (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } - - /* Check timeout is zero for Connectable Directed */ - if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) { - /* Timeout must be 0 with this type, although we'll never get here */ - /* since this isn't implemented yet anyway */ - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Check timeout for other advertising types */ - if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && - (params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - whitelist.addr_count = whitelistAddressesSize; - - for (uint32_t i = 0; i < whitelistAddressesSize; ++i) { - whitelistAddressPtrs[i] = &whitelistAddresses[i]; - } - - if (_privacy_enabled) { - if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) { - ArrayView entries = get_sm().get_resolving_list(); - - size_t limit = std::min( - entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE - ); - - for (size_t i = 0; i < limit; ++i) { - whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); - } - whitelist.irk_count = limit; - } - - if (_peripheral_privacy_configuration.use_non_resolvable_random_address && - is_advertising_non_connectable(params) - ) { - set_private_non_resolvable_address(); - } else { - set_private_resolvable_address(); - } - } - - adv_para.p_whitelist = &whitelist; -#endif - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - /* Start Advertising */ - adv_para.type = params.getAdvertisingType(); - adv_para.p_peer_addr = NULL; // Undirected advertisement - adv_para.fp = advertisingPolicyMode; - adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms) - adv_para.timeout = params.getTimeout(); - - err = sd_ble_gap_adv_start(&adv_para); - switch(err) { - case ERROR_NONE: - return BLE_ERROR_NONE; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - default: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ -#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) -ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams) -{ - ble_gap_scan_params_t scanParams; - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - whitelist.addr_count = whitelistAddressesSize; - - for (uint32_t i = 0; i < whitelistAddressesSize; ++i) { - whitelistAddressPtrs[i] = &whitelistAddresses[i]; - } - - if (_privacy_enabled) { - if (_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE) { - ArrayView entries = get_sm().get_resolving_list(); - - size_t limit = std::min( - entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE - ); - - for (size_t i = 0; i < limit; ++i) { - whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); - } - whitelist.irk_count = limit; - } - } - - scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ - scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ -#else - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - scanParams.use_whitelist = scanningPolicyMode; - scanParams.adv_dir_report = 0; -#endif - - scanParams.active = scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - - scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - - if (_privacy_enabled) { - if (_central_privacy_configuration.use_non_resolvable_random_address) { - set_private_non_resolvable_address(); - } else { - set_private_resolvable_address(); - } - } - - if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::stopScan(void) { - if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - - return BLE_STACK_BUSY; -} -#endif - -/**************************************************************************/ -/*! - @brief Stops the BLE HW and disconnects from any devices - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::stopAdvertising(void) -{ - /* Stop Advertising */ - ASSERT_TRUE(ERROR_NONE == sd_ble_gap_adv_stop(), BLE_ERROR_PARAM_OUT_OF_RANGE); - - state.advertising = 0; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - peer_address_type_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn -) { - // NOTE: Nordic address type is an closer to LegacyAddressType: resolved - // address are treaded either as PUBLIC or RANDOM STATIC adresses. - // The idea is to get the conversion done here and call the legacy function. - - LegacyAddressType_t legacy_address; - - switch (peerAddrType.value()) { - case peer_address_type_t::PUBLIC: - case peer_address_type_t::PUBLIC_IDENTITY: - legacy_address = LegacyAddressType::PUBLIC; - break; - case peer_address_type_t::RANDOM_STATIC_IDENTITY: - legacy_address = LegacyAddressType::RANDOM_STATIC; - break; - case peer_address_type_t::RANDOM: { - RandomAddressType_t random_address_type(RandomAddressType_t::STATIC); - ble_error_t err = getRandomAddressType(peerAddr, &random_address_type); - if (err) { - return err; - } - switch (random_address_type.value()) { - case RandomAddressType_t::STATIC: - legacy_address = LegacyAddressType::RANDOM_STATIC; - break; - case RandomAddressType_t::NON_RESOLVABLE_PRIVATE: - legacy_address = LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE; - break; - case RandomAddressType_t::RESOLVABLE_PRIVATE: - legacy_address = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; - break; - default: - return BLE_ERROR_UNSPECIFIED; - } - } break; - default: - return BLE_ERROR_INVALID_PARAM; - } - - bool identity = - peerAddrType == peer_address_type_t::PUBLIC_IDENTITY || - peerAddrType == peer_address_type_t::RANDOM_STATIC_IDENTITY; - - return connect(peerAddr, legacy_address, connectionParams, scanParamsIn, identity); -} - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - LegacyAddressType_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn -) { - return connect(peerAddr, peerAddrType, connectionParams, scanParamsIn, /* identity */ false); -} - - - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - LegacyAddressType_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn, - bool identity -) { - ble_gap_addr_t addr; - ble_gap_addr_t* addr_ptr = &addr; - addr.addr_type = peerAddrType; - memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); - - ble_gap_conn_params_t connParams; - if (connectionParams != NULL) { - connParams.min_conn_interval = connectionParams->minConnectionInterval; - connParams.max_conn_interval = connectionParams->maxConnectionInterval; - connParams.slave_latency = connectionParams->slaveLatency; - connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; - } else { - connParams.min_conn_interval = 50; - connParams.max_conn_interval = 100; - connParams.slave_latency = 0; - connParams.conn_sup_timeout = 600; - } - - ble_gap_scan_params_t scanParams = { 0 }; - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ - scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ - - if (_privacy_enabled) { - if (_central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE) { - ArrayView entries = get_sm().get_resolving_list(); - - size_t limit = std::min( - entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE - ); - - for (size_t i = 0; i < limit; ++i) { - whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); - } - whitelist.irk_count = limit; - - if (identity) { - scanParams.selective = true; - addr_ptr = NULL; - } - } - - set_private_resolvable_address(); - } -#else - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - scanParams.use_whitelist = (whitelistAddressesSize) ? 1 : 0; - - if ((addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) - || (addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)) { - /* If a device is using Resolvable Private Addresses Section 1.3.2.2 (Core spec v4.2 volume 6 part B), - it shall also have an Identity Address that is either a Public or Random Static address type. - To establish a connection, a static address must be provided by the application to the SoftDevice. - The SoftDevice resolves the address and connects to the right device if it is available. */ - addr.addr_id_peer = 1; - addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; - } else { - addr.addr_id_peer = 0; - } - -#endif - - if (scanParamsIn != NULL) { - scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - } else { - scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - } - - uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams); - if (rc == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - switch (rc) { - case NRF_ERROR_INVALID_ADDR: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_PARAM: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - case BLE_ERROR_GAP_INVALID_BLE_ADDR: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - case BLE_ERROR_GAP_WHITELIST_IN_USE: - return BLE_ERROR_UNSPECIFIED; - } -} - -ble_error_t nRF5xGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) -{ - uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; - switch (reason) { - case REMOTE_USER_TERMINATED_CONNECTION: - code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; - break; - case CONN_INTERVAL_UNACCEPTABLE: - code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE; - break; - default: - break; - } - - /* Disconnect if we are connected to a central device */ - ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -/*! - @brief Disconnects if we are connected to a central device - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly -*/ -ble_error_t nRF5xGap::disconnect(DisconnectionReason_t reason) -{ - return disconnect(m_connectionHandle, reason); -} - -ble_error_t nRF5xGap::getPreferredConnectionParams(ConnectionParams_t *params) -{ - ASSERT_INT(NRF_SUCCESS, - sd_ble_gap_ppcp_get(reinterpret_cast(params)), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setPreferredConnectionParams(const ConnectionParams_t *params) -{ - ASSERT_INT(NRF_SUCCESS, - sd_ble_gap_ppcp_set(reinterpret_cast(params)), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams) -{ - uint32_t rc; - - rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast(const_cast(newParams))); - if (rc == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/**************************************************************************/ -/*! - @brief Clear nRF5xGap's state. - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::reset(void) -{ - /* Clear all state that is from the parent, including private members */ - if (Gap::reset() != BLE_ERROR_NONE) { - return BLE_ERROR_INVALID_STATE; - } - - /* Clear derived class members */ - m_connectionHandle = BLE_CONN_HANDLE_INVALID; - - /* Set the whitelist policy filter modes to IGNORE_WHITELIST */ - advertisingPolicyMode = Gap::ADV_POLICY_IGNORE_WHITELIST; - scanningPolicyMode = Gap::SCAN_POLICY_IGNORE_WHITELIST; - - /* Clear the internal whitelist */ - whitelistAddressesSize = 0; - - /* Reset existing mapping between a connection and its role */ - release_all_connections_role(); - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Sets the 16-bit connection handle -*/ -/**************************************************************************/ -void nRF5xGap::setConnectionHandle(uint16_t con_handle) -{ - m_connectionHandle = con_handle; -} - -/**************************************************************************/ -/*! - @brief Gets the 16-bit connection handle -*/ -/**************************************************************************/ -uint16_t nRF5xGap::getConnectionHandle(void) -{ - return m_connectionHandle; -} - -/**************************************************************************/ -/*! - @brief Sets the BLE device address - - @returns ble_error_t - - @section EXAMPLE - - @code - - uint8_t device_address[6] = { 0xca, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0 }; - nrf.getGap().setAddress(Gap::BLEProtocol::AddressType::RANDOM_STATIC, device_address); - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAddress(LegacyAddressType_t type, const Address_t address) -{ - if (type != LegacyAddressType::PUBLIC && - type != LegacyAddressType::RANDOM_STATIC - ) { - return BLE_ERROR_INVALID_PARAM; - } - - if (_privacy_enabled) { - return BLE_ERROR_INVALID_STATE; - } - - ble_gap_addr_t dev_addr; - memcpy(dev_addr.addr, address, ADDR_LEN); - if (type == LegacyAddressType::PUBLIC) { - dev_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; - } else { - dev_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; - } - -#if (NRF_SD_BLE_API_VERSION <= 2) - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr); -#else - uint32_t err = sd_ble_gap_addr_set(&dev_addr); -#endif - - switch (err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - case NRF_ERROR_INVALID_ADDR: - return BLE_ERROR_INVALID_PARAM; - case BLE_ERROR_GAP_INVALID_BLE_ADDR: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - default: - return BLE_ERROR_UNSPECIFIED; - } -} - -ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address) -{ - if (typeP == NULL || address == NULL) { - return BLE_ERROR_INVALID_PARAM; - } - - ble_gap_addr_t dev_addr; -#if (NRF_SD_BLE_API_VERSION <= 2) - if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) { -#else - if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) { -#endif - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - switch (dev_addr.addr_type) { - case BLE_GAP_ADDR_TYPE_PUBLIC: - *typeP = LegacyAddressType::PUBLIC; - break; - - case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: - *typeP = LegacyAddressType::RANDOM_STATIC; - break; - - default: - return BLE_ERROR_INVALID_STATE; - } - - memcpy(address, dev_addr.addr, ADDR_LEN); - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setDeviceName(const uint8_t *deviceName) -{ - ble_gap_conn_sec_mode_t sec_mode; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed - - if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP) -{ - if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::setAppearance(GapAdvertisingData::Appearance appearance) -{ - if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::getAppearance(GapAdvertisingData::Appearance *appearanceP) -{ - if ((sd_ble_gap_appearance_get(reinterpret_cast(appearanceP)) == NRF_SUCCESS)) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ -ble_error_t nRF5xGap::setTxPower(int8_t txPower) -{ - unsigned rc; - if ((rc = sd_ble_gap_tx_power_set(txPower)) != NRF_SUCCESS) { - switch (rc) { - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_INVALID_PARAM: - default: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } - - return BLE_ERROR_NONE; -} - -void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) -{ -#if defined(NRF51) - static const int8_t permittedTxValues[] = { - -30, -20, -16, -12, -8, -4, 0, 4 - }; -#elif defined(NRF52) - static const int8_t permittedTxValues[] = { - -40, -20, -16, -12, -8, -4, 0, 4 - }; -#elif defined(NRF52840_XXAA) - static const int8_t permittedTxValues[] = { - -40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8, 9 - }; -#else -#error permitted TX power values unknown for this SOC -#endif - - *valueArrayPP = permittedTxValues; - *countP = sizeof(permittedTxValues) / sizeof(int8_t); -} - -/**************************************************************************/ -/*! - @brief Get the capacity of the internal whitelist maintained by this - implementation. - - @returns The capacity of the internal whitelist. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -uint8_t nRF5xGap::getMaxWhitelistSize(void) const -{ - return YOTTA_CFG_WHITELIST_MAX_SIZE; -} - -/**************************************************************************/ -/*! - @brief Get a copy of the implementation's internal whitelist. - - @param[out] whitelistOut - A \ref Gap::Whitelist_t structure containing a copy of the - addresses in the implemenetation's internal whitelist. - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const -{ - uint32_t i; - for (i = 0; i < whitelistAddressesSize && i < whitelistOut.capacity; ++i) { - memcpy( &whitelistOut.addresses[i].address, &whitelistAddresses[i].addr, sizeof(whitelistOut.addresses[0].address)); - whitelistOut.addresses[i].type = static_cast (whitelistAddresses[i].addr_type); - } - whitelistOut.size = i; - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the whitelist that will be used in the next call to - startAdvertising(). - - @param[in] whitelistIn - A reference to a \ref Gap::Whitelist_t structure - representing a whitelist containing all the white listed - BLE addresses. - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_INVALID_PARAM - The supplied whitelist contains a private non-resolvable - address - - BLE_ERROR_PARAM_OUT_OF_RANGE - The size of the supplied whitelist exceeds the maximum - capacity of the implementation's internal whitelist. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) -{ - if (whitelistIn.size > getMaxWhitelistSize()) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Test for invalid parameters before we change the internal state */ - for (uint32_t i = 0; i < whitelistIn.size; ++i) { - if (whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE || - whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE - ) { - /* This is not allowed because it is completely meaningless */ - return BLE_ERROR_INVALID_PARAM; - } - } - - whitelistAddressesSize = whitelistIn.size; - - for (uint32_t i = 0; i < whitelistIn.size; ++i) { - memcpy(&whitelistAddresses[i].addr , &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr)); - whitelistAddresses[i].addr_type = static_cast (whitelistIn.addresses[i].type); - } - -#if (NRF_SD_BLE_API_VERSION >= 3) - updateWhiteAndIdentityListInStack(); -#endif - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the advertising policy filter mode that will be used in - the next call to startAdvertising(). - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) -{ - advertisingPolicyMode = mode; - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the scanning policy filter mode that will be used in - the next call to startAdvertising(). - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) -{ - scanningPolicyMode = mode; - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the initiator policy filter mode that will be used in - the next call to startAdvertising() - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) -{ - return BLE_ERROR_NOT_IMPLEMENTED; -} - -/**************************************************************************/ -/*! - @brief Get the current advertising policy filter mode. - - @returns The advertising policy filter mode. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const -{ - return advertisingPolicyMode; -} - -/**************************************************************************/ -/*! - @brief Get the current scanning policy filter mode. - - @returns The scanning policy filter mode. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const -{ - return scanningPolicyMode; -} - -/**************************************************************************/ -/*! - @brief Get the current initiator policy filter mode. - - @returns The initiator policy filter mode. - - @note Currently initiator filtering using the whitelist is not - implemented in this module. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const -{ - return Gap::INIT_POLICY_IGNORE_WHITELIST; -} - -ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy) -{ - if (enable_privacy == _privacy_enabled) { - return BLE_ERROR_NONE; - } - - ble_error_t err = BLE_ERROR_UNSPECIFIED; - if (enable_privacy == false) { - err = setAddress(_non_private_address_type, _non_private_address); - } else { - err = getAddress(&_non_private_address_type, _non_private_address); - } - - if (err) { - return err; - } - -#if (NRF_SD_BLE_API_VERSION > 2) - ble_gap_privacy_params_t privacy_config = { 0 }; - if (sd_ble_gap_privacy_get(&privacy_config)) { - return BLE_ERROR_UNSPECIFIED; - } - - privacy_config.privacy_mode = enable_privacy ? - BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY : - BLE_GAP_PRIVACY_MODE_OFF; - if (sd_ble_gap_privacy_set(&privacy_config)) { - return BLE_ERROR_UNSPECIFIED; - } -#endif - - _privacy_enabled = enable_privacy; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setPeripheralPrivacyConfiguration( - const PeripheralPrivacyConfiguration_t *configuration -) { - _peripheral_privacy_configuration = *configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::getPeripheralPrivacyConfiguration( - PeripheralPrivacyConfiguration_t *configuration -) { - *configuration = _peripheral_privacy_configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setCentralPrivacyConfiguration( - const CentralPrivacyConfiguration_t *configuration -) { - _central_privacy_configuration = *configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::getCentralPrivacyConfiguration( - CentralPrivacyConfiguration_t *configuration -) { - *configuration = _central_privacy_configuration; - return BLE_ERROR_NONE; -} - -void nRF5xGap::set_connection_event_handler( - ConnectionEventMonitor::EventHandler* connection_event_handler -) { - _connection_event_handler = connection_event_handler; -} - -void nRF5xGap::processDisconnectionEvent( - Handle_t handle, - DisconnectionReason_t reason -) { - release_connection_role(handle); - - if (_connection_event_handler) { - _connection_event_handler->on_disconnected( - handle, - reason - ); - } - - ::Gap::processDisconnectionEvent( - handle, - reason - ); -} - -void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t& evt) { - using BLEProtocol::AddressType; - - // set the new connection handle as the _default_ handle in gap - setConnectionHandle(handle); - - // add the connection and the role of the device in the local table - allocate_connection_role(handle, static_cast(evt.role)); - - // deal with own address - LegacyAddressType_t own_addr_type; - Address_t own_address; - const uint8_t* own_resolvable_address = NULL; - -#if (NRF_SD_BLE_API_VERSION <= 2) - if (_privacy_enabled) { - own_addr_type = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; - } else { - if (evt.own_addr.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) { - own_addr_type = LegacyAddressType::PUBLIC; - } else { - own_addr_type = LegacyAddressType::RANDOM_STATIC; - } - } - - // FIXME: is it the resolvable address or the identity address ? - memcpy(own_address, evt.own_addr.addr, sizeof(own_address)); -#else - gap.getAddress(&addr_type, own_address); -#endif - - // deal with the peer address: If privacy is enabled then the softdevice - // indicates if the address has been resolved or not. If the address has - // been resolved then the identity address should be passed to the application. - // Depending on the privacy chosen by the application, connection request - // from privacy enabled peers may trigger a disconnection, the pairing procedure - // or the authentication procedure. - peer_address_type_t peer_addr_type(peer_address_type_t::PUBLIC); - const uint8_t* peer_address; - const uint8_t* peer_resolvable_address; - -#if (NRF_SD_BLE_API_VERSION <= 2) - bool private_peer_known = evt.irk_match; - - // thanks to softdevice consistencies; addresses are not resolved on the - // peripheral side ... - if (_privacy_enabled && - evt.role == BLE_GAP_ROLE_PERIPH && - _peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE && - get_sm().resolve_address(evt.peer_addr.addr) != NULL - ) { - private_peer_known = true; - } -#else - bool private_peer_known = evt.peer_addr.addr_id_peer; -#endif - - if (private_peer_known) { - const resolving_list_entry_t* entry = get_sm().resolve_address( - evt.peer_addr.addr - ); - MBED_ASSERT(entry != NULL); - - peer_addr_type = convert_identity_address(entry->peer_identity_address_type); - peer_address = entry->peer_identity_address.data(); - peer_resolvable_address = evt.peer_addr.addr; - } else { - if (_privacy_enabled && - evt.role == BLE_GAP_ROLE_PERIPH && - _peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && - get_sm().get_resolving_list().size() > 0 - ) { - // FIXME: should use BLE_HCI_AUTHENTICATION_FAILURE; not possible - // with the softdevice ... - sd_ble_gap_disconnect(handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); - return; - } - - peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); - peer_address = evt.peer_addr.addr; - peer_resolvable_address = NULL; - } - - // notify internal event handler before applying the resolution strategy - if (_connection_event_handler) { - _connection_event_handler->on_connected( - handle, - static_cast(evt.role), - peer_addr_type, - peer_address, - own_addr_type, - own_address, - reinterpret_cast(&(evt.conn_params)) - ); - } - - // Apply authentication strategy before application notification - if (!private_peer_known && - _privacy_enabled && - evt.role == BLE_GAP_ROLE_PERIPH && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - ) { - switch (_peripheral_privacy_configuration.resolution_strategy) { - case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE: - nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getSecurityManager().requestAuthentication(handle); - break; - - case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE: - // FIXME: lookup secure DB to know what to do. - break; - - default: - break; - } - } - - processConnectionEvent( - handle, - static_cast(evt.role), - peer_addr_type, - peer_address, - own_addr_type, - own_address, - reinterpret_cast(&(evt.conn_params)), - peer_resolvable_address, - own_resolvable_address - ); -} - -void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { - peer_address_type_t peer_addr_type(peer_address_type_t::PUBLIC); - const uint8_t* peer_address = evt.peer_addr.addr; - - if (_privacy_enabled && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && - _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE - ) { - using ble::pal::vendor::nordic::nRF5xSecurityManager; - - const resolving_list_entry_t* entry = get_sm().resolve_address( - peer_address - ); - - if (entry) { - peer_address = entry->peer_identity_address.data(); - peer_addr_type = convert_identity_address(entry->peer_identity_address_type); - } else if (_central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD || - get_sm().get_resolving_list().size() == 0 - ) { - peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); - } else { - // filter out the packet. - return; - } - } else { - peer_addr_type = convert_nordic_address(evt.peer_addr.addr_type); - } - - processAdvertisementReport( - peer_address, - evt.rssi, - evt.scan_rsp, - static_cast(evt.type), - evt.dlen, - evt.data, - peer_addr_type - ); -} - -ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated && c.connection == connection) { - role = c.is_peripheral ? PERIPHERAL : CENTRAL; - return BLE_ERROR_NONE; - } - } - - return BLE_ERROR_INVALID_PARAM; -} - -void nRF5xGap::allocate_connection_role( - ble::connection_handle_t connection, - Role_t role -) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated == false) { - c.connection = connection; - c.is_peripheral = (role == Gap::PERIPHERAL); - c.is_allocated = true; - return; - } - } -} -void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated && c.connection == connection) { - c.is_allocated = false; - return; - } - } -} - -void nRF5xGap::release_all_connections_role() { - for (size_t i = 0; i < max_connections_count; ++i) { - _connections_role[i].is_allocated = false; - } -} - diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp deleted file mode 100644 index 36c7c1e0a2..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.cpp +++ /dev/null @@ -1,1233 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "nRF5xPalSecurityManager.h" -#include "nRF5xn.h" -#include "ble/Gap.h" -#include "nRF5xGap.h" -#include "nrf_ble.h" -#include "nrf_ble_gap.h" -#include "nrf_soc.h" - -namespace ble { -namespace pal { -namespace vendor { -namespace nordic { - -namespace { -static ble_error_t convert_sd_error(uint32_t err) { - switch (err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - case NRF_ERROR_INVALID_ADDR: - case NRF_ERROR_INVALID_PARAM: - case BLE_ERROR_INVALID_CONN_HANDLE: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - case BLE_ERROR_INVALID_ROLE: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_NOT_SUPPORTED: - return BLE_ERROR_NOT_IMPLEMENTED; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_TIMEOUT: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - default: - return BLE_ERROR_UNSPECIFIED; - } -} -} - -enum pairing_role_t { - PAIRING_INITIATOR, - PAIRING_RESPONDER -}; - -struct nRF5xSecurityManager::pairing_control_block_t { - pairing_control_block_t* next; - connection_handle_t connection; - pairing_role_t role; - - // flags of the key present - KeyDistribution initiator_dist; - KeyDistribution responder_dist; - - // own keys - ble_gap_enc_key_t own_enc_key; - ble_gap_id_key_t own_id_key; - ble_gap_sign_info_t own_sign_key; - ble_gap_lesc_p256_pk_t own_pk; - - // peer keys - ble_gap_enc_key_t peer_enc_key; - ble_gap_id_key_t peer_id_key; - ble_gap_sign_info_t peer_sign_key; - ble_gap_lesc_p256_pk_t peer_pk; - - // flag required to help DHKey computation/process; should be removed with - // later versions of the softdevice - uint8_t own_oob:1; - uint8_t peer_oob:1; -}; - -nRF5xSecurityManager::nRF5xSecurityManager() - : ::ble::pal::SecurityManager(), - _sign_counter(), - _io_capability(io_capability_t::NO_INPUT_NO_OUTPUT), - _min_encryption_key_size(7), - _max_encryption_key_size(16), - _control_blocks(NULL), - resolving_list_entry_count(0) -{ - -} - -nRF5xSecurityManager::~nRF5xSecurityManager() -{ - terminate(); -} - -//////////////////////////////////////////////////////////////////////////// -// SM lifecycle management -// - -ble_error_t nRF5xSecurityManager::initialize() -{ -#if defined(MBEDTLS_ECDH_C) - if (_crypto.generate_keys( - make_ArrayView(X), - make_ArrayView(Y), - make_ArrayView(secret) - )) { - return BLE_ERROR_NONE; - } - - return BLE_ERROR_INTERNAL_STACK_FAILURE; -#endif - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::terminate() -{ - release_all_pairing_cb(); - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::reset() -{ - ble_error_t err = terminate(); - if (err) { - return err; - } - - return initialize(); -} - -//////////////////////////////////////////////////////////////////////////// -// Resolving list management -// - -// FIXME: on nordic, the irk is passed in sd_ble_gap_scan_start where whitelist -// and resolving list are all mixed up. - -uint8_t nRF5xSecurityManager::read_resolving_list_capacity() -{ - return MAX_RESOLVING_LIST_ENTRIES; -} - -ble_error_t nRF5xSecurityManager::add_device_to_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address, - const irk_t &peer_irk -) { - if (resolving_list_entry_count >= MAX_RESOLVING_LIST_ENTRIES) { - return BLE_ERROR_INVALID_STATE; - } - - resolving_list_entry_t& entry = resolving_list[resolving_list_entry_count]; - entry.peer_identity_address_type = peer_identity_address_type; - entry.peer_identity_address = peer_identity_address; - entry.peer_irk = peer_irk; - - ++resolving_list_entry_count; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::remove_device_from_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address -) { - size_t entry_index; - - // first the index needs to be found - for (entry_index = 0; entry_index < resolving_list_entry_count; ++entry_index) { - resolving_list_entry_t& entry = resolving_list[entry_index]; - if (entry.peer_identity_address_type == peer_identity_address_type && - entry.peer_identity_address == peer_identity_address - ) { - break; - } - } - - if (entry_index == resolving_list_entry_count) { - return BLE_ERROR_INVALID_PARAM; - } - - // Elements after the entry can be moved in the list - for (size_t i = entry_index; i < (resolving_list_entry_count - 1); ++i) { - resolving_list[i] = resolving_list[i + 1]; - } - - --resolving_list_entry_count; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::clear_resolving_list() -{ - resolving_list_entry_count = 0; - return BLE_ERROR_NONE; -} - -ArrayView -nRF5xSecurityManager::get_resolving_list() { - return ArrayView( - resolving_list, - resolving_list_entry_count - ); -} - -const nRF5xSecurityManager::resolving_list_entry_t* -nRF5xSecurityManager::resolve_address(const address_t& resolvable_address) { - typedef byte_array_t hash_t; - - for (size_t i = 0; i < resolving_list_entry_count; ++i) { - resolving_list_entry_t& entry = resolving_list[i]; - hash_t hash_generated; - - // Compute the hash part from the random address part when the irk of - // the entry is used - CryptoToolbox::ah( - make_const_ArrayView(entry.peer_irk), - make_const_ArrayView( - resolvable_address.data() + CryptoToolbox::hash_size_ - ), - make_ArrayView(hash_generated) - ); - - // Compare hash generated with the hash present in the address passed as - // parameter. If they are equal then the IRK of the entry has been used - // to generate the resolvable address. - if (memcmp(hash_generated.data(), resolvable_address.data(), CryptoToolbox::hash_size_) == 0) { - return &entry; - } - } - - return NULL; -} - - - -//////////////////////////////////////////////////////////////////////////// -// Pairing -// - - -ble_error_t nRF5xSecurityManager::send_pairing_request( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - // allocate the control block required for the procedure completion - pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_NO_MEM; - } - pairing_cb->role = PAIRING_INITIATOR; - - // override signing parameter - initiator_dist.set_signing(false); - responder_dist.set_signing(false); - - // override link parameter - initiator_dist.set_link(false); - responder_dist.set_link(false); - - ble_gap_sec_params_t security_params = make_security_params( - oob_data_flag, - authentication_requirements, - initiator_dist, - responder_dist - ); - - uint32_t err = sd_ble_gap_authenticate( - connection, - &security_params - ); - - if (err) { - release_pairing_cb(pairing_cb); - } - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::send_pairing_response( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); - if (!pairing_cb) { - // not enough memory; try to reject the pairing request instead of - // waiting for timeout. - cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON); - return BLE_ERROR_NO_MEM; - } - pairing_cb->role = PAIRING_RESPONDER; - - // override signing parameter - initiator_dist.set_signing(false); - responder_dist.set_signing(false); - - // override link parameter - initiator_dist.set_link(false); - responder_dist.set_link(false); - - ble_gap_sec_params_t security_params = make_security_params( - oob_data_flag, - authentication_requirements, - initiator_dist, - responder_dist - ); - - ble_gap_sec_keyset_t keyset = make_keyset( - *pairing_cb, - initiator_dist, - responder_dist - ); - - uint32_t err = sd_ble_gap_sec_params_reply( - connection, - /* status */ BLE_GAP_SEC_STATUS_SUCCESS, - /* params */ &security_params, - /* keys */ &keyset - ); - - if (err) { - release_pairing_cb(pairing_cb); - } - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::cancel_pairing( - connection_handle_t connection, pairing_failure_t reason -) { - uint32_t err = 0; - - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - - // If there is no control block yet then if the local device is a central - // then we must reject the security request otherwise it is a response to - // a pairing feature exchange from a central. - if (!pairing_cb) { - ::Gap::Role_t current_role; - if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) { - return BLE_ERROR_INVALID_PARAM; - } - - if (current_role == ::Gap::PERIPHERAL) { - // response to a pairing feature request - err = sd_ble_gap_sec_params_reply( - connection, - reason.value() | 0x80, - /* sec params */ NULL, - /* keyset */ NULL - ); - } else { - // response to a peripheral security request - err = sd_ble_gap_authenticate(connection, NULL); - } - } else { - // At this point this must be a response to a key - err = sd_ble_gap_auth_key_reply( - connection, - /* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE, - /* key */ NULL - ); - } - - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Feature support -// - -ble_error_t nRF5xSecurityManager::get_secure_connections_support( - bool &enabled -) { - enabled = false; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_io_capability(io_capability_t io_capability) -{ - _io_capability = io_capability; - return BLE_ERROR_NONE; -} - -//////////////////////////////////////////////////////////////////////////// -// Security settings -// - -ble_error_t nRF5xSecurityManager::set_authentication_timeout( - connection_handle_t connection, uint16_t timeout_in_10ms -) { - // FIXME: Use sd_ble_opt_set(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, ...) when - // available - return BLE_ERROR_NOT_IMPLEMENTED; -} - -ble_error_t nRF5xSecurityManager::get_authentication_timeout( - connection_handle_t connection, uint16_t &timeout_in_10ms -) { - // Return default value for now (30s) - timeout_in_10ms = 30 * 100; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_encryption_key_requirements( - uint8_t min_encryption_key_size, - uint8_t max_encryption_key_size -) { - if ((min_encryption_key_size < 7) || (min_encryption_key_size > 16) || - (min_encryption_key_size > max_encryption_key_size)) { - return BLE_ERROR_INVALID_PARAM; - } - - _min_encryption_key_size = min_encryption_key_size; - _max_encryption_key_size = max_encryption_key_size; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::slave_security_request( - connection_handle_t connection, - AuthenticationMask authentication -) { - // In the peripheral role, only the bond, mitm, lesc and keypress fields of - // this structure are used. - ble_gap_sec_params_t security_params = { - /* bond */ authentication.get_bondable(), - /* mitm */ authentication.get_mitm(), - /* lesc */ authentication.get_secure_connections(), - /* keypress */ authentication.get_keypress_notification(), - /* remainder of the data structure is ignored */ 0 - }; - - uint32_t err = sd_ble_gap_authenticate( - connection, - &security_params - ); - - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Encryption -// - -ble_error_t nRF5xSecurityManager::enable_encryption( - connection_handle_t connection, - const ltk_t <k, - const rand_t &rand, - const ediv_t &ediv, - bool mitm -) { - ble_gap_master_id_t master_id; - memcpy(master_id.rand, rand.data(), rand.size()); - memcpy(&master_id.ediv, ediv.data(), ediv.size()); - - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = false; - enc_info.auth = mitm; - - // FIXME: how to pass the lenght of the LTK ??? - enc_info.ltk_len = ltk.size(); - - uint32_t err = sd_ble_gap_encrypt( - connection, - &master_id, - &enc_info - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::enable_encryption( - connection_handle_t connection, - const ltk_t <k, - bool mitm -) { - ble_gap_master_id_t master_id = {0}; - - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = true; - enc_info.auth = mitm; - enc_info.ltk_len = ltk.size(); - - uint32_t err = sd_ble_gap_encrypt( - connection, - &master_id, - &enc_info - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::encrypt_data( - const byte_array_t<16> &key, - encryption_block_t &data -) { - // FIXME: Implement in LescCrypto ? - return BLE_ERROR_NOT_IMPLEMENTED; -} - -//////////////////////////////////////////////////////////////////////////// -// Privacy -// - -ble_error_t nRF5xSecurityManager::set_private_address_timeout( - uint16_t timeout_in_seconds -) { - // get the previous config - ble_gap_irk_t irk; - ble_opt_t privacy_config; - privacy_config.gap_opt.privacy.p_irk = &irk; - - uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, &privacy_config); - if (err) { - return convert_sd_error(err); - } - - // set the timeout and return the result - privacy_config.gap_opt.privacy.interval_s = timeout_in_seconds; - err = sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, &privacy_config); - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Keys -// - -ble_error_t nRF5xSecurityManager::set_ltk( - connection_handle_t connection, - const ltk_t& ltk, - bool mitm, - bool secure_connections -) { - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = secure_connections; - enc_info.auth = mitm; - enc_info.ltk_len = ltk.size(); - - // FIXME: provide peer irk and csrk ? - uint32_t err = sd_ble_gap_sec_info_reply( - connection, - &enc_info, - /* id info */ NULL, - /* sign info */ NULL // Not supported - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_ltk_not_found( - connection_handle_t connection -) { - uint32_t err = sd_ble_gap_sec_info_reply( - connection, - NULL, - NULL, - NULL // Not supported - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_irk(const irk_t& irk) -{ - // get the previous config - ble_gap_irk_t sd_irk; - ble_opt_t privacy_config; - privacy_config.gap_opt.privacy.p_irk = &sd_irk; - - uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_PRIVACY, &privacy_config); - if (err) { - return convert_sd_error(err); - } - - // set the new irk - memcpy(sd_irk.irk, irk.data(), irk.size()); - err = sd_ble_opt_set(BLE_GAP_OPT_PRIVACY, &privacy_config); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_csrk( - const csrk_t& csrk, - sign_count_t sign_counter -) { - _csrk = csrk; - _sign_counter = sign_counter; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_peer_csrk( - connection_handle_t connection, - const csrk_t &csrk, - bool authenticated, - sign_count_t sign_counter -) { - return BLE_ERROR_NOT_IMPLEMENTED; -} - -ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection) -{ - return BLE_ERROR_NOT_IMPLEMENTED; -} - -//////////////////////////////////////////////////////////////////////////// -// Authentication -// - -ble_error_t nRF5xSecurityManager::get_random_data(byte_array_t<8> &random_data) -{ - uint32_t err = sd_rand_application_vector_get( - random_data.data(), random_data.size() - ); - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// MITM -// - -ble_error_t nRF5xSecurityManager::set_display_passkey(passkey_num_t passkey) -{ - PasskeyAscii passkey_ascii(passkey); - ble_opt_t sd_passkey; - sd_passkey.gap_opt.passkey.p_passkey = passkey ? passkey_ascii.value() : NULL; - uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &sd_passkey); - return convert_sd_error(err); -} - - -ble_error_t nRF5xSecurityManager::passkey_request_reply( - connection_handle_t connection, const passkey_num_t passkey -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - PasskeyAscii pkasc(passkey); - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - BLE_GAP_AUTH_KEY_TYPE_PASSKEY, - pkasc.value() - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::secure_connections_oob_request_reply( - connection_handle_t connection, - const oob_lesc_value_t &local_random, - const oob_lesc_value_t &peer_random, - const oob_confirm_t &peer_confirm -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - ble_gap_lesc_oob_data_t oob_own; - ble_gap_lesc_oob_data_t oob_peer; - - // is own address important ? - memcpy(oob_own.r, local_random.data(), local_random.size()); - // FIXME: What to do with local confirm ??? - - // is peer address important ? - memcpy(oob_peer.r, peer_random.data(), peer_random.size()); - memcpy(oob_peer.c, peer_confirm.data(), peer_confirm.size()); - - uint32_t err = sd_ble_gap_lesc_oob_data_set( - connection, - pairing_cb->own_oob ? &oob_own : NULL, - pairing_cb->peer_oob ? &oob_peer : NULL - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::legacy_pairing_oob_request_reply( - connection_handle_t connection, - const oob_tk_t& oob_data -) { - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - BLE_GAP_AUTH_KEY_TYPE_OOB, - oob_data.data() - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::confirmation_entered( - connection_handle_t connection, bool confirmation -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - confirmation ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, - NULL - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::send_keypress_notification( - connection_handle_t connection, Keypress_t keypress -) { - uint32_t err = sd_ble_gap_keypress_notify( - connection, - static_cast(keypress) - ); - return convert_sd_error(err); -} - - -ble_error_t nRF5xSecurityManager::generate_secure_connections_oob() -{ -#if defined(MBEDTLS_ECDH_C) - ble_gap_lesc_p256_pk_t own_secret; - ble_gap_lesc_oob_data_t oob_data; - - memcpy(own_secret.pk, secret.data(), secret.size()); - - uint32_t err = sd_ble_gap_lesc_oob_data_get( - BLE_CONN_HANDLE_INVALID, - &own_secret, - &oob_data - ); - - if (!err) { - get_event_handler()->on_secure_connections_oob_generated( - oob_data.r, - oob_data.c - ); - } - - return convert_sd_error(err); -#endif - return BLE_ERROR_NOT_IMPLEMENTED; -} - -nRF5xSecurityManager& nRF5xSecurityManager::get_security_manager() -{ - static nRF5xSecurityManager _security_manager; - return _security_manager; -} - -bool nRF5xSecurityManager::sm_handler(const ble_evt_t *evt) -{ - nRF5xSecurityManager& self = nRF5xSecurityManager::get_security_manager(); - SecurityManager::EventHandler* handler = self.get_event_handler(); - - if ((evt == NULL) || (handler == NULL)) { - return false; - } - - const ble_gap_evt_t& gap_evt = evt->evt.gap_evt; - uint16_t connection = gap_evt.conn_handle; - pairing_control_block_t* pairing_cb = self.get_pairing_cb(connection); - - switch (evt->header.evt_id) { - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - const ble_gap_sec_params_t& params = - gap_evt.params.sec_params_request.peer_params; - - KeyDistribution initiator_dist( - params.kdist_peer.enc, - params.kdist_peer.id, - params.kdist_peer.sign, - params.kdist_peer.link - ); - - KeyDistribution responder_dist( - params.kdist_own.enc, - params.kdist_own.id, - params.kdist_own.sign, - params.kdist_own.link - ); - - if (pairing_cb && pairing_cb->role == PAIRING_INITIATOR) { - // when this event is received by an initiator, it should not be - // forwarded via the handler; this is not a behaviour expected - // by the bluetooth standard ... - ble_gap_sec_keyset_t keyset = make_keyset( - *pairing_cb, - initiator_dist, - responder_dist - ); - uint32_t err = sd_ble_gap_sec_params_reply( - connection, - /* status */ BLE_GAP_SEC_STATUS_SUCCESS, - /* params */ NULL, - /* keys ... */ &keyset - ); - - // in case of error; release the pairing control block and signal - // it to the event handler - if (err) { - release_pairing_cb(pairing_cb); - handler->on_pairing_error( - connection, - pairing_failure_t::UNSPECIFIED_REASON - ); - } - } else { - handler->on_pairing_request( - connection, - params.oob, - AuthenticationMask( - params.bond, - params.mitm, - params.lesc, - params.keypress - ), - initiator_dist, - responder_dist - ); - } - return true; - } - - case BLE_GAP_EVT_SEC_INFO_REQUEST: { - const ble_gap_evt_sec_info_request_t& req = - gap_evt.params.sec_info_request; - - handler->on_ltk_request( - connection, - ediv_t((uint8_t*)(&req.master_id.ediv)), - rand_t(req.master_id.rand) - ); - - return true; - } - - case BLE_GAP_EVT_PASSKEY_DISPLAY: { - const ble_gap_evt_passkey_display_t& req = - gap_evt.params.passkey_display; - - if (req.match_request == 0) { - handler->on_passkey_display( - connection, - PasskeyAscii::to_num(req.passkey) - ); - } else { - handler->on_passkey_display( - connection, - PasskeyAscii::to_num(req.passkey) - ); - handler->on_confirmation_request(connection); - } - - return true; - } - - case BLE_GAP_EVT_KEY_PRESSED: { - handler->on_keypress_notification( - connection, - (Keypress_t)gap_evt.params.key_pressed.kp_not - ); - return true; - } - - case BLE_GAP_EVT_AUTH_KEY_REQUEST: { - uint8_t key_type = gap_evt.params.auth_key_request.key_type; - - switch (key_type) { - case BLE_GAP_AUTH_KEY_TYPE_NONE: // Illegal - break; - - case BLE_GAP_AUTH_KEY_TYPE_PASSKEY: - handler->on_passkey_request(connection); - break; - - case BLE_GAP_AUTH_KEY_TYPE_OOB: - handler->on_legacy_pairing_oob_request(connection); - break; - } - - return true; - } - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { -#if defined(MBEDTLS_ECDH_C) - const ble_gap_evt_lesc_dhkey_request_t& dhkey_request = - gap_evt.params.lesc_dhkey_request; - - static const size_t key_size = public_key_coord_t::size_; - ble_gap_lesc_dhkey_t shared_secret; - - _crypto.generate_shared_secret( - make_const_ArrayView(dhkey_request.p_pk_peer->pk), - make_const_ArrayView(dhkey_request.p_pk_peer->pk + key_size), - make_const_ArrayView(secret), - shared_secret.key - ); - - sd_ble_gap_lesc_dhkey_reply(connection, &shared_secret); - - if (dhkey_request.oobd_req) { - handler->on_secure_connections_oob_request(connection); - } -#endif - return true; - } - - case BLE_GAP_EVT_AUTH_STATUS: { - const ble_gap_evt_auth_status_t& status = gap_evt.params.auth_status; - - switch (status.auth_status) { - // NOTE: pairing_cb must be valid if this event has been - // received as it is being allocated earlier and release - // in this block - // The memory is released before the last call to the event handler - // to free the heap a bit before subsequent allocation with user - // code. - case BLE_GAP_SEC_STATUS_SUCCESS: { - KeyDistribution own_dist; - KeyDistribution peer_dist; - - if (pairing_cb->role == PAIRING_INITIATOR) { - own_dist = pairing_cb->initiator_dist; - peer_dist = pairing_cb->responder_dist; - } else { - own_dist = pairing_cb->responder_dist; - peer_dist = pairing_cb->initiator_dist; - } - - if (own_dist.get_encryption()) { - handler->on_keys_distributed_local_ltk( - connection, - ltk_t(pairing_cb->own_enc_key.enc_info.ltk) - ); - - handler->on_keys_distributed_local_ediv_rand( - connection, - ediv_t(reinterpret_cast( - &pairing_cb->own_enc_key.master_id.ediv - )), - pairing_cb->own_enc_key.master_id.rand - ); - } - - if (peer_dist.get_encryption()) { - handler->on_keys_distributed_ltk( - connection, - ltk_t(pairing_cb->peer_enc_key.enc_info.ltk) - ); - - handler->on_keys_distributed_ediv_rand( - connection, - ediv_t(reinterpret_cast( - &pairing_cb->peer_enc_key.master_id.ediv - )), - pairing_cb->peer_enc_key.master_id.rand - ); - } - - if (peer_dist.get_identity()) { - handler->on_keys_distributed_irk( - connection, - irk_t(pairing_cb->peer_id_key.id_info.irk) - ); - - advertising_peer_address_type_t - address_type(advertising_peer_address_type_t::PUBLIC); - - if (pairing_cb->peer_id_key.id_addr_info.addr_type) { - address_type = advertising_peer_address_type_t::RANDOM; - } - - handler->on_keys_distributed_bdaddr( - connection, - address_type, - ble::address_t(pairing_cb->peer_id_key.id_addr_info.addr) - ); - } - - if (peer_dist.get_signing()) { - handler->on_keys_distributed_csrk( - connection, - pairing_cb->peer_sign_key.csrk - ); - } - - self.release_pairing_cb(pairing_cb); - handler->on_pairing_completed(connection); - break; - } - - case BLE_GAP_SEC_STATUS_TIMEOUT: - self.release_pairing_cb(pairing_cb); - handler->on_pairing_timed_out(connection); - break; - - case BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED: - case BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE: - case BLE_GAP_SEC_STATUS_AUTH_REQ: - case BLE_GAP_SEC_STATUS_CONFIRM_VALUE: - case BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP: - case BLE_GAP_SEC_STATUS_ENC_KEY_SIZE: - case BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED: - case BLE_GAP_SEC_STATUS_UNSPECIFIED: - case BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS: - case BLE_GAP_SEC_STATUS_INVALID_PARAMS: - case BLE_GAP_SEC_STATUS_DHKEY_FAILURE: - case BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE: - case BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG: - case BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED: - self.release_pairing_cb(pairing_cb); - handler->on_pairing_error( - connection, - (pairing_failure_t::type) (status.auth_status & 0xF) - ); - break; - - default: - self.release_pairing_cb(pairing_cb); - break; - } - - return true; - } - - case BLE_GAP_EVT_CONN_SEC_UPDATE: { - const ble_gap_evt_conn_sec_update_t& req = - gap_evt.params.conn_sec_update; - - if((req.conn_sec.sec_mode.sm == 1) && (req.conn_sec.sec_mode.lv >= 2)) { - handler->on_link_encryption_result( - connection, link_encryption_t::ENCRYPTED - ); - } else { - handler->on_link_encryption_result( - connection, link_encryption_t::NOT_ENCRYPTED - ); - } - return true; - } - - case BLE_GAP_EVT_TIMEOUT: { - switch (gap_evt.params.timeout.src) { - case BLE_GAP_TIMEOUT_SRC_SECURITY_REQUEST: - // Note: pairing_cb does not exist at this point; it is - // created when the module receive the pairing request. - handler->on_link_encryption_request_timed_out(connection); - return true; - - // FIXME: enable with latest SDK -#if 0 - case BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD: - handler->on_valid_mic_timeout(connection); - return true; -#endif - default: - return false; - } - return false; - } - - case BLE_GAP_EVT_SEC_REQUEST: { - const ble_gap_evt_sec_request_t& req = gap_evt.params.sec_request; - handler->on_slave_security_request( - connection, - AuthenticationMask(req.bond, req.mitm, req.lesc, req.keypress) - ); - return true; - } - - default: - return false; - } -} - -ble_gap_sec_params_t nRF5xSecurityManager::make_security_params( - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - ble_gap_sec_params_t security_params = { - /* bond */ authentication_requirements.get_bondable(), - /* mitm */ authentication_requirements.get_mitm(), - /* lesc */ authentication_requirements.get_secure_connections(), - /* keypress */ authentication_requirements.get_keypress_notification(), - /* io_caps */ _io_capability.value(), - /* oob */ oob_data_flag, - /* min_key_size */ _min_encryption_key_size, - /* max_key_size */ _max_encryption_key_size, - /* kdist_periph */ { - /* enc */ responder_dist.get_encryption(), - /* id */ responder_dist.get_identity(), - /* sign */ responder_dist.get_signing(), - /* link */ responder_dist.get_link() - }, - /* kdist_central */ { - /* enc */ initiator_dist.get_encryption(), - /* id */ initiator_dist.get_identity(), - /* sign */ initiator_dist.get_signing(), - /* link */ initiator_dist.get_link() - } - }; - return security_params; -} - -ble_gap_sec_keyset_t nRF5xSecurityManager::make_keyset( - pairing_control_block_t& pairing_cb, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - pairing_cb.initiator_dist = initiator_dist; - pairing_cb.responder_dist = responder_dist; - - KeyDistribution* own_dist = NULL; - KeyDistribution* peer_dist = NULL; - - if (pairing_cb.role == PAIRING_INITIATOR) { - own_dist = &initiator_dist; - peer_dist = &responder_dist; - } else { - own_dist = &responder_dist; - peer_dist = &initiator_dist; - } - - ble_gap_sec_keyset_t keyset = { - /* keys_own */ { - own_dist->get_encryption() ? &pairing_cb.own_enc_key : NULL, - own_dist->get_identity() ? &pairing_cb.own_id_key : NULL, - own_dist->get_signing() ? &pairing_cb.own_sign_key : NULL, - &pairing_cb.own_pk - }, - /* keys_peer */ { - peer_dist->get_encryption() ? &pairing_cb.peer_enc_key : NULL, - peer_dist->get_identity() ? &pairing_cb.peer_id_key : NULL, - peer_dist->get_signing() ? &pairing_cb.peer_sign_key : NULL, - &pairing_cb.peer_pk - } - }; - - // copy csrk if necessary - if (keyset.keys_own.p_sign_key) { - memcpy(keyset.keys_own.p_sign_key->csrk, _csrk.data(), _csrk.size()); - } - - // copy public keys used -#if defined(MBEDTLS_ECDH_C) - memcpy(pairing_cb.own_pk.pk, X.data(), X.size()); - memcpy(pairing_cb.own_pk.pk + X.size(), Y.data(), Y.size()); -#endif - return keyset; -} - -nRF5xSecurityManager::pairing_control_block_t* -nRF5xSecurityManager::allocate_pairing_cb(connection_handle_t connection) -{ - pairing_control_block_t* pairing_cb = - new (std::nothrow) pairing_control_block_t(); - if (pairing_cb) { - pairing_cb->next = _control_blocks; - _control_blocks = pairing_cb; - } - return pairing_cb; -} - -void nRF5xSecurityManager::release_pairing_cb(pairing_control_block_t* pairing_cb) -{ - if (pairing_cb == _control_blocks) { - _control_blocks = _control_blocks->next; - delete pairing_cb; - } else { - pairing_control_block_t* it = _control_blocks; - while (it->next) { - if (it->next == pairing_cb) { - it->next = pairing_cb->next; - delete pairing_cb; - return; - } - it = it->next; - } - } -} - -nRF5xSecurityManager::pairing_control_block_t* -nRF5xSecurityManager::get_pairing_cb(connection_handle_t connection) -{ - pairing_control_block_t* pcb = _control_blocks; - while (pcb) { - if (pcb->connection == connection) { - return pcb; - } - pcb = pcb->next; - } - - return NULL; -} - -void nRF5xSecurityManager::release_all_pairing_cb() -{ - while(_control_blocks) { - release_pairing_cb(_control_blocks); - } -} - -} // nordic -} // vendor -} // pal -} // ble - diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.h deleted file mode 100644 index 32184507da..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xPalSecurityManager.h +++ /dev/null @@ -1,408 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NRF5X_PAL_SECURITY_MANAGER_ -#define NRF5X_PAL_SECURITY_MANAGER_ - -#include "ble/BLETypes.h" -#include "ble/pal/PalSecurityManager.h" -#include "nrf_ble.h" -#include "nRF5xCrypto.h" - - -namespace ble { -namespace pal { -namespace vendor { -namespace nordic { - -class nRF5xSecurityManager : public ::ble::pal::SecurityManager { -public: - nRF5xSecurityManager(); - - virtual ~nRF5xSecurityManager(); - - //////////////////////////////////////////////////////////////////////////// - // SM lifecycle management - // - - /** - * @see ::ble::pal::SecurityManager::initialize - */ - virtual ble_error_t initialize(); - - /** - * @see ::ble::pal::SecurityManager::terminate - */ - virtual ble_error_t terminate(); - - /** - * @see ::ble::pal::SecurityManager::reset - */ - virtual ble_error_t reset() ; - - //////////////////////////////////////////////////////////////////////////// - // Resolving list management - // - - /** - * @see ::ble::pal::SecurityManager::read_resolving_list_capacity - */ - virtual uint8_t read_resolving_list_capacity(); - - /** - * @see ::ble::pal::SecurityManager::add_device_to_resolving_list - */ - virtual ble_error_t add_device_to_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address, - const irk_t &peer_irk - ); - - /** - * @see ::ble::pal::SecurityManager::remove_device_from_resolving_list - */ - virtual ble_error_t remove_device_from_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address - ); - - /** - * @see ::ble::pal::SecurityManager::clear_resolving_list - */ - virtual ble_error_t clear_resolving_list(); - - /** - * An entry of the resolving list stored in the SecurityManager. - */ - struct resolving_list_entry_t { - resolving_list_entry_t() : - peer_identity_address_type( - advertising_peer_address_type_t::PUBLIC - ) - { } - - irk_t peer_irk; - address_t peer_identity_address; - advertising_peer_address_type_t peer_identity_address_type; - }; - - /** - * Return the IRKs present in the resolving list - * @param count The number of entries present in the resolving list. - * @param pointer to the first entry of the resolving list. - */ - ArrayView get_resolving_list(); - - /** - * Try to resolve a private resolvable address. - * - * @param resolvable_address The address to resolve. - * - * @return Pointer to the entry found if any. - */ - const resolving_list_entry_t* resolve_address( - const address_t& resolvable_address - ); - - - //////////////////////////////////////////////////////////////////////////// - // Pairing - // - - /** - * @see ::ble::pal::SecurityManager::send_pairing_request - */ - virtual ble_error_t send_pairing_request( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - /** - * @see ::ble::pal::SecurityManager::send_pairing_response - */ - virtual ble_error_t send_pairing_response( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - /** - * @see ::ble::pal::SecurityManager::cancel_pairing - */ - virtual ble_error_t cancel_pairing( - connection_handle_t connection, pairing_failure_t reason - ); - - - //////////////////////////////////////////////////////////////////////////// - // Feature support - // - - /** - * @see ::ble::pal::SecurityManager::get_secure_connections_support - */ - virtual ble_error_t get_secure_connections_support( - bool &enabled - ); - - /** - * @see ::ble::pal::SecurityManager::set_io_capability - */ - virtual ble_error_t set_io_capability(io_capability_t io_capability); - - //////////////////////////////////////////////////////////////////////////// - // Security settings - // - - /** - * @see ::ble::pal::SecurityManager::set_authentication_timeout - */ - virtual ble_error_t set_authentication_timeout( - connection_handle_t, uint16_t timeout_in_10ms - ); - - /** - * @see ::ble::pal::SecurityManager::get_authentication_timeout - */ - virtual ble_error_t get_authentication_timeout( - connection_handle_t, uint16_t &timeout_in_10ms - ); - - /** - * @see ::ble::pal::SecurityManager::set_encryption_key_requirements - */ - virtual ble_error_t set_encryption_key_requirements( - uint8_t min_encryption_key_size, - uint8_t max_encryption_key_size - ); - - /** - * @see ::ble::pal::SecurityManager::slave_security_request - */ - virtual ble_error_t slave_security_request( - connection_handle_t connection, - AuthenticationMask authentication - ); - - //////////////////////////////////////////////////////////////////////////// - // Encryption - // - - /** - * @see ::ble::pal::SecurityManager::enable_encryption - */ - virtual ble_error_t enable_encryption( - connection_handle_t connection, - const ltk_t <k, - const rand_t &rand, - const ediv_t &ediv, - bool mitm - ); - - /** - * @see ::ble::pal::SecurityManager::enable_encryption - */ - virtual ble_error_t enable_encryption( - connection_handle_t connection, - const ltk_t <k, - bool mitm - ) ; - - /** - * @see ::ble::pal::SecurityManager::encrypt_data - */ - virtual ble_error_t encrypt_data( - const byte_array_t<16> &key, - encryption_block_t &data - ); - - //////////////////////////////////////////////////////////////////////////// - // Privacy - // - - /** - * @see ::ble::pal::SecurityManager::set_private_address_timeout - */ - virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds); - - //////////////////////////////////////////////////////////////////////////// - // Keys - // - - /** - * @see ::ble::pal::SecurityManager::set_ltk - */ - virtual ble_error_t set_ltk( - connection_handle_t connection, - const ltk_t <k, - bool mitm, - bool secure_connections - ); - - /** - * @see ::ble::pal::SecurityManager::set_ltk_not_found - */ - virtual ble_error_t set_ltk_not_found( - connection_handle_t connection - ); - - /** - * @see ::ble::pal::SecurityManager::set_irk - */ - virtual ble_error_t set_irk(const irk_t &irk); - - /** - * @see ::ble::pal::SecurityManager::set_csrk - */ - virtual ble_error_t set_csrk(const csrk_t &csrk, sign_count_t sign_counter); - - /** - * @see ::ble::pal::SecurityManager::set_peer_csrk - */ - virtual ble_error_t set_peer_csrk( - connection_handle_t connection, - const csrk_t &csrk, - bool authenticated, - sign_count_t sign_counter - ); - - /** - * @see ::ble::pal::SecurityManager::remove_peer_csrk - */ - virtual ble_error_t remove_peer_csrk(connection_handle_t connection); - - - //////////////////////////////////////////////////////////////////////////// - // Authentication - // - - /** - * @see ::ble::pal::SecurityManager::get_random_data - */ - virtual ble_error_t get_random_data(byte_array_t<8> &random_data); - - //////////////////////////////////////////////////////////////////////////// - // MITM - // - - /** - * @see ::ble::pal::SecurityManager::set_display_passkey - */ - virtual ble_error_t set_display_passkey(passkey_num_t passkey); - - /** - * @see ::ble::pal::SecurityManager::passkey_request_reply - */ - virtual ble_error_t passkey_request_reply( - connection_handle_t connection, - passkey_num_t passkey - ); - - /** - * @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply - */ - virtual ble_error_t secure_connections_oob_request_reply( - connection_handle_t connection, - const oob_lesc_value_t &local_random, - const oob_lesc_value_t &peer_random, - const oob_confirm_t &peer_confirm - ); - - /** - * @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply - */ - virtual ble_error_t legacy_pairing_oob_request_reply( - connection_handle_t connection, - const oob_tk_t &oob_data - ); - - /** - * @see ::ble::pal::SecurityManager::confirmation_entered - */ - virtual ble_error_t confirmation_entered( - connection_handle_t connection, bool confirmation - ); - - /** - * @see ::ble::pal::SecurityManager::send_keypress_notification - */ - virtual ble_error_t send_keypress_notification( - connection_handle_t connection, Keypress_t keypress - ); - - /** - * @see ::ble::pal::SecurityManager::generate_secure_connections_oob - */ - virtual ble_error_t generate_secure_connections_oob(); - - // singleton of nordic Security Manager - static nRF5xSecurityManager& get_security_manager(); - - // Event handler - bool sm_handler(const ble_evt_t *evt); - -private: - csrk_t _csrk; - sign_count_t _sign_counter; - io_capability_t _io_capability; - uint8_t _min_encryption_key_size; - uint8_t _max_encryption_key_size; - - struct pairing_control_block_t; - - ble_gap_sec_params_t make_security_params( - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - ble_gap_sec_keyset_t make_keyset( - pairing_control_block_t& pairing_cb, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - pairing_control_block_t* allocate_pairing_cb(connection_handle_t connection); - void release_pairing_cb(pairing_control_block_t* pairing_cb); - pairing_control_block_t* get_pairing_cb(connection_handle_t connection); - void release_all_pairing_cb(); - - pairing_control_block_t* _control_blocks; -#if defined(MBEDTLS_ECDH_C) - CryptoToolbox _crypto; - ble::public_key_coord_t X; - ble::public_key_coord_t Y; - ble::public_key_coord_t secret; -#endif - - static const size_t MAX_RESOLVING_LIST_ENTRIES = BLE_GAP_WHITELIST_IRK_MAX_COUNT; - - size_t resolving_list_entry_count; - resolving_list_entry_t resolving_list[MAX_RESOLVING_LIST_ENTRIES]; -}; - -} // nordic -} // vendor -} // pal -} // ble - -#endif /* NRF5X_PAL_SECURITY_MANAGER_ */ diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp deleted file mode 100644 index 5c343eafa5..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "nRF5xn.h" -#ifdef YOTTA_CFG_MBED_OS - #include "mbed-drivers/mbed.h" -#else - #include "mbed.h" -#endif -#include "ble/BLE.h" - -#include "common/common.h" -#include "headers/ble_hci.h" -#include "ble/pal/ConnectionEventMonitor.h" -#include "nRF5xPalSecurityManager.h" -#include - -using ble::pal::vendor::nordic::nRF5xSecurityManager; -using ble::ArrayView; -using ble::pal::advertising_peer_address_type_t; -using ble::peer_address_type_t; - -typedef BLEProtocol::AddressType LegacyAddressType; -typedef BLEProtocol::AddressType_t LegacyAddressType_t; - -namespace { - -nRF5xSecurityManager& get_sm() { - return nRF5xSecurityManager::get_security_manager(); -} - -ble_error_t set_private_resolvable_address() { -#if (NRF_SD_BLE_API_VERSION <= 2) - ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE }; - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); -#else - ble_gap_privacy_params_t privacy_config = { 0 }; - uint32_t err = sd_ble_gap_privacy_get(&privacy_config); - if (err) { - return BLE_ERROR_UNSPECIFIED; - } - - privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; - err = sd_ble_gap_privacy_set(&privacy_config); -#endif - return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; -} - -ble_error_t set_private_non_resolvable_address() { -#if (NRF_SD_BLE_API_VERSION <= 2) - ble_gap_addr_t addr = { BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE }; - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_AUTO, &addr); -#else - ble_gap_privacy_params_t privacy_config = { 0 }; - uint32_t err = sd_ble_gap_privacy_get(&privacy_config); - if (err) { - return BLE_ERROR_UNSPECIFIED; - } - - privacy_config.private_addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE; - err = sd_ble_gap_privacy_set(&privacy_config); -#endif - return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE; -} - -bool is_advertising_non_connectable(const GapAdvertisingParams ¶ms) { - switch (params.getAdvertisingType()) { - case GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED: - case GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED: - return true; - default: - return false; - } -} - -bool is_identity_address(peer_address_type_t address_type) { - return address_type == peer_address_type_t::PUBLIC_IDENTITY || - address_type == peer_address_type_t::RANDOM_STATIC_IDENTITY; -} - -peer_address_type_t convert_nordic_address(bool identity, uint8_t address) { - if (identity) { - if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { - return peer_address_type_t::PUBLIC_IDENTITY; - } else { - return peer_address_type_t::RANDOM_STATIC_IDENTITY; - } - } else { - if (address == BLE_GAP_ADDR_TYPE_PUBLIC) { - return peer_address_type_t::PUBLIC; - } else { - return peer_address_type_t::RANDOM; - } - } -} - -peer_address_type_t convert_identity_address(advertising_peer_address_type_t address) { - if (address == advertising_peer_address_type_t::PUBLIC) { - return peer_address_type_t::PUBLIC_IDENTITY; - } else { - return peer_address_type_t::RANDOM_STATIC_IDENTITY; - } -} - -// FIXME: update when SD 5 (not alpha!) or more is used for 52840. -#ifndef BLE_GAP_PHY_AUTO -#define BLE_GAP_PHY_AUTO 0 -#endif - -} // namespace - -void radioNotificationStaticCallback(bool param) { - nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); - gap.processRadioNotificationEvent(param); -} - -nRF5xGap::nRF5xGap() : Gap(), - advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), - scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), - whitelistAddressesSize(0), - whitelistAddresses(), - radioNotificationCallbackParam(false), - radioNotificationTimeout(), - _connection_event_handler(NULL), - _privacy_enabled(false), - _peripheral_privacy_configuration(default_peripheral_privacy_configuration), - _central_privacy_configuration(default_central_privacy_configuration), - _non_private_address_type(LegacyAddressType::RANDOM_STATIC), - _preferred_tx_phys(BLE_GAP_PHY_AUTO), - _preferred_rx_phys(BLE_GAP_PHY_AUTO), - _connections_role() -{ - m_connectionHandle = BLE_CONN_HANDLE_INVALID; -} -/**************************************************************************/ -/*! - @brief Sets the advertising parameters and payload for the device - - @param[in] params - Basic advertising details, including the advertising - delay, timeout and how the device should be advertised - @params[in] advData - The primary advertising data payload - @params[in] scanResponse - The optional Scan Response payload if the advertising - type is set to \ref GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED - in \ref GapAdveritinngParams - - @returns \ref ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @retval BLE_ERROR_BUFFER_OVERFLOW - The proposed action would cause a buffer overflow. All - advertising payloads must be <= 31 bytes, for example. - - @retval BLE_ERROR_NOT_IMPLEMENTED - A feature was requested that is not yet supported in the - nRF51 firmware or hardware. - - @retval BLE_ERROR_PARAM_OUT_OF_RANGE - One of the proposed values is outside the valid range. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) -{ - /* Make sure we don't exceed the advertising payload length */ - if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { - return BLE_ERROR_BUFFER_OVERFLOW; - } - - /* Make sure we have a payload! */ - if (advData.getPayloadLen() == 0) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Check the scan response payload limits */ - //if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED)) - //{ - // /* Check if we're within the upper limit */ - // if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) - // { - // return BLE_ERROR_BUFFER_OVERFLOW; - // } - // /* Make sure we have a payload! */ - // if (advData.getPayloadLen() == 0) - // { - // return BLE_ERROR_PARAM_OUT_OF_RANGE; - // } - //} - - /* Send advertising data! */ - ASSERT_TRUE(ERROR_NONE == - sd_ble_gap_adv_data_set(advData.getPayload(), - advData.getPayloadLen(), - scanResponse.getPayload(), - scanResponse.getPayloadLen()), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - /* Make sure the GAP Service appearance value is aligned with the - *appearance from GapAdvertisingData */ - ASSERT_TRUE(ERROR_NONE == sd_ble_gap_appearance_set(advData.getAppearance()), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - /* ToDo: Perform some checks on the payload, for example the Scan Response can't */ - /* contains a flags AD type, etc. */ - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Starts the BLE HW, initialising any services that were - added before this function was called. - - @note All services must be added before calling this function! - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) -{ - uint32_t err; - ble_gap_adv_params_t adv_para = {0}; - - /* Make sure we support the advertising type */ - if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) { - /* ToDo: This requires a propery security implementation, etc. */ - return BLE_ERROR_NOT_IMPLEMENTED; - } - - /* Check interval range */ - if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) { - /* Min delay is slightly longer for unconnectable devices */ - if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) || - (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } else { - if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) || - (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } - - /* Check timeout is zero for Connectable Directed */ - if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) { - /* Timeout must be 0 with this type, although we'll never get here */ - /* since this isn't implemented yet anyway */ - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Check timeout for other advertising types */ - if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && - (params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ - if (advertisingPolicyMode != Gap::ADV_POLICY_IGNORE_WHITELIST) { - ble_error_t error = generateStackWhitelist(whitelist); - if (error != BLE_ERROR_NONE) { - return error; - } - } - - if (_privacy_enabled) { - if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) { - ArrayView entries = get_sm().get_resolving_list(); - - size_t limit = std::min( - entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE - ); - - for (size_t i = 0; i < limit; ++i) { - whitelistIrkPtrs[i] = (ble_gap_irk_t*) entries[i].peer_irk.data(); - } - whitelist.irk_count = limit; - } - - if (_peripheral_privacy_configuration.use_non_resolvable_random_address && - is_advertising_non_connectable(params) - ) { - set_private_non_resolvable_address(); - } else { - set_private_resolvable_address(); - } - } - adv_para.p_whitelist = &whitelist; -#else - if (_privacy_enabled) { - bool enable_resolution = - _peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE; - update_identities_list(enable_resolution); - - if (_peripheral_privacy_configuration.use_non_resolvable_random_address && - is_advertising_non_connectable(params) - ) { - set_private_non_resolvable_address(); - } else { - set_private_resolvable_address(); - } - } -#endif - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - /* Start Advertising */ - - - adv_para.type = params.getAdvertisingType(); - adv_para.p_peer_addr = NULL; // Undirected advertisement - adv_para.fp = advertisingPolicyMode; - adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms) - adv_para.timeout = params.getTimeout(); - -#if (NRF_SD_BLE_API_VERSION >= 5) - err = sd_ble_gap_adv_start(&adv_para, NRF_CONNECTION_TAG); -#else - err = sd_ble_gap_adv_start(&adv_para); -#endif - switch(err) { - case ERROR_NONE: - return BLE_ERROR_NONE; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - default: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/* Observer role is not supported by S110, return BLE_ERROR_NOT_IMPLEMENTED */ -#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) -ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams) -{ - - ble_gap_scan_params_t scanParams; - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ - if (scanningPolicyMode != Gap::SCAN_POLICY_IGNORE_WHITELIST) { - ble_error_t error = generateStackWhitelist(whitelist); - if (error != BLE_ERROR_NONE) { - return error; - } - } - - // FIXME: fill the irk list once addresses are resolved by the softdevice. - scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ - scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ -#else - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - scanParams.use_whitelist = scanningPolicyMode; - scanParams.adv_dir_report = 0; -#endif - - scanParams.active = scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - - scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - - if (_privacy_enabled) { - bool enable_resolution = - _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE; - - update_identities_list(enable_resolution); - - if (_central_privacy_configuration.use_non_resolvable_random_address) { - set_private_non_resolvable_address(); - } else { - set_private_resolvable_address(); - } - } - - if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::stopScan(void) { - if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - - return BLE_STACK_BUSY; -} -#endif - -/**************************************************************************/ -/*! - @brief Stops the BLE HW and disconnects from any devices - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::stopAdvertising(void) -{ - /* Stop Advertising */ - ASSERT_TRUE(ERROR_NONE == sd_ble_gap_adv_stop(), BLE_ERROR_PARAM_OUT_OF_RANGE); - - state.advertising = 0; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - peer_address_type_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn -) { - // NOTE: Nordic address type is an closer to LegacyAddressType: resolved - // address are treaded either as PUBLIC or RANDOM STATIC adresses. - // The idea is to get the conversion done here and call the legacy function. - - LegacyAddressType_t legacy_address; - - switch (peerAddrType.value()) { - case peer_address_type_t::PUBLIC: - case peer_address_type_t::PUBLIC_IDENTITY: - legacy_address = LegacyAddressType::PUBLIC; - break; - case peer_address_type_t::RANDOM_STATIC_IDENTITY: - legacy_address = LegacyAddressType::RANDOM_STATIC; - break; - case peer_address_type_t::RANDOM: { - RandomAddressType_t random_address_type(RandomAddressType_t::STATIC); - ble_error_t err = getRandomAddressType(peerAddr, &random_address_type); - if (err) { - return err; - } - switch (random_address_type.value()) { - case RandomAddressType_t::STATIC: - legacy_address = LegacyAddressType::RANDOM_STATIC; - break; - case RandomAddressType_t::NON_RESOLVABLE_PRIVATE: - legacy_address = LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE; - break; - case RandomAddressType_t::RESOLVABLE_PRIVATE: - legacy_address = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; - break; - default: - return BLE_ERROR_UNSPECIFIED; - } - } break; - default: - return BLE_ERROR_INVALID_PARAM; - } - - bool identity = - peerAddrType == peer_address_type_t::PUBLIC_IDENTITY || - peerAddrType == peer_address_type_t::RANDOM_STATIC_IDENTITY; - - return connect(peerAddr, legacy_address, connectionParams, scanParamsIn, identity); -} - - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - LegacyAddressType_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn -) { - return connect(peerAddr, peerAddrType, connectionParams, scanParamsIn, false); -} - -ble_error_t nRF5xGap::connect( - const Address_t peerAddr, - LegacyAddressType_t peerAddrType, - const ConnectionParams_t *connectionParams, - const GapScanningParams *scanParamsIn, - bool identity -) { - ble_gap_addr_t addr; - ble_gap_addr_t* addr_ptr = &addr; - addr.addr_type = peerAddrType; - memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); - - ble_gap_conn_params_t connParams; - if (connectionParams != NULL) { - connParams.min_conn_interval = connectionParams->minConnectionInterval; - connParams.max_conn_interval = connectionParams->maxConnectionInterval; - connParams.slave_latency = connectionParams->slaveLatency; - connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; - } else { - connParams.min_conn_interval = 50; - connParams.max_conn_interval = 100; - connParams.slave_latency = 0; - connParams.conn_sup_timeout = 600; - } - - ble_gap_scan_params_t scanParams ={0}; - -#if (NRF_SD_BLE_API_VERSION <= 2) - /* Allocate the stack's whitelist statically */ - ble_gap_whitelist_t whitelist; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - /* Initialize the whitelist */ - whitelist.pp_addrs = whitelistAddressPtrs; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.addr_count = 0; - whitelist.irk_count = 0; - - /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ - if (scanningPolicyMode != Gap::SCAN_POLICY_IGNORE_WHITELIST) { - ble_error_t error = generateStackWhitelist(whitelist); - if (error != BLE_ERROR_NONE) { - return error; - } - } - - scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ - scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ - if (_privacy_enabled) { - // configure the "whitelist" with the IRK associated with the identity - // address in input. - if (is_identity_address(peerAddrType)) { - ArrayView entries = get_sm().get_resolving_list(); - - size_t i; - for (i = 0; i < entries.size(); ++i) { - const ble::address_t& entry_address = entries[i].peer_identity_address; - - // entry found; fill the whitelist and invalidate addr_ptr - if (memcmp(entry_address.data(), peerAddr, entry_address.size_) == 0) { - whitelist.pp_irks[0] = (ble_gap_irk_t*) entries[i].peer_irk.data(); - whitelist.irk_count = 1; - scanParams.selective = 1; - addr_ptr = NULL; - break; - } - } - - // Occur only if the address in input hasn't been resolved. - if (i == entries.size()) { - return BLE_ERROR_INVALID_PARAM; - } - } - - set_private_resolvable_address(); - } -#else - /* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */ - - scanParams.use_whitelist = (whitelistAddressesSize) ? 1 : 0; - - if (_privacy_enabled) { - bool enable_resolution = - _central_privacy_configuration.resolution_strategy != CentralPrivacyConfiguration_t::DO_NOT_RESOLVE; - - update_identities_list(enable_resolution); - - if (enable_resolution && identity) { - addr.addr_id_peer = 1; - } - - set_private_resolvable_address(); - } - -#endif - - if (scanParamsIn != NULL) { - scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - } else { - scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ - scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - } - -#if NRF_SD_BLE_API_VERSION >= 5 - uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams, NRF_CONNECTION_TAG); -#else - uint32_t rc = sd_ble_gap_connect(addr_ptr, &scanParams, &connParams); -#endif - if (rc == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - switch (rc) { - case NRF_ERROR_INVALID_ADDR: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_PARAM: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - case BLE_ERROR_GAP_INVALID_BLE_ADDR: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - case BLE_ERROR_GAP_WHITELIST_IN_USE: - return BLE_ERROR_UNSPECIFIED; - } -} - -ble_error_t nRF5xGap::readPhy(Handle_t connection) { - /* - * This function is not implemented as it is not possible with current - * nordic API to know which phy was used to establish the connection. - * - * TODO: Update when Nordic provides the API to do the job. - */ - return BLE_ERROR_NOT_IMPLEMENTED; -} - -ble_error_t nRF5xGap::setPreferredPhys( - const ble::phy_set_t* txPhys, - const ble::phy_set_t* rxPhys -) { - uint8_t preferred_tx_phys = txPhys? txPhys->value() : 0; - uint8_t preferred_rx_phys = rxPhys? rxPhys->value() : 0; - -#ifdef S140 - ble_opt_t opt = { 0 }; - opt.gap_opt.preferred_phys.tx_phys = preferred_tx_phys; - opt.gap_opt.preferred_phys.rx_phys = preferred_rx_phys; - - uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PREFERRED_PHYS_SET, &opt); - - switch (err) { - case NRF_SUCCESS: - break; - case NRF_ERROR_INVALID_ADDR: - case BLE_ERROR_INVALID_CONN_HANDLE: - case NRF_ERROR_INVALID_PARAM: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - return BLE_ERROR_UNSPECIFIED; - } - -#endif - - _preferred_tx_phys = preferred_tx_phys; - _preferred_rx_phys = preferred_rx_phys; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setPhy( - Handle_t connection, - const ble::phy_set_t* txPhys, - const ble::phy_set_t* rxPhys, - CodedSymbolPerBit_t codedSymbol -) { -#ifdef S140 - return BLE_ERROR_NOT_IMPLEMENTED; -#else - // TODO handle coded symbol once supported by the softdevice. - ble_gap_phys_t gap_phys = { - txPhys? txPhys->value() : 0, - rxPhys? rxPhys->value() : 0 - }; - - uint32_t err = sd_ble_gap_phy_update(connection, &gap_phys); - - switch (err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - case NRF_ERROR_INVALID_ADDR: - case BLE_ERROR_INVALID_CONN_HANDLE: - case NRF_ERROR_INVALID_PARAM: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - default: - return BLE_ERROR_UNSPECIFIED; - } -#endif -} - -ble_error_t nRF5xGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) -{ - uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; - switch (reason) { - case REMOTE_USER_TERMINATED_CONNECTION: - code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION; - break; - case CONN_INTERVAL_UNACCEPTABLE: - code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE; - break; - default: - break; - } - - /* Disconnect if we are connected to a central device */ - ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -/*! - @brief Disconnects if we are connected to a central device - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly -*/ -ble_error_t nRF5xGap::disconnect(DisconnectionReason_t reason) -{ - return disconnect(m_connectionHandle, reason); -} - -ble_error_t nRF5xGap::getPreferredConnectionParams(ConnectionParams_t *params) -{ - ASSERT_INT(NRF_SUCCESS, - sd_ble_gap_ppcp_get(reinterpret_cast(params)), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setPreferredConnectionParams(const ConnectionParams_t *params) -{ - ASSERT_INT(NRF_SUCCESS, - sd_ble_gap_ppcp_set(reinterpret_cast(params)), - BLE_ERROR_PARAM_OUT_OF_RANGE); - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams) -{ - uint32_t rc; - - rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast(const_cast(newParams))); - if (rc == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/**************************************************************************/ -/*! - @brief Clear nRF5xGap's state. - - @returns ble_error_t - - @retval BLE_ERROR_NONE - Everything executed properly -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::reset(void) -{ - /* Clear all state that is from the parent, including private members */ - if (Gap::reset() != BLE_ERROR_NONE) { - return BLE_ERROR_INVALID_STATE; - } - - /* Clear derived class members */ - m_connectionHandle = BLE_CONN_HANDLE_INVALID; - - /* Set the whitelist policy filter modes to IGNORE_WHITELIST */ - advertisingPolicyMode = Gap::ADV_POLICY_IGNORE_WHITELIST; - scanningPolicyMode = Gap::SCAN_POLICY_IGNORE_WHITELIST; - - /* Clear the internal whitelist */ - whitelistAddressesSize = 0; - - /* Reset existing mapping between a connection and its role */ - release_all_connections_role(); - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Sets the 16-bit connection handle -*/ -/**************************************************************************/ -void nRF5xGap::setConnectionHandle(uint16_t con_handle) -{ - m_connectionHandle = con_handle; -} - -/**************************************************************************/ -/*! - @brief Gets the 16-bit connection handle -*/ -/**************************************************************************/ -uint16_t nRF5xGap::getConnectionHandle(void) -{ - return m_connectionHandle; -} - -/**************************************************************************/ -/*! - @brief Sets the BLE device address - - @returns ble_error_t - - @section EXAMPLE - - @code - - uint8_t device_address[6] = { 0xca, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0 }; - nrf.getGap().setAddress(Gap::BLEProtocol::AddressType::RANDOM_STATIC, device_address); - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAddress(LegacyAddressType_t type, const Address_t address) -{ - if (type != LegacyAddressType::PUBLIC && - type != LegacyAddressType::RANDOM_STATIC - ) { - return BLE_ERROR_INVALID_PARAM; - } - - if (_privacy_enabled) { - return BLE_ERROR_INVALID_STATE; - } - - ble_gap_addr_t dev_addr; - memcpy(dev_addr.addr, address, ADDR_LEN); - if (type == LegacyAddressType::PUBLIC) { - dev_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; - } else { - dev_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; - } - -#if (NRF_SD_BLE_API_VERSION <= 2) - uint32_t err = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr); -#else - uint32_t err = sd_ble_gap_addr_set(&dev_addr); -#endif - - switch (err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - case NRF_ERROR_INVALID_ADDR: - return BLE_ERROR_INVALID_PARAM; - case BLE_ERROR_GAP_INVALID_BLE_ADDR: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_INVALID_STATE: - return BLE_ERROR_INVALID_STATE; - default: - return BLE_ERROR_UNSPECIFIED; - } -} - -ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address) -{ - // FIXME: check if privacy is enabled ? - if (typeP == NULL || address == NULL) { - return BLE_ERROR_INVALID_PARAM; - } - - ble_gap_addr_t dev_addr; -#if (NRF_SD_BLE_API_VERSION <= 2) - if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) { -#else - if (sd_ble_gap_addr_get(&dev_addr) != NRF_SUCCESS) { -#endif - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - switch (dev_addr.addr_type) { - case BLE_GAP_ADDR_TYPE_PUBLIC: - *typeP = LegacyAddressType::PUBLIC; - break; - - case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: - *typeP = LegacyAddressType::RANDOM_STATIC; - break; - - default: - return BLE_ERROR_INVALID_STATE; - } - - memcpy(address, dev_addr.addr, ADDR_LEN); - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setDeviceName(const uint8_t *deviceName) -{ - ble_gap_conn_sec_mode_t sec_mode; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed - - if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP) -{ - if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::setAppearance(GapAdvertisingData::Appearance appearance) -{ - if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -ble_error_t nRF5xGap::getAppearance(GapAdvertisingData::Appearance *appearanceP) -{ - if ((sd_ble_gap_appearance_get(reinterpret_cast(appearanceP)) == NRF_SUCCESS)) { - return BLE_ERROR_NONE; - } else { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -} - -/* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ -ble_error_t nRF5xGap::setTxPower(int8_t txPower) -{ - unsigned rc; - if ((rc = sd_ble_gap_tx_power_set(txPower)) != NRF_SUCCESS) { - switch (rc) { - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_INVALID_PARAM: - default: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - } - - return BLE_ERROR_NONE; -} - -void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) -{ -#if defined(NRF51) - static const int8_t permittedTxValues[] = { - -30, -20, -16, -12, -8, -4, 0, 4 - }; -#elif defined(NRF52) -#if NRF_SD_BLE_API_VERSION >= 5 - static const int8_t permittedTxValues[] = { - -40, -20, -16, -12, -8, -4, 0, 3, 4 - }; -#else - static const int8_t permittedTxValues[] = { - -40, -20, -16, -12, -8, -4, 0, 4 - }; -#endif -#elif defined(NRF52840_XXAA) - static const int8_t permittedTxValues[] = { - -40, -20, -16, -12, -8, -4, 0, 2, 3, 4, 5, 6, 7, 8, 9 - }; -#else -#error permitted TX power values unknown for this SOC -#endif - - *valueArrayPP = permittedTxValues; - *countP = sizeof(permittedTxValues) / sizeof(int8_t); -} - -/**************************************************************************/ -/*! - @brief Get the capacity of the internal whitelist maintained by this - implementation. - - @returns The capacity of the internal whitelist. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -uint8_t nRF5xGap::getMaxWhitelistSize(void) const -{ - return YOTTA_CFG_WHITELIST_MAX_SIZE; -} - -/**************************************************************************/ -/*! - @brief Get a copy of the implementation's internal whitelist. - - @param[out] whitelistOut - A \ref Gap::Whitelist_t structure containing a copy of the - addresses in the implemenetation's internal whitelist. - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const -{ - uint32_t i; - for (i = 0; i < whitelistAddressesSize && i < whitelistOut.capacity; ++i) { - memcpy( &whitelistOut.addresses[i].address, &whitelistAddresses[i].addr, sizeof(whitelistOut.addresses[0].address)); - whitelistOut.addresses[i].type = static_cast (whitelistAddresses[i].addr_type); - - - } - whitelistOut.size = i; - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the whitelist that will be used in the next call to - startAdvertising(). - - @param[in] whitelistIn - A reference to a \ref Gap::Whitelist_t structure - representing a whitelist containing all the white listed - BLE addresses. - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_INVALID_PARAM - The supplied whitelist contains a private non-resolvable - address - - BLE_ERROR_PARAM_OUT_OF_RANGE - The size of the supplied whitelist exceeds the maximum - capacity of the implementation's internal whitelist. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) -{ - if (whitelistIn.size > getMaxWhitelistSize()) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - /* Test for invalid parameters before we change the internal state */ - for (uint32_t i = 0; i < whitelistIn.size; ++i) { - if (whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_NON_RESOLVABLE || - whitelistIn.addresses[i].type == LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE - ) { - /* This is not allowed because it is completely meaningless */ - return BLE_ERROR_INVALID_PARAM; - } - } - - whitelistAddressesSize = whitelistIn.size; - ble_gap_addr_t* pp_addrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - - for (uint32_t i = 0; i < whitelistIn.size; ++i) { - memcpy(&whitelistAddresses[i].addr, &whitelistIn.addresses[i].address , sizeof(whitelistAddresses[0].addr)); - whitelistAddresses[i].addr_type = static_cast (whitelistIn.addresses[i].type); - pp_addrs[i] = &whitelistAddresses[i]; - } - - ble_gap_addr_t** addresses_list_ptr = (whitelistIn.size == 0) ? NULL : pp_addrs; - - uint32_t err = sd_ble_gap_whitelist_set(addresses_list_ptr, whitelistAddressesSize); - - switch(err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - - case BLE_ERROR_GAP_WHITELIST_IN_USE: - return BLE_ERROR_INVALID_STATE; - - case NRF_ERROR_INVALID_ADDR: - case BLE_ERROR_GAP_INVALID_BLE_ADDR: - case NRF_ERROR_DATA_SIZE: - return BLE_ERROR_INVALID_PARAM; - - default: - return BLE_ERROR_UNSPECIFIED; - } -} - -/**************************************************************************/ -/*! - @brief Set the advertising policy filter mode that will be used in - the next call to startAdvertising(). - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) -{ - advertisingPolicyMode = mode; - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the scanning policy filter mode that will be used in - the next call to startAdvertising(). - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) -{ - scanningPolicyMode = mode; - - return BLE_ERROR_NONE; -} - -/**************************************************************************/ -/*! - @brief Set the initiator policy filter mode that will be used in - the next call to startAdvertising() - - @returns \ref ble_errror_t - - @retval BLE_ERROR_NONE - Everything executed properly. - - BLE_ERROR_NOT_IMPLEMENTED - This feature is currently note implemented. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -ble_error_t nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) -{ - return BLE_ERROR_NOT_IMPLEMENTED; -} - -/**************************************************************************/ -/*! - @brief Get the current advertising policy filter mode. - - @returns The advertising policy filter mode. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const -{ - return advertisingPolicyMode; -} - -/**************************************************************************/ -/*! - @brief Get the current scanning policy filter mode. - - @returns The scanning policy filter mode. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const -{ - return scanningPolicyMode; -} - -/**************************************************************************/ -/*! - @brief Get the current initiator policy filter mode. - - @returns The initiator policy filter mode. - - @note Currently initiator filtering using the whitelist is not - implemented in this module. - - @section EXAMPLE - - @code - - @endcode -*/ -/**************************************************************************/ -Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const -{ - return Gap::INIT_POLICY_IGNORE_WHITELIST; -} - -ble_error_t nRF5xGap::enablePrivacy(bool enable_privacy) -{ - if (enable_privacy == _privacy_enabled) { - return BLE_ERROR_NONE; - } - - ble_error_t err = BLE_ERROR_UNSPECIFIED; - if (enable_privacy == false) { - err = setAddress(_non_private_address_type, _non_private_address); - } else { - err = getAddress(&_non_private_address_type, _non_private_address); - } - - if (err) { - return err; - } - -#if (NRF_SD_BLE_API_VERSION > 2) - ble_gap_privacy_params_t privacy_config = { 0 }; - if (sd_ble_gap_privacy_get(&privacy_config)) { - return BLE_ERROR_UNSPECIFIED; - } - - privacy_config.privacy_mode = enable_privacy ? - BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY : - BLE_GAP_PRIVACY_MODE_OFF; - if (sd_ble_gap_privacy_set(&privacy_config)) { - return BLE_ERROR_UNSPECIFIED; - } -#endif - - _privacy_enabled = enable_privacy; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setPeripheralPrivacyConfiguration( - const PeripheralPrivacyConfiguration_t *configuration -) { - _peripheral_privacy_configuration = *configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::getPeripheralPrivacyConfiguration( - PeripheralPrivacyConfiguration_t *configuration -) { - *configuration = _peripheral_privacy_configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::setCentralPrivacyConfiguration( - const CentralPrivacyConfiguration_t *configuration -) { - _central_privacy_configuration = *configuration; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xGap::getCentralPrivacyConfiguration( - CentralPrivacyConfiguration_t *configuration -) { - *configuration = _central_privacy_configuration; - return BLE_ERROR_NONE; -} - -void nRF5xGap::set_connection_event_handler( - ConnectionEventMonitor::EventHandler* connection_event_handler -) { - _connection_event_handler = connection_event_handler; -} - -void nRF5xGap::processDisconnectionEvent( - Handle_t handle, - DisconnectionReason_t reason -) { - release_connection_role(handle); - - if (_connection_event_handler) { - _connection_event_handler->on_disconnected( - handle, - reason - ); - } - - ::Gap::processDisconnectionEvent( - handle, - reason - ); -} - -ble_error_t nRF5xGap::update_identities_list(bool resolution_enabled) -{ - uint32_t err; - - if (resolution_enabled) { - ArrayView entries = get_sm().get_resolving_list(); - size_t limit = std::min( - entries.size(), (size_t) YOTTA_CFG_IRK_TABLE_MAX_SIZE - ); - ble_gap_id_key_t* id_keys_pp[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - - for (size_t i = 0; i < limit; ++i) { - id_keys_pp[i] = &entries[i]; - } - - err = sd_ble_gap_device_identities_set( - limit ? id_keys_pp : NULL, - /* use the local IRK for all devices */ NULL, - limit - ); - } else { - err = sd_ble_gap_device_identities_set( - NULL, - /* use the local IRK for all devices */ NULL, - 0 - ); - } - - return err ? BLE_ERROR_INVALID_STATE : BLE_ERROR_NONE; -} - -void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t& evt) { - // set the new connection handle as the _default_ handle in gap - setConnectionHandle(handle); - - // add the connection and the role of the device in the local table - allocate_connection_role(handle, static_cast(evt.role)); - - // deal with own address - LegacyAddressType_t own_addr_type; - ble::address_t own_address; - const uint8_t* own_resolvable_address = NULL; - -#if (NRF_SD_BLE_API_VERSION <= 2) - if (evt.own_addr.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) { - own_addr_type = AddressType::PUBLIC; - } else { - own_addr_type = AddressType::RANDOM; - } - memcpy(own_address, evt.own_addr.addr, sizeof(own_address)); -#else - getAddress(&own_addr_type, own_address.data()); - if (_privacy_enabled) { - own_addr_type = LegacyAddressType::RANDOM_PRIVATE_RESOLVABLE; - } -#endif - -#if (NRF_SD_BLE_API_VERSION <= 2) - bool private_peer_known = evt.irk_match; -#else - bool private_peer_known = evt.peer_addr.addr_id_peer; -#endif - - // Filter out private address non resolved if the its required by the - // resolution policy - if (_privacy_enabled && - evt.role == BLE_GAP_ROLE_PERIPH && - _peripheral_privacy_configuration.resolution_strategy == PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && - private_peer_known == false && - get_sm().get_resolving_list().size() > 0 - ) { - // FIXME: should use BLE_HCI_AUTHENTICATION_FAILURE; not possible - // with the softdevice ... - sd_ble_gap_disconnect(handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); - return; - } - - // deal with the peer address: If privacy is enabled then the softdevice - // indicates if the address has been resolved or not. If the address has - // been resolved then the identity address should be passed to the application. - // Depending on the privacy chosen by the application, connection request - // from privacy enabled peers may trigger a disconnection, the pairing procedure - // or the authentication procedure. - peer_address_type_t peer_addr_type = convert_nordic_address( - private_peer_known, - evt.peer_addr.addr_type - ); - - // NOTE: when privacy is enabled, the only address returned is the resolved - // address. - const uint8_t* peer_address = evt.peer_addr.addr; - const uint8_t* peer_resolvable_address = NULL; - - // notify internal event handler before applying the resolution strategy - if (_connection_event_handler) { - _connection_event_handler->on_connected( - handle, - static_cast(evt.role), - peer_addr_type, - peer_address, - own_addr_type, - own_address.data(), - reinterpret_cast(&(evt.conn_params)) - ); - } - - // Apply authentication strategy before application notification - if (_privacy_enabled && - !private_peer_known && - evt.role == BLE_GAP_ROLE_PERIPH && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - ) { - switch (_peripheral_privacy_configuration.resolution_strategy) { - case PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE: - nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getSecurityManager().requestAuthentication(handle); - break; - - case PeripheralPrivacyConfiguration_t::PERFORM_AUTHENTICATION_PROCEDURE: - // FIXME: lookup secure DB to know what to do. - break; - - default: - break; - } - } - - processConnectionEvent( - handle, - static_cast(evt.role), - peer_addr_type, - peer_address, - own_addr_type, - own_address.data(), - reinterpret_cast(&(evt.conn_params)), - peer_resolvable_address, - own_resolvable_address - ); -} - -void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { - bool peer_address_resolved = evt.peer_addr.addr_id_peer; - - if (_privacy_enabled && - evt.peer_addr.addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE && - peer_address_resolved == false && - get_sm().get_resolving_list().size() > 0 && - _central_privacy_configuration.resolution_strategy == CentralPrivacyConfiguration_t::RESOLVE_AND_FILTER - ) { - return; - } - - peer_address_type_t peer_addr_type = convert_nordic_address( - evt.peer_addr.addr_id_peer, - evt.peer_addr.addr_type - ); - const uint8_t* peer_address = evt.peer_addr.addr; - - processAdvertisementReport( - peer_address, - evt.rssi, - evt.scan_rsp, - static_cast(evt.type), - evt.dlen, - evt.data, - peer_addr_type - ); -} - -ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated && c.connection == connection) { - role = c.is_peripheral ? PERIPHERAL : CENTRAL; - return BLE_ERROR_NONE; - } - } - - return BLE_ERROR_INVALID_PARAM; -} - -void nRF5xGap::allocate_connection_role( - ble::connection_handle_t connection, - Role_t role -) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated == false) { - c.connection = connection; - c.is_peripheral = (role == Gap::PERIPHERAL); - c.is_allocated = true; - return; - } - } -} -void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { - for (size_t i = 0; i < max_connections_count; ++i) { - connection_role_t& c = _connections_role[i]; - if (c.is_allocated && c.connection == connection) { - c.is_allocated = false; - return; - } - } -} - -void nRF5xGap::release_all_connections_role() { - for (size_t i = 0; i < max_connections_count; ++i) { - _connections_role[i].is_allocated = false; - } -} -void nRF5xGap::on_phy_update( - Handle_t connection, - const ble_gap_evt_phy_update_t& evt -) { - if (!_eventHandler) { - return; - } - - ble_error_t status; - switch (evt.status) { - case BLE_HCI_STATUS_CODE_SUCCESS: - status = BLE_ERROR_NONE; - break; - - case BLE_HCI_UNSUPPORTED_REMOTE_FEATURE: - status = BLE_ERROR_OPERATION_NOT_PERMITTED; - break; - - case BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION: - case BLE_HCI_DIFFERENT_TRANSACTION_COLLISION: - status = BLE_ERROR_INVALID_STATE; - break; - - case BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS: - status = BLE_ERROR_INVALID_PARAM; - break; - - default: - status = BLE_ERROR_UNSPECIFIED; - break; - } - - _eventHandler->onPhyUpdateComplete( - status, - connection, - Phy_t::LE_1M, - Phy_t::LE_1M - ); -} - -#ifndef S140 -void nRF5xGap::on_phy_update_request( - Handle_t connection, - const ble_gap_evt_phy_update_request_t& evt -) { - ble_gap_phys_t phys = { - _preferred_tx_phys & evt.peer_preferred_phys.tx_phys, - _preferred_rx_phys & evt.peer_preferred_phys.rx_phys - }; - - if (!phys.tx_phys) { - phys.tx_phys = BLE_GAP_PHY_AUTO; - } - - if (!phys.rx_phys) { - phys.rx_phys = BLE_GAP_PHY_AUTO; - } - - sd_ble_gap_phy_update(connection, &phys); -} -#endif - - - diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp deleted file mode 100644 index a1d6b1e7e9..0000000000 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xPalSecurityManager.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "nRF5xPalSecurityManager.h" -#include "nRF5xn.h" -#include "ble/Gap.h" -#include "nRF5xGap.h" -#include "nrf_ble.h" -#include "ble_gap.h" -#include "nrf_soc.h" -#include "nrf_error.h" - -namespace ble { -namespace pal { -namespace vendor { -namespace nordic { - -namespace { -static ble_error_t convert_sd_error(uint32_t err) { - switch (err) { - case NRF_SUCCESS: - return BLE_ERROR_NONE; - case NRF_ERROR_INVALID_ADDR: - case NRF_ERROR_INVALID_PARAM: - case BLE_ERROR_INVALID_CONN_HANDLE: - return BLE_ERROR_INVALID_PARAM; - case NRF_ERROR_INVALID_STATE: - case BLE_ERROR_INVALID_ROLE: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_NOT_SUPPORTED: - return BLE_ERROR_NOT_IMPLEMENTED; - case NRF_ERROR_BUSY: - return BLE_STACK_BUSY; - case NRF_ERROR_TIMEOUT: - return BLE_ERROR_INVALID_STATE; - case NRF_ERROR_NO_MEM: - return BLE_ERROR_NO_MEM; - default: - return BLE_ERROR_UNSPECIFIED; - } -} -} - -enum pairing_role_t { - PAIRING_INITIATOR, - PAIRING_RESPONDER -}; - -struct nRF5xSecurityManager::pairing_control_block_t { - pairing_control_block_t* next; - connection_handle_t connection; - pairing_role_t role; - - // flags of the key present - KeyDistribution initiator_dist; - KeyDistribution responder_dist; - - // own keys - ble_gap_enc_key_t own_enc_key; - ble_gap_id_key_t own_id_key; - ble_gap_sign_info_t own_sign_key; - ble_gap_lesc_p256_pk_t own_pk; - - // peer keys - ble_gap_enc_key_t peer_enc_key; - ble_gap_id_key_t peer_id_key; - ble_gap_sign_info_t peer_sign_key; - ble_gap_lesc_p256_pk_t peer_pk; - - // flag required to help DHKey computation/process; should be removed with - // later versions of the softdevice - uint8_t own_oob:1; - uint8_t peer_oob:1; -}; - -nRF5xSecurityManager::nRF5xSecurityManager() - : ::ble::pal::SecurityManager(), - _sign_counter(), - _io_capability(io_capability_t::NO_INPUT_NO_OUTPUT), - _min_encryption_key_size(7), - _max_encryption_key_size(16), - _control_blocks(NULL), - resolving_list_entry_count(0) -{ - -} - -nRF5xSecurityManager::~nRF5xSecurityManager() -{ - terminate(); -} - -//////////////////////////////////////////////////////////////////////////// -// SM lifecycle management -// - -ble_error_t nRF5xSecurityManager::initialize() -{ -#if defined(MBEDTLS_ECDH_C) - if (_crypto.generate_keys( - make_ArrayView(X), - make_ArrayView(Y), - make_ArrayView(secret) - )) { - return BLE_ERROR_NONE; - } - - return BLE_ERROR_INTERNAL_STACK_FAILURE; -#endif - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::terminate() -{ - release_all_pairing_cb(); - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::reset() -{ - ble_error_t err = terminate(); - if (err) { - return err; - } - - return initialize(); -} - -//////////////////////////////////////////////////////////////////////////// -// Resolving list management -// - -// FIXME: on nordic, the irk is passed in sd_ble_gap_scan_start where whitelist -// and resolving list are all mixed up. - -uint8_t nRF5xSecurityManager::read_resolving_list_capacity() -{ - return MAX_RESOLVING_LIST_ENTRIES; -} - -ble_error_t nRF5xSecurityManager::add_device_to_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address, - const irk_t &peer_irk -) { - if (resolving_list_entry_count >= MAX_RESOLVING_LIST_ENTRIES) { - return BLE_ERROR_INVALID_STATE; - } - - ble_gap_id_key_t& entry = resolving_list[resolving_list_entry_count]; - entry.id_addr_info.addr_type = peer_identity_address_type.value(); - memcpy( - entry.id_addr_info.addr, - peer_identity_address.data(), - peer_identity_address.size() - ); - memcpy( - entry.id_info.irk, - peer_irk.data(), - peer_irk.size() - ); - - ++resolving_list_entry_count; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::remove_device_from_resolving_list( - advertising_peer_address_type_t peer_identity_address_type, - const address_t &peer_identity_address -) { - size_t entry_index; - - // first the index needs to be found - for (entry_index = 0; entry_index < resolving_list_entry_count; ++entry_index) { - ble_gap_id_key_t& entry = resolving_list[entry_index]; - if (entry.id_addr_info.addr_type == peer_identity_address_type.value() && - entry.id_addr_info.addr == peer_identity_address - ) { - break; - } - } - - if (entry_index == resolving_list_entry_count) { - return BLE_ERROR_INVALID_PARAM; - } - - // Elements after the entry can be moved in the list - for (size_t i = entry_index; i < (resolving_list_entry_count - 1); ++i) { - resolving_list[i] = resolving_list[i + 1]; - } - - --resolving_list_entry_count; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::clear_resolving_list() -{ - resolving_list_entry_count = 0; - return BLE_ERROR_NONE; -} - -ArrayView nRF5xSecurityManager::get_resolving_list() { - return ArrayView( - resolving_list, - resolving_list_entry_count - ); -} - -//////////////////////////////////////////////////////////////////////////// -// Pairing -// - - -ble_error_t nRF5xSecurityManager::send_pairing_request( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - // allocate the control block required for the procedure completion - pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_NO_MEM; - } - pairing_cb->role = PAIRING_INITIATOR; - - // override signing parameter - initiator_dist.set_signing(false); - responder_dist.set_signing(false); - - // override link parameter - initiator_dist.set_link(false); - responder_dist.set_link(false); - - ble_gap_sec_params_t security_params = make_security_params( - oob_data_flag, - authentication_requirements, - initiator_dist, - responder_dist - ); - - uint32_t err = sd_ble_gap_authenticate( - connection, - &security_params - ); - - if (err) { - release_pairing_cb(pairing_cb); - } - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::send_pairing_response( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection); - if (!pairing_cb) { - // not enough memory; try to reject the pairing request instead of - // waiting for timeout. - cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON); - return BLE_ERROR_NO_MEM; - } - pairing_cb->role = PAIRING_RESPONDER; - - // override signing parameter - initiator_dist.set_signing(false); - responder_dist.set_signing(false); - - // override link parameter - initiator_dist.set_link(false); - responder_dist.set_link(false); - - ble_gap_sec_params_t security_params = make_security_params( - oob_data_flag, - authentication_requirements, - initiator_dist, - responder_dist - ); - - ble_gap_sec_keyset_t keyset = make_keyset( - *pairing_cb, - initiator_dist, - responder_dist - ); - - uint32_t err = sd_ble_gap_sec_params_reply( - connection, - /* status */ BLE_GAP_SEC_STATUS_SUCCESS, - /* params */ &security_params, - /* keys */ &keyset - ); - - if (err) { - release_pairing_cb(pairing_cb); - } - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::cancel_pairing( - connection_handle_t connection, pairing_failure_t reason -) { - uint32_t err = 0; - - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - - // If there is no control block yet then if the local device is a central - // then we must reject the security request otherwise it is a response to - // a pairing feature exchange from a central. - if (!pairing_cb) { - ::Gap::Role_t current_role; - if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) { - return BLE_ERROR_INVALID_PARAM; - } - - if (current_role == ::Gap::PERIPHERAL) { - // response to a pairing feature request - err = sd_ble_gap_sec_params_reply( - connection, - reason.value() | 0x80, - /* sec params */ NULL, - /* keyset */ NULL - ); - } else { - // response to a peripheral security request - err = sd_ble_gap_authenticate(connection, NULL); - } - } else { - // At this point this must be a response to a key - err = sd_ble_gap_auth_key_reply( - connection, - /* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE, - /* key */ NULL - ); - } - - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Feature support -// - -ble_error_t nRF5xSecurityManager::get_secure_connections_support( - bool &enabled -) { - enabled = true; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_io_capability(io_capability_t io_capability) -{ - _io_capability = io_capability; - return BLE_ERROR_NONE; -} - -//////////////////////////////////////////////////////////////////////////// -// Security settings -// - -ble_error_t nRF5xSecurityManager::set_authentication_timeout( - connection_handle_t connection, uint16_t timeout_in_10ms -) { - ble_opt_t opt; - opt.gap_opt.auth_payload_timeout.conn_handle = connection; - opt.gap_opt.auth_payload_timeout.auth_payload_timeout = timeout_in_10ms; - uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, &opt); - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::get_authentication_timeout( - connection_handle_t connection, uint16_t &timeout_in_10ms -) { - ble_opt_t opt; - opt.gap_opt.auth_payload_timeout.conn_handle = connection; - - uint32_t err = sd_ble_opt_get(BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT, &opt); - if (err) { - return convert_sd_error(err); - } - - timeout_in_10ms = opt.gap_opt.auth_payload_timeout.auth_payload_timeout; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_encryption_key_requirements( - uint8_t min_encryption_key_size, - uint8_t max_encryption_key_size -) { - if ((min_encryption_key_size < 7) || (min_encryption_key_size > 16) || - (min_encryption_key_size > max_encryption_key_size)) { - return BLE_ERROR_INVALID_PARAM; - } - - _min_encryption_key_size = min_encryption_key_size; - _max_encryption_key_size = max_encryption_key_size; - - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::slave_security_request( - connection_handle_t connection, - AuthenticationMask authentication -) { - // In the peripheral role, only the bond, mitm, lesc and keypress fields of - // this structure are used. - ble_gap_sec_params_t security_params = { - /* bond */ authentication.get_bondable(), - /* mitm */ authentication.get_mitm(), - /* lesc */ authentication.get_secure_connections(), - /* keypress */ authentication.get_keypress_notification(), - /* remainder of the data structure is ignored */ 0 - }; - - uint32_t err = sd_ble_gap_authenticate( - connection, - &security_params - ); - - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Encryption -// - -ble_error_t nRF5xSecurityManager::enable_encryption( - connection_handle_t connection, - const ltk_t <k, - const rand_t &rand, - const ediv_t &ediv, - bool mitm -) { - ble_gap_master_id_t master_id; - memcpy(master_id.rand, rand.data(), rand.size()); - memcpy(&master_id.ediv, ediv.data(), ediv.size()); - - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = false; - enc_info.auth = mitm; - - // FIXME: how to pass the lenght of the LTK ??? - enc_info.ltk_len = ltk.size(); - - uint32_t err = sd_ble_gap_encrypt( - connection, - &master_id, - &enc_info - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::enable_encryption( - connection_handle_t connection, - const ltk_t <k, - bool mitm -) { - ble_gap_master_id_t master_id = {0}; - - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = true; - enc_info.auth = mitm; - enc_info.ltk_len = ltk.size(); - - uint32_t err = sd_ble_gap_encrypt( - connection, - &master_id, - &enc_info - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::encrypt_data( - const byte_array_t<16> &key, - encryption_block_t &data -) { - nrf_ecb_hal_data_t ecb; - memcpy(&ecb.key, key.data(), key.size()); - memcpy(&ecb.cleartext, data.data(), data.size()); - - uint32_t err = sd_ecb_block_encrypt(&ecb); - if (err) { - return convert_sd_error(err); - } - - memcpy(data.data(), &ecb.ciphertext, data.size()); - return BLE_ERROR_NONE; -} - -//////////////////////////////////////////////////////////////////////////// -// Privacy -// - -ble_error_t nRF5xSecurityManager::set_private_address_timeout( - uint16_t timeout_in_seconds -) { - ble_gap_privacy_params_t privacy_config; - - uint32_t err = sd_ble_gap_privacy_get(&privacy_config); - if (err) { - return convert_sd_error(err); - } - - privacy_config.private_addr_cycle_s = timeout_in_seconds; - err = sd_ble_gap_privacy_set(&privacy_config); - - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// Keys -// - -ble_error_t nRF5xSecurityManager::set_ltk( - connection_handle_t connection, - const ltk_t& ltk, - bool mitm, - bool secure_connections -) { - ble_gap_enc_info_t enc_info; - memcpy(enc_info.ltk, ltk.data(), ltk.size()); - enc_info.lesc = secure_connections; - enc_info.auth = mitm; - enc_info.ltk_len = ltk.size(); - - // FIXME: provide peer irk and csrk ? - uint32_t err = sd_ble_gap_sec_info_reply( - connection, - &enc_info, - /* id info */ NULL, - /* sign info */ NULL // Not supported - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_ltk_not_found( - connection_handle_t connection -) { - uint32_t err = sd_ble_gap_sec_info_reply( - connection, - NULL, - NULL, - NULL // Not supported - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_irk(const irk_t& irk) -{ - - ble_gap_privacy_params_t privacy_config; - - // get the previous config - uint32_t err = sd_ble_gap_privacy_get(&privacy_config); - if (err) { - return convert_sd_error(err); - } - - // set the new irk - memcpy(privacy_config.p_device_irk, irk.data(), irk.size()); - err = sd_ble_gap_privacy_set(&privacy_config); - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::set_csrk( - const csrk_t& csrk, - sign_count_t sign_counter -) { - _csrk = csrk; - _sign_counter = sign_counter; - return BLE_ERROR_NONE; -} - -ble_error_t nRF5xSecurityManager::set_peer_csrk( - connection_handle_t connection, - const csrk_t &csrk, - bool authenticated, - sign_count_t sign_counter -) { - return BLE_ERROR_NOT_IMPLEMENTED; -} - -ble_error_t nRF5xSecurityManager::remove_peer_csrk(connection_handle_t connection) -{ - return BLE_ERROR_NOT_IMPLEMENTED; -} -//////////////////////////////////////////////////////////////////////////// -// Authentication -// - -ble_error_t nRF5xSecurityManager::get_random_data(byte_array_t<8> &random_data) -{ - uint32_t err = sd_rand_application_vector_get( - random_data.data(), random_data.size() - ); - return convert_sd_error(err); -} - -//////////////////////////////////////////////////////////////////////////// -// MITM -// - -ble_error_t nRF5xSecurityManager::set_display_passkey(passkey_num_t passkey) -{ - PasskeyAscii passkey_ascii(passkey); - ble_opt_t sd_passkey; - sd_passkey.gap_opt.passkey.p_passkey = passkey ? passkey_ascii.value() : NULL; - uint32_t err = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &sd_passkey); - return convert_sd_error(err); -} - - -ble_error_t nRF5xSecurityManager::passkey_request_reply( - connection_handle_t connection, const passkey_num_t passkey -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - PasskeyAscii pkasc(passkey); - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - BLE_GAP_AUTH_KEY_TYPE_PASSKEY, - pkasc.value() - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::secure_connections_oob_request_reply( - connection_handle_t connection, - const oob_lesc_value_t &local_random, - const oob_lesc_value_t &peer_random, - const oob_confirm_t &peer_confirm -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - ble_gap_lesc_oob_data_t oob_own; - ble_gap_lesc_oob_data_t oob_peer; - - // is own address important ? - memcpy(oob_own.r, local_random.data(), local_random.size()); - // FIXME: What to do with local confirm ??? - - // is peer address important ? - memcpy(oob_peer.r, peer_random.data(), peer_random.size()); - memcpy(oob_peer.c, peer_confirm.data(), peer_confirm.size()); - - uint32_t err = sd_ble_gap_lesc_oob_data_set( - connection, - pairing_cb->own_oob ? &oob_own : NULL, - pairing_cb->peer_oob ? &oob_peer : NULL - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::legacy_pairing_oob_request_reply( - connection_handle_t connection, - const oob_tk_t& oob_data -) { - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - BLE_GAP_AUTH_KEY_TYPE_OOB, - oob_data.data() - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::confirmation_entered( - connection_handle_t connection, bool confirmation -) { - pairing_control_block_t* pairing_cb = get_pairing_cb(connection); - if (!pairing_cb) { - return BLE_ERROR_INVALID_STATE; - } - - uint32_t err = sd_ble_gap_auth_key_reply( - connection, - confirmation ? BLE_GAP_AUTH_KEY_TYPE_PASSKEY : BLE_GAP_AUTH_KEY_TYPE_NONE, - NULL - ); - - return convert_sd_error(err); -} - -ble_error_t nRF5xSecurityManager::send_keypress_notification( - connection_handle_t connection, Keypress_t keypress -) { - uint32_t err = sd_ble_gap_keypress_notify( - connection, - static_cast(keypress) - ); - return convert_sd_error(err); -} - - -ble_error_t nRF5xSecurityManager::generate_secure_connections_oob() -{ -#if defined(MBEDTLS_ECDH_C) - ble_gap_lesc_p256_pk_t own_secret; - ble_gap_lesc_oob_data_t oob_data; - - memcpy(own_secret.pk, secret.data(), secret.size()); - - uint32_t err = sd_ble_gap_lesc_oob_data_get( - BLE_CONN_HANDLE_INVALID, - &own_secret, - &oob_data - ); - - if (!err) { - get_event_handler()->on_secure_connections_oob_generated( - oob_data.r, - oob_data.c - ); - } - - return convert_sd_error(err); -#endif - return BLE_ERROR_NOT_IMPLEMENTED; -} - -nRF5xSecurityManager& nRF5xSecurityManager::get_security_manager() -{ - static nRF5xSecurityManager _security_manager; - return _security_manager; -} - -/** - * EDIV and Rand are invalid if both are zero - */ -bool is_ediv_rand_valid(const uint16_t ediv, const uint8_t* rand) -{ - for (int i = 0; i < BLE_GAP_SEC_RAND_LEN; ++i) { - if (rand[i]) { - return true; - } - } - - if (ediv != 0) { - return true; - } - - return false; -} - -bool nRF5xSecurityManager::sm_handler(const ble_evt_t *evt) -{ - nRF5xSecurityManager& self = nRF5xSecurityManager::get_security_manager(); - SecurityManager::EventHandler* handler = self.get_event_handler(); - - if ((evt == NULL) || (handler == NULL)) { - return false; - } - - const ble_gap_evt_t& gap_evt = evt->evt.gap_evt; - uint16_t connection = gap_evt.conn_handle; - pairing_control_block_t* pairing_cb = self.get_pairing_cb(connection); - - switch (evt->header.evt_id) { - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - const ble_gap_sec_params_t& params = - gap_evt.params.sec_params_request.peer_params; - - KeyDistribution initiator_dist( - params.kdist_peer.enc, - params.kdist_peer.id, - params.kdist_peer.sign, - params.kdist_peer.link - ); - - KeyDistribution responder_dist( - params.kdist_own.enc, - params.kdist_own.id, - params.kdist_own.sign, - params.kdist_own.link - ); - - if (pairing_cb && pairing_cb->role == PAIRING_INITIATOR) { - // override signing parameter - initiator_dist.set_signing(false); - responder_dist.set_signing(false); - - // override link parameter - initiator_dist.set_link(false); - responder_dist.set_link(false); - - // when this event is received by an initiator, it should not be - // forwarded via the handler; this is not a behaviour expected - // by the bluetooth standard ... - ble_gap_sec_keyset_t keyset = make_keyset( - *pairing_cb, - initiator_dist, - responder_dist - ); - uint32_t err = sd_ble_gap_sec_params_reply( - connection, - /* status */ BLE_GAP_SEC_STATUS_SUCCESS, - /* params */ NULL, - /* keys ... */ &keyset - ); - - // in case of error; release the pairing control block and signal - // it to the event handler - if (err) { - release_pairing_cb(pairing_cb); - handler->on_pairing_error( - connection, - pairing_failure_t::UNSPECIFIED_REASON - ); - } - } else { - handler->on_pairing_request( - connection, - params.oob, - AuthenticationMask( - params.bond, - params.mitm, - params.lesc, - params.keypress - ), - initiator_dist, - responder_dist - ); - } - return true; - } - - case BLE_GAP_EVT_SEC_INFO_REQUEST: { - const ble_gap_evt_sec_info_request_t& req = - gap_evt.params.sec_info_request; - - if (is_ediv_rand_valid(req.master_id.ediv, req.master_id.rand)) { - handler->on_ltk_request( - connection, - ediv_t((uint8_t*)(&req.master_id.ediv)), - rand_t(req.master_id.rand) - ); - } else { - /* no valid EDIV and Rand - * request ltk generated with secure connection */ - handler->on_ltk_request(connection); - } - - return true; - } - - case BLE_GAP_EVT_PASSKEY_DISPLAY: { - const ble_gap_evt_passkey_display_t& req = - gap_evt.params.passkey_display; - - if (req.match_request == 0) { - handler->on_passkey_display( - connection, - PasskeyAscii::to_num(req.passkey) - ); - } else { - handler->on_passkey_display( - connection, - PasskeyAscii::to_num(req.passkey) - ); - handler->on_confirmation_request(connection); - } - - return true; - } - - case BLE_GAP_EVT_KEY_PRESSED: { - handler->on_keypress_notification( - connection, - (Keypress_t)gap_evt.params.key_pressed.kp_not - ); - return true; - } - - case BLE_GAP_EVT_AUTH_KEY_REQUEST: { - uint8_t key_type = gap_evt.params.auth_key_request.key_type; - - switch (key_type) { - case BLE_GAP_AUTH_KEY_TYPE_NONE: // Illegal - break; - - case BLE_GAP_AUTH_KEY_TYPE_PASSKEY: - handler->on_passkey_request(connection); - break; - - case BLE_GAP_AUTH_KEY_TYPE_OOB: - handler->on_legacy_pairing_oob_request(connection); - break; - } - - return true; - } - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: { -#if defined(MBEDTLS_ECDH_C) - const ble_gap_evt_lesc_dhkey_request_t& dhkey_request = - gap_evt.params.lesc_dhkey_request; - - static const size_t key_size = public_key_coord_t::size_; - ble_gap_lesc_dhkey_t shared_secret; - - _crypto.generate_shared_secret( - make_const_ArrayView(dhkey_request.p_pk_peer->pk), - make_const_ArrayView(dhkey_request.p_pk_peer->pk + key_size), - make_const_ArrayView(secret), - shared_secret.key - ); - - sd_ble_gap_lesc_dhkey_reply(connection, &shared_secret); - - if (dhkey_request.oobd_req) { - handler->on_secure_connections_oob_request(connection); - } -#endif - return true; - } - - case BLE_GAP_EVT_AUTH_STATUS: { - const ble_gap_evt_auth_status_t& status = gap_evt.params.auth_status; - - switch (status.auth_status) { - // NOTE: pairing_cb must be valid if this event has been - // received as it is being allocated earlier and release - // in this block - // The memory is released before the last call to the event handler - // to free the heap a bit before subsequent allocation with user - // code. - case BLE_GAP_SEC_STATUS_SUCCESS: { - KeyDistribution own_dist; - KeyDistribution peer_dist; - - if (pairing_cb->role == PAIRING_INITIATOR) { - own_dist = pairing_cb->initiator_dist; - peer_dist = pairing_cb->responder_dist; - } else { - own_dist = pairing_cb->responder_dist; - peer_dist = pairing_cb->initiator_dist; - } - - if (is_ediv_rand_valid( - pairing_cb->own_enc_key.master_id.ediv, - pairing_cb->own_enc_key.master_id.rand - ) - ) { - if (own_dist.get_encryption()) { - handler->on_keys_distributed_local_ltk( - connection, - ltk_t(pairing_cb->own_enc_key.enc_info.ltk) - ); - - handler->on_keys_distributed_local_ediv_rand( - connection, - ediv_t(reinterpret_cast( - &pairing_cb->own_enc_key.master_id.ediv - )), - pairing_cb->own_enc_key.master_id.rand - ); - } - - if (peer_dist.get_encryption()) { - handler->on_keys_distributed_ltk( - connection, - ltk_t(pairing_cb->peer_enc_key.enc_info.ltk) - ); - - handler->on_keys_distributed_ediv_rand( - connection, - ediv_t(reinterpret_cast( - &pairing_cb->peer_enc_key.master_id.ediv - )), - pairing_cb->peer_enc_key.master_id.rand - ); - } - } else { - /* no valid EDIV and Rand meaning this is a - * Secure Connections key */ - handler->on_secure_connections_ltk_generated( - connection, - ltk_t(pairing_cb->own_enc_key.enc_info.ltk) - ); - } - - if (peer_dist.get_identity()) { - handler->on_keys_distributed_irk( - connection, - irk_t(pairing_cb->peer_id_key.id_info.irk) - ); - - advertising_peer_address_type_t - address_type(advertising_peer_address_type_t::PUBLIC); - - if (pairing_cb->peer_id_key.id_addr_info.addr_type) { - address_type = advertising_peer_address_type_t::RANDOM; - } - - handler->on_keys_distributed_bdaddr( - connection, - address_type, - ble::address_t(pairing_cb->peer_id_key.id_addr_info.addr) - ); - } - - if (peer_dist.get_signing()) { - handler->on_keys_distributed_csrk( - connection, - pairing_cb->peer_sign_key.csrk - ); - } - - self.release_pairing_cb(pairing_cb); - handler->on_pairing_completed(connection); - break; - } - - case BLE_GAP_SEC_STATUS_TIMEOUT: - if (!pairing_cb) { - // Note: if pairing_cb does not exist then the timeout; - // is caused by a security request as the paiting_cb is - // created when the module receive the pairing request. - handler->on_link_encryption_request_timed_out(connection); - } else { - self.release_pairing_cb(pairing_cb); - handler->on_pairing_timed_out(connection); - } - break; - - case BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED: - case BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE: - case BLE_GAP_SEC_STATUS_AUTH_REQ: - case BLE_GAP_SEC_STATUS_CONFIRM_VALUE: - case BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP: - case BLE_GAP_SEC_STATUS_ENC_KEY_SIZE: - case BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED: - case BLE_GAP_SEC_STATUS_UNSPECIFIED: - case BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS: - case BLE_GAP_SEC_STATUS_INVALID_PARAMS: - case BLE_GAP_SEC_STATUS_DHKEY_FAILURE: - case BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE: - case BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG: - case BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED: - self.release_pairing_cb(pairing_cb); - handler->on_pairing_error( - connection, - (pairing_failure_t::type) (status.auth_status & 0xF) - ); - break; - - default: - self.release_pairing_cb(pairing_cb); - break; - } - - return true; - } - - case BLE_GAP_EVT_CONN_SEC_UPDATE: { - const ble_gap_evt_conn_sec_update_t& req = - gap_evt.params.conn_sec_update; - - if((req.conn_sec.sec_mode.sm == 1) && (req.conn_sec.sec_mode.lv >= 2)) { - handler->on_link_encryption_result( - connection, link_encryption_t::ENCRYPTED - ); - } else { - handler->on_link_encryption_result( - connection, link_encryption_t::NOT_ENCRYPTED - ); - } - return true; - } - - case BLE_GAP_EVT_TIMEOUT: { - switch (gap_evt.params.timeout.src) { - case BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD: - handler->on_valid_mic_timeout(connection); - return true; - - default: - return false; - } - return false; - } - - case BLE_GAP_EVT_SEC_REQUEST: { - const ble_gap_evt_sec_request_t& req = gap_evt.params.sec_request; - handler->on_slave_security_request( - connection, - AuthenticationMask(req.bond, req.mitm, req.lesc, req.keypress) - ); - return true; - } - - default: - return false; - } -} - -ble_gap_sec_params_t nRF5xSecurityManager::make_security_params( - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - ble_gap_sec_params_t security_params = { - /* bond */ authentication_requirements.get_bondable(), - /* mitm */ authentication_requirements.get_mitm(), - /* lesc */ authentication_requirements.get_secure_connections(), - /* keypress */ authentication_requirements.get_keypress_notification(), - /* io_caps */ _io_capability.value(), - /* oob */ oob_data_flag, - /* min_key_size */ _min_encryption_key_size, - /* max_key_size */ _max_encryption_key_size, - /* kdist_periph */ { - /* enc */ responder_dist.get_encryption(), - /* id */ responder_dist.get_identity(), - /* sign */ responder_dist.get_signing(), - /* link */ responder_dist.get_link() - }, - /* kdist_central */ { - /* enc */ initiator_dist.get_encryption(), - /* id */ initiator_dist.get_identity(), - /* sign */ initiator_dist.get_signing(), - /* link */ initiator_dist.get_link() - } - }; - return security_params; -} - -ble_gap_sec_keyset_t nRF5xSecurityManager::make_keyset( - pairing_control_block_t& pairing_cb, - KeyDistribution initiator_dist, - KeyDistribution responder_dist -) { - pairing_cb.initiator_dist = initiator_dist; - pairing_cb.responder_dist = responder_dist; - - ble_gap_sec_keyset_t keyset = { - /* keys_own */ { - &pairing_cb.own_enc_key, - &pairing_cb.own_id_key, - &pairing_cb.own_sign_key, - &pairing_cb.own_pk - }, - /* keys_peer */ { - &pairing_cb.peer_enc_key, - &pairing_cb.peer_id_key, - &pairing_cb.peer_sign_key, - &pairing_cb.peer_pk - } - }; - - // copy csrk if necessary - if (keyset.keys_own.p_sign_key) { - memcpy(keyset.keys_own.p_sign_key->csrk, _csrk.data(), _csrk.size()); - } - - // copy public keys used -#if defined(MBEDTLS_ECDH_C) - memcpy(pairing_cb.own_pk.pk, X.data(), X.size()); - memcpy(pairing_cb.own_pk.pk + X.size(), Y.data(), Y.size()); -#endif - return keyset; -} - -nRF5xSecurityManager::pairing_control_block_t* -nRF5xSecurityManager::allocate_pairing_cb(connection_handle_t connection) -{ - pairing_control_block_t* pairing_cb = - new (std::nothrow) pairing_control_block_t(); - if (pairing_cb) { - pairing_cb->next = _control_blocks; - _control_blocks = pairing_cb; - } - return pairing_cb; -} - -void nRF5xSecurityManager::release_pairing_cb(pairing_control_block_t* pairing_cb) -{ - if (pairing_cb == _control_blocks) { - _control_blocks = _control_blocks->next; - delete pairing_cb; - } else { - pairing_control_block_t* it = _control_blocks; - while (it->next) { - if (it->next == pairing_cb) { - it->next = pairing_cb->next; - delete pairing_cb; - return; - } - it = it->next; - } - } -} - -nRF5xSecurityManager::pairing_control_block_t* -nRF5xSecurityManager::get_pairing_cb(connection_handle_t connection) -{ - pairing_control_block_t* pcb = _control_blocks; - while (pcb) { - if (pcb->connection == connection) { - return pcb; - } - pcb = pcb->next; - } - - return NULL; -} - -void nRF5xSecurityManager::release_all_pairing_cb() -{ - while(_control_blocks) { - release_pairing_cb(_control_blocks); - } -} - -} // nordic -} // vendor -} // pal -} // ble -