From fdead9ec36966b2f5c8ef6ae083cd593da1e1fac Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Thu, 31 Dec 2015 13:51:52 +0000 Subject: [PATCH 01/10] Early whitelisting API prototype implementation --- source/nRF5xGap.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++--- source/nRF5xGap.h | 54 ++++++++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 9ec7522..67338c5 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -173,8 +173,8 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) adv_para.type = params.getAdvertisingType(); adv_para.p_peer_addr = NULL; // Undirected advertisement - adv_para.fp = BLE_GAP_ADV_FP_ANY; - adv_para.p_whitelist = NULL; + adv_para.fp = advertisingPolicyMode; + adv_para.p_whitelist = &whitelist; adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms) adv_para.timeout = params.getTimeout(); @@ -234,8 +234,8 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr, } ble_gap_scan_params_t scanParams; - scanParams.selective = 0; /**< If 1, ignore unknown devices (non whitelisted). */ - scanParams.p_whitelist = NULL; /**< Pointer to whitelist, NULL if none is given. */ + scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ + scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ 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). */ @@ -507,3 +507,65 @@ void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *co *valueArrayPP = permittedTxValues; *countP = sizeof(permittedTxValues) / sizeof(int8_t); } + +/////////////////////////WHITELISTING +int8_t nRF5xGap::getMaxWhitelistSize(void) const +{ + return YOTTA_CFG_WHITELIST_MAX_SIZE; +} + +ble_error_t nRF5xGap::getWhitelist(std::set &whitelist) const +{ + for (uint8_t i = 0; i < whitelistAddressesSize; i++) { + BLEProtocol::Address_t addr;//((BLEProtocol::AddressType_t)whitelistAddrs[i].addr_type, (BLEProtocol::AddressBytes_t) whitelistAddrs[i].addr); + addr.type = (BLEProtocol::AddressType_t) whitelistAddrs[i].addr_type; + memcpy(addr.address, whitelistAddrs[i].addr, sizeof(BLEProtocol::AddressBytes_t)); + whitelist.insert(addr); + } + return BLE_ERROR_NONE; +} + +ble_error_t nRF5xGap::setWhitelist(std::set whitelistIn) +{ + whitelistAddressesSize = 0; + for (std::set::iterator it = whitelistIn.begin(); it != whitelistIn.end(); it++) { + whitelistAddrs[whitelistAddressesSize].addr_type = it->type; + memcpy(whitelistAddrs[whitelistAddressesSize].addr, it->address, sizeof(BLEProtocol::AddressBytes_t)); + whitelistAddressesSize++; + } + whitelist.addr_count = whitelistAddressesSize; + whitelist.irk_count = whitelistIrksSize; + return BLE_ERROR_NONE; +} + +// Accessors +void nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) +{ + advertisingPolicyMode = mode; +} + +void nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) +{ + scanningPolicyMode = mode; +} + +void nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) +{ + initiatorPolicyMode = mode; +} + +Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const +{ + return advertisingPolicyMode; +} + +Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const +{ + return scanningPolicyMode; +} + +Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const +{ + return initiatorPolicyMode; +} +///////////////////////// diff --git a/source/nRF5xGap.h b/source/nRF5xGap.h index c972b1c..94a7805 100644 --- a/source/nRF5xGap.h +++ b/source/nRF5xGap.h @@ -22,6 +22,12 @@ #else #include "mbed.h" #endif +#ifndef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#elif YOTTA_CFG_WHITELIST_MAX_SIZE > BLE_GAP_WHITELIST_ADDR_MAX_COUNT + #undef YOTTA_CFG_WHITELIST_MAX_SIZE + #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT +#endif #include "ble/blecommon.h" #include "ble.h" #include "ble/GapAdvertisingParams.h" @@ -37,6 +43,8 @@ extern "C" { #include "btle_security.h" +#include + void radioNotificationStaticCallback(bool param); /**************************************************************************/ @@ -80,6 +88,20 @@ public: virtual ble_error_t reset(void); + /////////////////// WHITELISTING + virtual int8_t getMaxWhitelistSize(void) const; + virtual ble_error_t getWhitelist(std::set &whitelist) const; + virtual ble_error_t setWhitelist(std::set whitelist); + + // Accessors + virtual void setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); + virtual void setScanningPolicyMode(ScanningPolicyMode_t mode); + virtual void setInitiatorPolicyMode(InitiatorPolicyMode_t mode); + virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; + virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; + virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; + /////////////////// + virtual ble_error_t initRadioNotification(void) { if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { return BLE_ERROR_NONE; @@ -93,8 +115,8 @@ public: virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) { ble_gap_scan_params_t scanParams = { .active = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */ - .selective = 0, /**< If 1, ignore unknown devices (non whitelisted). */ - .p_whitelist = NULL, /**< Pointer to whitelist, NULL if none is given. */ + .selective = scanningPolicyMode, /**< If 1, ignore unknown devices (non whitelisted). */ + .p_whitelist = &whitelist, /**< Pointer to whitelist, NULL if none is given. */ .interval = scanningParams.getInterval(), /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ .window = scanningParams.getWindow(), /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ .timeout = scanningParams.getTimeout(), /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ @@ -117,6 +139,21 @@ public: #endif private: + /////////////////WHITELISTING + Gap::AdvertisingPolicyMode_t advertisingPolicyMode; + Gap::ScanningPolicyMode_t scanningPolicyMode; + Gap::InitiatorPolicyMode_t initiatorPolicyMode; /* Unused */ + + ble_gap_addr_t whitelistAddrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_addr_t *whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; + uint8_t whitelistAddressesSize; + ble_gap_irk_t *whitelistIrks[YOTTA_CFG_WHITELIST_MAX_SIZE]; + uint8_t whitelistIrksSize; + + ble_gap_whitelist_t whitelist; + + ///////////////// + bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ Timeout radioNotificationTimeout; @@ -206,8 +243,19 @@ private: */ friend class nRF5xn; - nRF5xGap() { + nRF5xGap() : + advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), + initiatorPolicyMode(Gap::INIT_POLICY_IGNORE_WHITELIST), + whitelistAddressesSize(0), + whitelistIrksSize(0) { m_connectionHandle = BLE_CONN_HANDLE_INVALID; + + whitelist.pp_addrs = whitelistAddresses; + for (int i = 0; i < YOTTA_CFG_WHITELIST_MAX_SIZE; i++) { + whitelistAddresses[i] = &(whitelistAddrs[i]); + } + whitelist.pp_irks = whitelistIrks; } nRF5xGap(nRF5xGap const &); From 0f76db4eed2e2074bda95cf56383f3a997492e93 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 4 Jan 2016 15:30:47 +0000 Subject: [PATCH 02/10] Add helper function to get whitelist from SD bond table --- source/btle/btle_security.cpp | 12 ++++++++++++ source/btle/btle_security.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/source/btle/btle_security.cpp b/source/btle/btle_security.cpp index ba92fe7..6f21b19 100644 --- a/source/btle/btle_security.cpp +++ b/source/btle/btle_security.cpp @@ -43,6 +43,18 @@ static ble_gap_sec_params_t securityParameters = { }, /**< Key distribution bitmap: keys that the peripheral device will distribute. */ }; +ble_error_t btle_createWhitelistFromBonds(ble_gap_whitelist_t *p_whitelist) +{ + ret_code_t err = dm_whitelist_create(&applicationInstance, 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; + } +} + ble_error_t btle_initializeSecurity(bool enableBonding, bool requireMITM, diff --git a/source/btle/btle_security.h b/source/btle/btle_security.h index b3e4b07..44d6233 100644 --- a/source/btle/btle_security.h +++ b/source/btle/btle_security.h @@ -40,6 +40,8 @@ ble_error_t btle_initializeSecurity(bool en SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE, const SecurityManager::Passkey_t passkey = NULL); +ble_error_t btle_createWhitelistFromBonds(ble_gap_whitelist_t *p_whitelist); + /** * Get the security status of a link. * From c9b6bb9bbbf2755811267bd44598b7deacc4c9de Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 10:46:11 +0000 Subject: [PATCH 03/10] Almost complete implementation of whitelisting API --- source/btle/btle_security.cpp | 15 ++- source/btle/btle_security.h | 6 +- source/nRF5xGap.cpp | 187 ++++++++++++++++++++++++++++++---- source/nRF5xGap.h | 87 +++++++--------- source/nRF5xSecurityManager.h | 14 +++ 5 files changed, 233 insertions(+), 76 deletions(-) diff --git a/source/btle/btle_security.cpp b/source/btle/btle_security.cpp index 6f21b19..74f8a2a 100644 --- a/source/btle/btle_security.cpp +++ b/source/btle/btle_security.cpp @@ -21,11 +21,13 @@ extern "C" { #include "pstorage.h" #include "device_manager.h" +#include "id_manager.h" } #include "btle_security.h" static dm_application_instance_t applicationInstance; +static bool initialized = false; static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result); // default security parameters @@ -43,7 +45,7 @@ static ble_gap_sec_params_t securityParameters = { }, /**< Key distribution bitmap: keys that the peripheral device will distribute. */ }; -ble_error_t btle_createWhitelistFromBonds(ble_gap_whitelist_t *p_whitelist) +ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) { ret_code_t err = dm_whitelist_create(&applicationInstance, p_whitelist); if (err == NRF_SUCCESS) { @@ -55,6 +57,11 @@ ble_error_t btle_createWhitelistFromBonds(ble_gap_whitelist_t *p_whitelist) } } +bool btle_hasInitializedSecurity(void) +{ + return initialized; +} + ble_error_t btle_initializeSecurity(bool enableBonding, bool requireMITM, @@ -62,7 +69,6 @@ btle_initializeSecurity(bool enableBonding, const SecurityManager::Passkey_t passkey) { /* guard against multiple initializations */ - static bool initialized = false; if (initialized) { return BLE_ERROR_NONE; } @@ -274,3 +280,8 @@ dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t ev return NRF_SUCCESS; } + +bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) +{ + return im_address_resolve(p_addr, p_irk); +} diff --git a/source/btle/btle_security.h b/source/btle/btle_security.h index 44d6233..3db36ee 100644 --- a/source/btle/btle_security.h +++ b/source/btle/btle_security.h @@ -40,7 +40,7 @@ ble_error_t btle_initializeSecurity(bool en SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE, const SecurityManager::Passkey_t passkey = NULL); -ble_error_t btle_createWhitelistFromBonds(ble_gap_whitelist_t *p_whitelist); +ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist); /** * Get the security status of a link. @@ -77,4 +77,8 @@ ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager */ ble_error_t btle_purgeAllBondingState(void); +bool btle_hasInitializedSecurity(void); + +bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk); + #endif /* _BTLE_SECURITY_H_ */ diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 67338c5..99f7d14 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -168,6 +168,18 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) return BLE_ERROR_PARAM_OUT_OF_RANGE; } + /* 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(); + if (error != BLE_ERROR_NONE) { + return error; + } + } else { + /* Reset the whitelist table to avoid any errors */ + whitelist.addr_count = 0; + whitelist.irk_count = 0; + } + /* Start Advertising */ ble_gap_adv_params_t adv_para = {0}; @@ -185,6 +197,47 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) return BLE_ERROR_NONE; } +/* 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) { + + /* 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(); + if (error != BLE_ERROR_NONE) { + return error; + } + } else { + /* Reset the whitelist table to avoid any errors */ + whitelist.addr_count = 0; + whitelist.irk_count = 0; + } + + ble_gap_scan_params_t scanParams = { + .active = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */ + .selective = scanningPolicyMode, /**< If 1, ignore unknown devices (non whitelisted). */ + .p_whitelist = &whitelist, /**< Pointer to whitelist, NULL if none is given. */ + .interval = scanningParams.getInterval(), /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + .window = scanningParams.getWindow(), /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ + .timeout = scanningParams.getTimeout(), /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ + }; + + 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 @@ -233,6 +286,18 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr, connParams.conn_sup_timeout = 600; } + /* 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(); + if (error != BLE_ERROR_NONE) { + return error; + } + } else { + /* Reset the whitelist table to avoid any errors */ + whitelist.addr_count = 0; + whitelist.irk_count = 0; + } + ble_gap_scan_params_t scanParams; scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ @@ -508,50 +573,58 @@ void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *co *countP = sizeof(permittedTxValues) / sizeof(int8_t); } -/////////////////////////WHITELISTING -int8_t nRF5xGap::getMaxWhitelistSize(void) const +uint8_t nRF5xGap::getMaxWhitelistSize(void) const { return YOTTA_CFG_WHITELIST_MAX_SIZE; } -ble_error_t nRF5xGap::getWhitelist(std::set &whitelist) const +ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const { - for (uint8_t i = 0; i < whitelistAddressesSize; i++) { - BLEProtocol::Address_t addr;//((BLEProtocol::AddressType_t)whitelistAddrs[i].addr_type, (BLEProtocol::AddressBytes_t) whitelistAddrs[i].addr); - addr.type = (BLEProtocol::AddressType_t) whitelistAddrs[i].addr_type; - memcpy(addr.address, whitelistAddrs[i].addr, sizeof(BLEProtocol::AddressBytes_t)); - whitelist.insert(addr); + uint8_t i; + for (i = 0; i < whitelistAddressesSize && i < whitelistOut.capacity; ++i) { + memcpy(&whitelistOut.addresses[i], &whitelistAddresses[i], sizeof(BLEProtocol::Address_t)); } + whitelistOut.size = i; + return BLE_ERROR_NONE; } -ble_error_t nRF5xGap::setWhitelist(std::set whitelistIn) +ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) { + if (whitelistIn.size > getMaxWhitelistSize()) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + whitelistAddressesSize = 0; - for (std::set::iterator it = whitelistIn.begin(); it != whitelistIn.end(); it++) { - whitelistAddrs[whitelistAddressesSize].addr_type = it->type; - memcpy(whitelistAddrs[whitelistAddressesSize].addr, it->address, sizeof(BLEProtocol::AddressBytes_t)); + for (uint8_t i = 0; i < whitelistIn.size; ++i) { + if (whitelistIn.addresses[i].type == BLEProtocol::AddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE) { + /* This is not allowed because it is completely meaningless */ + return BLE_ERROR_INVALID_PARAM; + } + memcpy(&whitelistAddresses[whitelistAddressesSize], &whitelistIn.addresses[i], sizeof(BLEProtocol::Address_t)); whitelistAddressesSize++; } - whitelist.addr_count = whitelistAddressesSize; - whitelist.irk_count = whitelistIrksSize; + return BLE_ERROR_NONE; } -// Accessors -void nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) +ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t mode) { advertisingPolicyMode = mode; + + return BLE_ERROR_NONE; } -void nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) +ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t mode) { scanningPolicyMode = mode; + + return BLE_ERROR_NONE; } -void nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) +ble_error_t nRF5xGap::setInitiatorPolicyMode(Gap::InitiatorPolicyMode_t mode) { - initiatorPolicyMode = mode; + return BLE_ERROR_NOT_IMPLEMENTED; } Gap::AdvertisingPolicyMode_t nRF5xGap::getAdvertisingPolicyMode(void) const @@ -566,6 +639,78 @@ Gap::ScanningPolicyMode_t nRF5xGap::getScanningPolicyMode(void) const Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const { - return initiatorPolicyMode; + return Gap::INIT_POLICY_IGNORE_WHITELIST; +} + +ble_error_t nRF5xGap::generateStackWhitelist(void) +{ + ble_gap_whitelist_t whitelistFromBondTable; + ble_gap_addr_t *addressPtr[1]; + ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + + nRF5xSecurityManager& securityManager = (nRF5xSecurityManager&) nRF5xn::Instance(0).getSecurityManager(); + + if (securityManager.hasInitialized()) { + /* We do not care about the addresses, set the count to 0 */ + whitelistFromBondTable.addr_count = 0; + /* The Nordic SDK will return a failure if we set pp_addr to NULL */ + whitelistFromBondTable.pp_addrs = addressPtr; + /* We want all the IRKs we can get because we do not know which ones match the addresses */ + whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE; + whitelistFromBondTable.pp_irks = irkPtr; + + /* Use the security manager to get the IRKs from the bond table */ + ble_error_t error = securityManager.createWhitelistFromBondTable(whitelistFromBondTable); + if (error != BLE_ERROR_NONE) { + return error; + } + } else { + /** + * If there is no security manager then we cannot access the bond table, + * so disable IRK matching + */ + whitelistFromBondTable.addr_count = 0; + whitelistFromBondTable.irk_count = 0; + } + + /** + * For every private resolvable address in the local whitelist check if + * there is an IRK for said address in the bond table and add it to the + * local IRK list. + */ + whitelist.irk_count = 0; + whitelist.addr_count = 0; + for (uint8_t i = 0; i < whitelistAddressesSize; ++i) { + if (whitelistAddresses[i].addr_type == BLEProtocol::AddressType_t::RANDOM_PRIVATE_RESOLVABLE) { + /* Test if there is a matching IRK for this private resolvable address */ + for (uint8_t j = 0; j < whitelistFromBondTable.irk_count; ++j) { + if (securityManager.matchAddressAndIrk(&whitelistAddresses[i], whitelistFromBondTable.pp_irks[j])) { + /* Found the corresponding IRK, add it to our local whitelist */ + whitelist.pp_irks[whitelist.irk_count] = whitelistFromBondTable.pp_irks[j]; + whitelist.irk_count++; + /* Make sure we do not look at this IRK again */ + if (j != whitelistFromBondTable.irk_count - 1) { + /** + * This is not the last IRK, so replace the pointer + * with the last pointer in the array + */ + whitelistFromBondTable.pp_irks[j] = + whitelistFromBondTable.pp_irks[whitelistFromBondTable.irk_count - 1]; + } + /** + * If the IRK is the last pointer in the array simply + * decrement the total IRK count + */ + whitelistFromBondTable.irk_count--; + break; + } + } + } else { + /* Include the address into the whitelist */ + whitelist.pp_addrs[whitelist.addr_count] = &whitelistAddresses[i]; + whitelist.addr_count++; + } + } + + return BLE_ERROR_NONE; } -///////////////////////// diff --git a/source/nRF5xGap.h b/source/nRF5xGap.h index 94a7805..751133b 100644 --- a/source/nRF5xGap.h +++ b/source/nRF5xGap.h @@ -28,6 +28,12 @@ #undef YOTTA_CFG_WHITELIST_MAX_SIZE #define YOTTA_CFG_WHITELIST_MAX_SIZE BLE_GAP_WHITELIST_ADDR_MAX_COUNT #endif +#ifndef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#elif YOTTA_CFG_IRK_TABLE_MAX_SIZE > BLE_GAP_WHITELIST_IRK_MAX_COUNT + #undef YOTTA_CFG_IRK_TABLE_MAX_SIZE + #define YOTTA_CFG_IRK_TABLE_MAX_SIZE BLE_GAP_WHITELIST_IRK_MAX_COUNT +#endif #include "ble/blecommon.h" #include "ble.h" #include "ble/GapAdvertisingParams.h" @@ -43,8 +49,6 @@ extern "C" { #include "btle_security.h" -#include - void radioNotificationStaticCallback(bool param); /**************************************************************************/ @@ -88,19 +92,16 @@ public: virtual ble_error_t reset(void); - /////////////////// WHITELISTING - virtual int8_t getMaxWhitelistSize(void) const; - virtual ble_error_t getWhitelist(std::set &whitelist) const; - virtual ble_error_t setWhitelist(std::set whitelist); + virtual uint8_t getMaxWhitelistSize(void) const; + virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; + virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); - // Accessors - virtual void setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); - virtual void setScanningPolicyMode(ScanningPolicyMode_t mode); - virtual void setInitiatorPolicyMode(InitiatorPolicyMode_t mode); + virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode); + virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode); + virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode); virtual Gap::AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const; virtual Gap::ScanningPolicyMode_t getScanningPolicyMode(void) const; virtual Gap::InitiatorPolicyMode_t getInitiatorPolicyMode(void) const; - /////////////////// virtual ble_error_t initRadioNotification(void) { if (ble_radio_notification_init(NRF_APP_PRIORITY_HIGH, NRF_RADIO_NOTIFICATION_DISTANCE_800US, radioNotificationStaticCallback) == NRF_SUCCESS) { @@ -112,47 +113,31 @@ public: /* 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) - virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams) { - ble_gap_scan_params_t scanParams = { - .active = scanningParams.getActiveScanning(), /**< If 1, perform active scanning (scan requests). */ - .selective = scanningPolicyMode, /**< If 1, ignore unknown devices (non whitelisted). */ - .p_whitelist = &whitelist, /**< Pointer to whitelist, NULL if none is given. */ - .interval = scanningParams.getInterval(), /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - .window = scanningParams.getWindow(), /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - .timeout = scanningParams.getTimeout(), /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - }; - - if (sd_ble_gap_scan_start(&scanParams) != NRF_SUCCESS) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - return BLE_ERROR_NONE; - } - - virtual ble_error_t stopScan(void) { - if (sd_ble_gap_scan_stop() == NRF_SUCCESS) { - return BLE_ERROR_NONE; - } - - return BLE_STACK_BUSY; - } + virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams); + virtual ble_error_t stopScan(void); #endif private: - /////////////////WHITELISTING + /* Policy modes set by the user. By default these are set to ignore the whitelist */ Gap::AdvertisingPolicyMode_t advertisingPolicyMode; Gap::ScanningPolicyMode_t scanningPolicyMode; - Gap::InitiatorPolicyMode_t initiatorPolicyMode; /* Unused */ - ble_gap_addr_t whitelistAddrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_addr_t *whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; - uint8_t whitelistAddressesSize; - ble_gap_irk_t *whitelistIrks[YOTTA_CFG_WHITELIST_MAX_SIZE]; - uint8_t whitelistIrksSize; + /* Internal representation of a whitelist */ + uint8_t whitelistAddressesSize; + ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; + ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; + /* Structure used by the SoftDevice to represent a whitelist together with IRK table */ ble_gap_whitelist_t whitelist; - ///////////////// + /* + * An internal function used to populate the ble_gap_whitelist_t that will be used by + * the SoftDevice for filtering requests. This function is needed because for the BLE + * API the whitelist is just a collection of keys, but for the stack it also includes + * the IRK table. + */ + ble_error_t generateStackWhitelist(void); bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ Timeout radioNotificationTimeout; @@ -245,17 +230,15 @@ private: nRF5xGap() : advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), - scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), - initiatorPolicyMode(Gap::INIT_POLICY_IGNORE_WHITELIST), - whitelistAddressesSize(0), - whitelistIrksSize(0) { + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST) { m_connectionHandle = BLE_CONN_HANDLE_INVALID; - whitelist.pp_addrs = whitelistAddresses; - for (int i = 0; i < YOTTA_CFG_WHITELIST_MAX_SIZE; i++) { - whitelistAddresses[i] = &(whitelistAddrs[i]); - } - whitelist.pp_irks = whitelistIrks; + /* Reset the whitelist */ + whitelist.addr_count = 0; + whitelist.irk_count = 0; + whitelist.pp_irks = whitelistIrkPtrs; + whitelist.pp_addrs = whitelistAddressPtrs; + whitelistAddressesSize = 0; } nRF5xGap(nRF5xGap const &); diff --git a/source/nRF5xSecurityManager.h b/source/nRF5xSecurityManager.h index 4c30841..2e842b6 100644 --- a/source/nRF5xSecurityManager.h +++ b/source/nRF5xSecurityManager.h @@ -19,6 +19,7 @@ #include +#include "nRF5xGap.h" #include "ble/SecurityManager.h" #include "btle_security.h" @@ -60,6 +61,10 @@ public: return BLE_ERROR_NONE; } + bool hasInitialized(void) const { + return btle_hasInitializedSecurity(); + } + public: /* * Allow instantiation from nRF5xn when required. @@ -73,6 +78,15 @@ public: private: nRF5xSecurityManager(const nRF5xSecurityManager &); const nRF5xSecurityManager& operator=(const nRF5xSecurityManager &); + + ble_error_t createWhitelistFromBondTable(ble_gap_whitelist_t &whitelistFromBondTable) const { + return btle_createWhitelistFromBondTable(&whitelistFromBondTable); + } + + bool matchAddressAndIrk(ble_gap_addr_t *address, ble_gap_irk_t *irk) const { + return btle_matchAddressAndIrk(address, irk); + } + friend class nRF5xGap; }; #endif // ifndef __NRF51822_SECURITY_MANAGER_H__ From 2ebbcb08b5185b22a858028de3a81aba4fc103e9 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 10:59:28 +0000 Subject: [PATCH 04/10] Add documentation and fix style of SecurityManager --- source/btle/btle_security.cpp | 36 +++++++++++++++++++++-------------- source/btle/btle_security.h | 17 +++++++++++++++++ source/nRF5xSecurityManager.h | 15 +++++++++++++++ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/source/btle/btle_security.cpp b/source/btle/btle_security.cpp index 74f8a2a..a03dd4f 100644 --- a/source/btle/btle_security.cpp +++ b/source/btle/btle_security.cpp @@ -45,19 +45,8 @@ static ble_gap_sec_params_t securityParameters = { }, /**< Key distribution bitmap: keys that the peripheral device will distribute. */ }; -ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) -{ - ret_code_t err = dm_whitelist_create(&applicationInstance, 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_hasInitializedSecurity(void) +bool +btle_hasInitializedSecurity(void) { return initialized; } @@ -281,7 +270,26 @@ dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t ev return NRF_SUCCESS; } -bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) +ble_error_t +btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) { + ret_code_t err = dm_whitelist_create(&applicationInstance, 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); } diff --git a/source/btle/btle_security.h b/source/btle/btle_security.h index 3db36ee..af4084f 100644 --- a/source/btle/btle_security.h +++ b/source/btle/btle_security.h @@ -77,8 +77,25 @@ ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager */ ble_error_t btle_purgeAllBondingState(void); +/** + * Function to test whether the SecurityManager has been initialized. + * Possible by a call to @ref btle_initializeSecurity(). + * + * @return True if the SecurityManager was previously initialized, false + * otherwise. + */ bool btle_hasInitializedSecurity(void); +/** + * Function to test whether a BLE address is generated using an IRK. + * + * @param[in] p_addr + * Pointer to a BLE address. + * @param[in] p_irk + * Pointer to an IRK. + * + * @return True if p_addr can be generated using p_irk, false otherwise. + */ bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk); #endif /* _BTLE_SECURITY_H_ */ diff --git a/source/nRF5xSecurityManager.h b/source/nRF5xSecurityManager.h index 2e842b6..63a1ef4 100644 --- a/source/nRF5xSecurityManager.h +++ b/source/nRF5xSecurityManager.h @@ -79,13 +79,28 @@ private: nRF5xSecurityManager(const nRF5xSecurityManager &); const nRF5xSecurityManager& operator=(const nRF5xSecurityManager &); + /* + * Expose an interface that allows us to query the SoftDevice bond table + * and extract a whitelist. + */ ble_error_t createWhitelistFromBondTable(ble_gap_whitelist_t &whitelistFromBondTable) const { return btle_createWhitelistFromBondTable(&whitelistFromBondTable); } + /* + * Given a BLE address and a IRK this function check whether the address + * can be generated from the IRK. To do so, this function uses the hash + * function and algorithm described in the Bluetooth low Energy + * Specification. Internally, Nordic SDK functions are used. + */ bool matchAddressAndIrk(ble_gap_addr_t *address, ble_gap_irk_t *irk) const { return btle_matchAddressAndIrk(address, irk); } + + /* + * Give nRF5xGap access to createWhitelistFromBondTable() and + * matchAddressAndIrk() + */ friend class nRF5xGap; }; From 9d0c6381d49ba56742608c4d72581e59ebc05907 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 11:15:35 +0000 Subject: [PATCH 05/10] Add missing documentation to btle_security for whitelisting --- source/btle/btle_security.h | 27 +++++++++++++++++------- source/nRF5xGap.cpp | 42 +++++++++++++++++++++++++++++++++++++ source/nRF5xGap.h | 9 ++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/source/btle/btle_security.h b/source/btle/btle_security.h index af4084f..54f5f5e 100644 --- a/source/btle/btle_security.h +++ b/source/btle/btle_security.h @@ -20,6 +20,15 @@ #include "ble/Gap.h" #include "ble/SecurityManager.h" +/** + * Function to test whether the SecurityManager has been initialized. + * Possible by a call to @ref btle_initializeSecurity(). + * + * @return True if the SecurityManager was previously initialized, false + * otherwise. + */ +bool btle_hasInitializedSecurity(void); + /** * Enable Nordic's Device Manager, which brings in functionality from the * stack's Security Manager. The Security Manager implements the actual @@ -40,8 +49,6 @@ ble_error_t btle_initializeSecurity(bool en SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE, const SecurityManager::Passkey_t passkey = NULL); -ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist); - /** * Get the security status of a link. * @@ -78,13 +85,19 @@ ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager ble_error_t btle_purgeAllBondingState(void); /** - * Function to test whether the SecurityManager has been initialized. - * Possible by a call to @ref btle_initializeSecurity(). + * Query the SoftDevice bond table to extract a whitelist containing the BLE + * addresses and IRKs of bonded devices. * - * @return True if the SecurityManager was previously initialized, false - * otherwise. + * @param[in/out] p_whitelist + * (on input) p_whitelist->addr_count and + * p_whitelist->irk_count specify the maximum number of + * addresses and IRKs added to the whitelist structure. + * (on output) *p_whitelist is a whitelist containing the + * addresses and IRKs of the bonded devices. + * + * @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure. */ -bool btle_hasInitializedSecurity(void); +ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist); /** * Function to test whether a BLE address is generated using an IRK. diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 99f7d14..5f1df7f 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -642,6 +642,48 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const return Gap::INIT_POLICY_IGNORE_WHITELIST; } +/**************************************************************************/ +/*! + @brief Helper function used to populate the ble_gap_whitelist_t that + will be used by the SoftDevice for filtering requests. + + @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. + + @note This function is needed because for the BLE API the whitelist + is just a collection of keys, but for the stack it also includes + the IRK table. + + @section EXAMPLE + + @code + + @endcode +*/ +/**************************************************************************/ ble_error_t nRF5xGap::generateStackWhitelist(void) { ble_gap_whitelist_t whitelistFromBondTable; diff --git a/source/nRF5xGap.h b/source/nRF5xGap.h index 751133b..c417239 100644 --- a/source/nRF5xGap.h +++ b/source/nRF5xGap.h @@ -92,6 +92,10 @@ public: virtual ble_error_t reset(void); + /* + * The following functions are part of the whitelisting experimental API. + * Therefore, this functionality can change in the near future. + */ virtual uint8_t getMaxWhitelistSize(void) const; virtual ble_error_t getWhitelist(Gap::Whitelist_t &whitelistOut) const; virtual ble_error_t setWhitelist(const Gap::Whitelist_t &whitelistIn); @@ -118,6 +122,10 @@ public: #endif private: + /* + * Whitelisting API related structures and helper functions. + */ + /* Policy modes set by the user. By default these are set to ignore the whitelist */ Gap::AdvertisingPolicyMode_t advertisingPolicyMode; Gap::ScanningPolicyMode_t scanningPolicyMode; @@ -139,6 +147,7 @@ private: */ ble_error_t generateStackWhitelist(void); +private: bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ Timeout radioNotificationTimeout; From b72f9aa24e94498123913d9ff4037733d9e8767a Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 11:43:28 +0000 Subject: [PATCH 06/10] Add whitelisting documentation to nRF51xGap --- source/nRF5xGap.cpp | 189 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 19 deletions(-) diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 5f1df7f..1fd1092 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -573,11 +573,45 @@ void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *co *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 { uint8_t i; @@ -589,6 +623,36 @@ ble_error_t nRF5xGap::getWhitelist(Gap::Whitelist_t &whitelistOut) const 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()) { @@ -608,6 +672,26 @@ ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) 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; @@ -615,6 +699,26 @@ ble_error_t nRF5xGap::setAdvertisingPolicyMode(Gap::AdvertisingPolicyMode_t 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; @@ -622,21 +726,83 @@ ble_error_t nRF5xGap::setScanningPolicyMode(Gap::ScanningPolicyMode_t 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; @@ -647,31 +813,16 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const @brief Helper function used to populate the ble_gap_whitelist_t that will be used by the SoftDevice for filtering requests. - @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_INVALID_STATE + The internal stack was not initialized correctly. - @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. + @note Both the SecurityManager and Gap must initialize correctly for + this function to succeed. @note This function is needed because for the BLE API the whitelist is just a collection of keys, but for the stack it also includes From 553551aa4fb5b06700d87fe5757e391f95ede029 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 13:44:39 +0000 Subject: [PATCH 07/10] Update nrf51-sdk dependency to v2.1.0 This is required because 2.1.0 includes additional files from the peer manager that are used by the implementation of the whitelisting API to check whether an address can be generated from a given IRK. --- module.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.json b/module.json index f183df2..0c1b130 100644 --- a/module.json +++ b/module.json @@ -25,7 +25,7 @@ ], "dependencies": { "ble": "^2.3.0", - "nrf51-sdk": "^2.0.0" + "nrf51-sdk": "^2.1.0" }, "extraIncludes": [ "source/btle", From 12e6c9ec099d96e5574b383a9a92729461109279 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 14:18:44 +0000 Subject: [PATCH 08/10] Make setWhitelist check errors before changing state --- source/nRF5xGap.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 1fd1092..13eea42 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -659,12 +659,16 @@ ble_error_t nRF5xGap::setWhitelist(const Gap::Whitelist_t &whitelistIn) return BLE_ERROR_PARAM_OUT_OF_RANGE; } - whitelistAddressesSize = 0; + /* Test for invalid parameters before we change the internal state */ for (uint8_t i = 0; i < whitelistIn.size; ++i) { if (whitelistIn.addresses[i].type == BLEProtocol::AddressType_t::RANDOM_PRIVATE_NON_RESOLVABLE) { /* This is not allowed because it is completely meaningless */ return BLE_ERROR_INVALID_PARAM; } + } + + whitelistAddressesSize = 0; + for (uint8_t i = 0; i < whitelistIn.size; ++i) { memcpy(&whitelistAddresses[whitelistAddressesSize], &whitelistIn.addresses[i], sizeof(BLEProtocol::Address_t)); whitelistAddressesSize++; } From bdf392d4717d61f89da96b34076ed23e22594b3f Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 15:19:18 +0000 Subject: [PATCH 09/10] Remove redundant structures from nRF5xGap Remove the following structures/arrays from the nRF5xGap class: * ble_gap_whitelist_t whitelist * ble_gap_addr_t *whitelistAddressePtrs[] * ble_gap_irk_t *whitelistIrkPtrs[] These are made redundant because the SoftDevice does not require the user to keep a copy of the whitelist itself. --- source/nRF5xGap.cpp | 52 ++++++++++++++++++++++++++++++--------------- source/nRF5xGap.h | 17 +++------------ 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index 13eea42..d338aa8 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -168,16 +168,22 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) return BLE_ERROR_PARAM_OUT_OF_RANGE; } + /* 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(); + ble_error_t error = generateStackWhitelist(whitelist); if (error != BLE_ERROR_NONE) { return error; } - } else { - /* Reset the whitelist table to avoid any errors */ - whitelist.addr_count = 0; - whitelist.irk_count = 0; } /* Start Advertising */ @@ -199,18 +205,24 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams ¶ms) /* 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_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams) +{ + /* 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(); + ble_error_t error = generateStackWhitelist(whitelist); if (error != BLE_ERROR_NONE) { return error; } - } else { - /* Reset the whitelist table to avoid any errors */ - whitelist.addr_count = 0; - whitelist.irk_count = 0; } ble_gap_scan_params_t scanParams = { @@ -286,16 +298,22 @@ ble_error_t nRF5xGap::connect(const Address_t peerAddr, connParams.conn_sup_timeout = 600; } + /* 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(); + ble_error_t error = generateStackWhitelist(whitelist); if (error != BLE_ERROR_NONE) { return error; } - } else { - /* Reset the whitelist table to avoid any errors */ - whitelist.addr_count = 0; - whitelist.irk_count = 0; } ble_gap_scan_params_t scanParams; @@ -839,7 +857,7 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const @endcode */ /**************************************************************************/ -ble_error_t nRF5xGap::generateStackWhitelist(void) +ble_error_t nRF5xGap::generateStackWhitelist(ble_gap_whitelist_t &whitelist) { ble_gap_whitelist_t whitelistFromBondTable; ble_gap_addr_t *addressPtr[1]; diff --git a/source/nRF5xGap.h b/source/nRF5xGap.h index c417239..e9a2d92 100644 --- a/source/nRF5xGap.h +++ b/source/nRF5xGap.h @@ -133,11 +133,6 @@ private: /* Internal representation of a whitelist */ uint8_t whitelistAddressesSize; ble_gap_addr_t whitelistAddresses[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; - ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; - - /* Structure used by the SoftDevice to represent a whitelist together with IRK table */ - ble_gap_whitelist_t whitelist; /* * An internal function used to populate the ble_gap_whitelist_t that will be used by @@ -145,7 +140,7 @@ private: * API the whitelist is just a collection of keys, but for the stack it also includes * the IRK table. */ - ble_error_t generateStackWhitelist(void); + ble_error_t generateStackWhitelist(ble_gap_whitelist_t &whitelist); private: bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ @@ -239,15 +234,9 @@ private: nRF5xGap() : advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST), - scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST) { + scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST), + whitelistAddressesSize(0) { m_connectionHandle = BLE_CONN_HANDLE_INVALID; - - /* Reset the whitelist */ - whitelist.addr_count = 0; - whitelist.irk_count = 0; - whitelist.pp_irks = whitelistIrkPtrs; - whitelist.pp_addrs = whitelistAddressPtrs; - whitelistAddressesSize = 0; } nRF5xGap(nRF5xGap const &); From 91e8bf4bb22e8772c277c091d4f3d6a3d4035a3a Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 8 Jan 2016 15:33:19 +0000 Subject: [PATCH 10/10] Modify nRF5xGap::reset() to reset the whitelist --- source/nRF5xGap.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/nRF5xGap.cpp b/source/nRF5xGap.cpp index d338aa8..d96dc92 100644 --- a/source/nRF5xGap.cpp +++ b/source/nRF5xGap.cpp @@ -440,6 +440,13 @@ ble_error_t nRF5xGap::reset(void) /* 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; + return BLE_ERROR_NONE; }