diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle.cpp index cbd8d33051..afe6c77d8f 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle.cpp @@ -30,9 +30,23 @@ #include "ble/GapEvents.h" #include "nRF5xn.h" +#ifdef S110 + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 1 +#elif defined(S130) || defined(S132) + #define IS_LEGACY_DEVICE_MANAGER_ENABLED 0 +#endif + extern "C" { -#include "pstorage.h" -#include "device_manager.h" +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) + #include "pstorage.h" + #include "device_manager.h" +#else + #include "fstorage.h" + #include "fds.h" + #include "peer_manager.h" + #include "ble_conn_state.h" +#endif + #include "softdevice_handler.h" #include "ble_stack_handler_types.h" } @@ -70,7 +84,12 @@ static void btle_handler(ble_evt_t *p_ble_evt); static void sys_evt_dispatch(uint32_t sys_evt) { +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) pstorage_sys_event_handler(sys_evt); +#else + // Forward Softdevice events to the fstorage module + fs_sys_event_handler(sys_evt); +#endif } /** @@ -160,7 +179,16 @@ static void btle_handler(ble_evt_t *p_ble_evt) ble_conn_params_on_ble_evt(p_ble_evt); #endif +#if (IS_LEGACY_DEVICE_MANAGER_ENABLED) dm_ble_evt_handler(p_ble_evt); +#else + // Forward BLE events to the Connection State module. + // This must be called before any event handler that uses this module. + ble_conn_state_on_ble_evt(p_ble_evt); + + // Forward BLE events to the Peer Manager + pm_on_ble_evt(p_ble_evt); +#endif #if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110) bleGattcEventHandler(p_ble_evt); diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_discovery.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_discovery.cpp index e6fb30e613..0b6b1d6a9c 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_discovery.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_discovery.cpp @@ -23,7 +23,6 @@ void bleGattcEventHandler(const ble_evt_t *p_ble_evt) { nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); - nRF5xGap &gap = (nRF5xGap &) ble.getGap(); nRF5xGattClient &gattClient = (nRF5xGattClient &) ble.getGattClient(); nRF5xServiceDiscovery &sdSingleton = gattClient.discovery(); nRF5xCharacteristicDescriptorDiscoverer &characteristicDescriptorDiscoverer = diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security.cpp index e7f176cad3..389c9b5c4c 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#if defined(S110) #include "btle.h" #include "nRF5xn.h" @@ -323,3 +323,4 @@ btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address /* Calculate the hash and store it in the top half of the address */ ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr); } +#endif diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security_pm.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security_pm.cpp new file mode 100644 index 0000000000..cdc53ac084 --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/btle/btle_security_pm.cpp @@ -0,0 +1,419 @@ +/* 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. + */ + +#if defined(S130) || defined(S132) +#include "btle.h" + +#include "nRF5xn.h" + +extern "C" { +#include "peer_manager.h" +#include "id_manager.h" +#include "fds.h" +} + +#include "btle_security.h" + +static bool initialized = false; + +static void pm_handler(pm_evt_t const *p_event); +static bool _enc_in_progress = false; // helper flag for distinguish between state of link connected and link connected in progres of encryption establishing. + +// default security parameters. Avoid "holes" between member assigments in order to compile by gcc++11. +static ble_gap_sec_params_t securityParameters = { + .bond = true, /**< Perform bonding. */ + .mitm = true, /**< Man In The Middle protection required. */ + .lesc = false, /**< Enable LE Secure Connection pairing. */ + .keypress = false, /**< Enable generation of keypress notifications. */ + .io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ + .oob = 0, /**< Out Of Band data available. */ + .min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ + .max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */ + .kdist_own = { + .enc = 0, /**< Long Term Key and Master Identification. */ + .id = 0, /**< Identity Resolving Key and Identity Address Information. */ + .sign = 0, /**< Connection Signature Resolving Key. */ + .link = 0 /**< Derive the Link Key from the LTK. */ + }, /**< Key distribution bitmap: keys that the local device will distribute. */ + .kdist_peer = { + .enc = 1, /**< Long Term Key and Master Identification. */ + .id = 1, /**< Identity Resolving Key and Identity Address Information. */ + .sign = 0, /**< Connection Signature Resolving Key. */ + .link = 0 /**< Derive the Link Key from the LTK. */ + } /**< Key distribution bitmap: keys that the peripheral device will distribute. */ +}; + +bool +btle_hasInitializedSecurity(void) +{ + return initialized; +} + + +ble_error_t +btle_initializeSecurity(bool enableBonding, + bool requireMITM, + SecurityManager::SecurityIOCapabilities_t iocaps, + const SecurityManager::Passkey_t passkey) +{ + /* guard against multiple initializations */ + if (initialized) { + return BLE_ERROR_NONE; + } + + ret_code_t rc; + if (passkey) { + ble_opt_t opts; + opts.gap_opt.passkey.p_passkey = const_cast(passkey); + if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) { + switch (rc) { + case BLE_ERROR_INVALID_CONN_HANDLE: + case NRF_ERROR_INVALID_ADDR: + case NRF_ERROR_INVALID_PARAM: + default: + return BLE_ERROR_INVALID_PARAM; + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + case NRF_ERROR_BUSY: + return BLE_STACK_BUSY; + } + } + } + + if (pm_init() != NRF_SUCCESS) { + return BLE_ERROR_UNSPECIFIED; + } + + // update default security parameters with function call parameters + securityParameters.bond = enableBonding; + securityParameters.mitm = requireMITM; + securityParameters.io_caps = iocaps; + + if (enableBonding) { + securityParameters.kdist_own.enc = 1; + securityParameters.kdist_own.id = 1; + } else { + securityParameters.kdist_own.enc = 0; + securityParameters.kdist_own.id = 0; + } + rc = pm_sec_params_set(&securityParameters); + + if (rc == NRF_SUCCESS) { + rc = pm_register(pm_handler); + } + + switch (rc) { + case NRF_SUCCESS: + initialized = true; + return BLE_ERROR_NONE; + + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + + default: + return BLE_ERROR_UNSPECIFIED; + } + + + initialized = true; + return BLE_ERROR_NONE; +} + +ble_error_t +btle_purgeAllBondingState(void) +{ + ret_code_t rc; + + rc = pm_peers_delete(); + + switch (rc) { + case NRF_SUCCESS: + return BLE_ERROR_NONE; + + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t +btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP) +{ + ret_code_t rc; + pm_conn_sec_status_t conn_sec_status; + + rc = pm_conn_sec_status_get(connectionHandle, &conn_sec_status); + + if (rc == NRF_SUCCESS) + { + if (conn_sec_status.encrypted) { + *securityStatusP = SecurityManager::ENCRYPTED; + } + else if (conn_sec_status.connected) { + if (_enc_in_progress) { + *securityStatusP = SecurityManager::ENCRYPTION_IN_PROGRESS; + } + else { + *securityStatusP = SecurityManager::NOT_ENCRYPTED; + } + } + + return BLE_ERROR_NONE; + } + + switch (rc) { + case BLE_ERROR_INVALID_CONN_HANDLE: + return BLE_ERROR_INVALID_PARAM; + + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + + default: + return BLE_ERROR_UNSPECIFIED; + } +} + +ble_error_t +btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode) +{ + // use default and updated parameters as starting point + // and modify structure based on security mode. + ret_code_t rc; + + switch (securityMode) { + case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK: + /**< Require no protection, open link. */ + securityParameters.bond = false; + securityParameters.mitm = false; + securityParameters.kdist_own.enc = 0; + break; + + case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM: + /**< Require encryption, but no MITM protection. */ + securityParameters.bond = true; + securityParameters.mitm = false; + securityParameters.kdist_own.enc = 1; + break; + + // not yet implemented security modes + case SecurityManager::SECURITY_MODE_NO_ACCESS: + case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM: + /**< Require encryption and MITM protection. */ + case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM: + /**< Require signing or encryption, but no MITM protection. */ + case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM: + /**< Require signing or encryption, and MITM protection. */ + default: + return BLE_ERROR_NOT_IMPLEMENTED; + } + + // update security settings for given connection + + rc = pm_sec_params_set(&securityParameters); + + if (rc == NRF_SUCCESS) { + rc = pm_conn_secure(connectionHandle, false); + } + + switch (rc) { + case NRF_SUCCESS: + initialized = true; + return BLE_ERROR_NONE; + + case NRF_ERROR_INVALID_STATE: + return BLE_ERROR_INVALID_STATE; + + case NRF_ERROR_INVALID_PARAM: + return BLE_ERROR_INVALID_PARAM; + + default: + return BLE_ERROR_UNSPECIFIED; + } +} + + +void pm_handler(pm_evt_t const *p_event) +{ + nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); + nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager(); + ret_code_t err_code; + SecurityManager::SecurityMode_t resolvedSecurityMode; + + switch (p_event->evt_id) { + case PM_EVT_CONN_SEC_START: /* started */ { + const ble_gap_sec_params_t *peerParams = &securityParameters; + securityManager.processSecuritySetupInitiatedEvent(p_event->conn_handle, + peerParams->bond, + peerParams->mitm, + (SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps); + _enc_in_progress = true; + break; + } + case PM_EVT_CONN_SEC_SUCCEEDED: + // Update the rank of the peer. + if (p_event->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING) + { + err_code = pm_peer_rank_highest(p_event->peer_id); + } + + securityManager. + processSecuritySetupCompletedEvent(p_event->conn_handle, + SecurityManager::SEC_STATUS_SUCCESS);// SEC_STATUS_SUCCESS of SecurityCompletionStatus_t + + ble_gap_conn_sec_t conn_sec; + sd_ble_gap_conn_sec_get(p_event->conn_handle, &conn_sec); + + resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS; + + switch (conn_sec.sec_mode.sm) { + case 1: + switch (conn_sec.sec_mode.lv) { + case 1: + resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK; + break; + case 2: + resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM; + break; + case 3: + resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM; + break; + } + break; + case 2: + switch (conn_sec.sec_mode.lv) { + case 1: + resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM; + break; + case 2: + resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM; + break; + } + break; + } + + securityManager.processLinkSecuredEvent(p_event->conn_handle, resolvedSecurityMode); + + _enc_in_progress = false; + break; + + case PM_EVT_CONN_SEC_FAILED: + SecurityManager::SecurityCompletionStatus_t securityCompletionStatus; + + if ((uint32_t)p_event->params.conn_sec_failed.error >= PM_CONN_SEC_ERROR_BASE ) { + securityCompletionStatus = SecurityManager::SEC_STATUS_UNSPECIFIED; + } else { + securityCompletionStatus = + (SecurityManager::SecurityCompletionStatus_t)p_event->params.conn_sec_failed.error; + } + + securityManager. + processSecuritySetupCompletedEvent(p_event->conn_handle, securityCompletionStatus); + + _enc_in_progress = false; + break; + + case PM_EVT_BONDED_PEER_CONNECTED: + pm_peer_rank_highest(p_event->peer_id); + break; + + case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: + if (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE) + { + securityManager.processSecurityContextStoredEvent(p_event->conn_handle); + } + break; + + case PM_EVT_PEER_DATA_UPDATE_FAILED: + break; + + case PM_EVT_STORAGE_FULL: + // Run garbage collection on the flash. + err_code = fds_gc(); + if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) + { + // Retry. + } + else + { + APP_ERROR_CHECK(err_code); + } + break;//PM_EVT_STORAGE_FULL + + case PM_EVT_CONN_SEC_CONFIG_REQ:{ + // A connected peer (central) is trying to pair, but the Peer Manager already has a bond + // for that peer. Setting allow_repairing to false rejects the pairing request. + // If this event is ignored (pm_conn_sec_config_reply is not called in the event + // handler), the Peer Manager assumes allow_repairing to be false. + pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true}; + pm_conn_sec_config_reply(p_event->conn_handle, &conn_sec_config); + } + break;//PM_EVT_CONN_SEC_CONFIG_REQ + + default: + break; + } +} + +ble_error_t +btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) +{ + if (!btle_hasInitializedSecurity()) { + return BLE_ERROR_INITIALIZATION_INCOMPLETE; + } + ret_code_t err = pm_whitelist_create( NULL, BLE_GAP_WHITELIST_ADDR_MAX_COUNT, p_whitelist); + if (err == NRF_SUCCESS) { + return BLE_ERROR_NONE; + } else if (err == NRF_ERROR_NULL) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } else { + return BLE_ERROR_INVALID_STATE; + } +} + + +bool +btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) +{ + /* + * Use a helper function from the Nordic SDK to test whether the BLE + * address can be generated using the IRK. + */ + return im_address_resolve(p_addr, p_irk); +} + +void +btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address) +{ + /* Set type to resolvable */ + address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; + + /* + * Assign a random number to the most significant 3 bytes + * of the address. + */ + address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E; + address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F; + address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C; + + /* Calculate the hash and store it in the top half of the address */ + ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr); +} +#endif diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/ble/peer_manager/pm_buffer.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/ble/peer_manager/pm_buffer.h index 8093ad4957..55fea30d10 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/ble/peer_manager/pm_buffer.h +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/ble/peer_manager/pm_buffer.h @@ -60,10 +60,13 @@ #define PM_BUFFER_INIT(p_buffer, n_blocks, block_size, err_code) \ do \ { \ - static uint8_t buffer_memory[(n_blocks) * (block_size)]; \ + static union { \ + uint8_t u8[(n_blocks) * (block_size)]; \ + uint32_t u32[1]; /*force allign to uint32_t*/ \ + } buffer_memory; \ static uint8_t mutex_memory[MUTEX_STORAGE_SIZE(n_blocks)]; \ err_code = pm_buffer_init((p_buffer), \ - buffer_memory, \ + buffer_memory.u8, \ (n_blocks) * (block_size), \ mutex_memory, \ MUTEX_STORAGE_SIZE(n_blocks), \ diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/libraries/util/app_util_platform.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/libraries/util/app_util_platform.h index a01b26d0e7..9eb20b7e43 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/libraries/util/app_util_platform.h +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/libraries/util/app_util_platform.h @@ -111,7 +111,9 @@ typedef enum #define EXTERNAL_INT_VECTOR_OFFSET 16 /**@endcond */ -#define PACKED(TYPE) __packed TYPE +#ifndef PACKED + #define PACKED(TYPE) __packed TYPE +#endif void app_util_critical_region_enter (uint8_t *p_nested); void app_util_critical_region_exit (uint8_t nested);