microbit: Added optional support for whitelisting and limited advertising

Added MicroBitConfig.h option to enable/disable whitelisting
Added MicroBitConfig.h option to enable/disable limited period advertising
Added support for limited period advertising
Minor code cleanups
This commit is contained in:
Joe Finney 2016-01-16 16:54:58 +00:00
parent 90cf35a38a
commit f17151a0bf
3 changed files with 74 additions and 35 deletions

View File

@ -33,10 +33,12 @@
#include "MicroBitTemperatureService.h"
#include "ExternalEvents.h"
#define MICROBIT_BLE_PAIR_REQUEST 0x01
#define MICROBIT_BLE_PAIR_COMPLETE 0x02
#define MICROBIT_BLE_PAIR_PASSCODE 0x04
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x08
#define MICROBIT_BLE_PAIR_REQUEST 0x01
#define MICROBIT_BLE_PAIR_COMPLETE 0x02
#define MICROBIT_BLE_PAIR_PASSCODE 0x04
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x08
#define MICROBIT_BLE_PAIRING_TIMEOUT 90
/**
* Class definition for the MicroBitBLEManager.
@ -81,36 +83,36 @@ class MicroBitBLEManager
void pairingMode(MicroBitDisplay &display);
/**
* Method that is called whenever a BLE device disconnects from us.
* The nordic stack stops dvertising whenever a device connects, so we use
* this callback to restart advertising.
* Makes the micro:bit discoverable via BLE, such that bonded devices can connect
* When called, the micro:bit will begin advertising for a predefined period,
* (MICROBIT_BLE_ADVERTISING_TIMEOUT seconds) thereby allowing bonded devices to connect.
*/
void onDisconnectionCallback();
/**
* Displays the device's ID code as a histogram on the LED matrix display.
*/
void showNameHistogram(MicroBitDisplay &display);
void advertise();
/**
* A request to pair has been received from a BLE device.
* If we're in pairing mode, display the passkey to the user.
*/
void pairingRequested(ManagedString passKey);
void pairingRequested(ManagedString passKey);
/**
* A pairing request has been sucesfully completed.
* If we're in pairing mode, display feedback to the user.
*/
void pairingComplete(bool success);
void pairingComplete(bool success);
private:
/**
* Displays the device's ID code as a histogram on the LED matrix display.
*/
void showNameHistogram(MicroBitDisplay &display);
private:
int pairingStatus;
ManagedString passKey;
ManagedString deviceName;
};
#endif

View File

@ -129,13 +129,13 @@
// Enable/Disable BLE during normal operation.
// Set '1' to enable.
#ifndef MICROBIT_BLE_ENABLED
#define MICROBIT_BLE_ENABLED 1
#define MICROBIT_BLE_ENABLED 1
#endif
// Enable/Disable BLE pairing mode mode at power up.
// Set '1' to enable.
#ifndef MICROBIT_BLE_PAIRING_MODE
#define MICROBIT_BLE_PAIRING_MODE 1
#define MICROBIT_BLE_PAIRING_MODE 1
#endif
// Enable/Disable the use of private resolvable addresses.
@ -144,11 +144,24 @@
#define MICROBIT_BLE_PRIVATE_ADDRESSES 0
#endif
// Enable/Disbale the use of BLE whitelisting.
// If enabled, the micro:bit will only respond to conneciton requests from
// known, bonded devices.
#ifndef MICROBIT_BLE_WHITELIST
#define MICROBIT_BLE_WHITELIST 1
#endif
// Define the period of time for which the BLE stack will advertise (seconds)
// Afer this period, advertising will cease. Set to '0' for no timeout (always advertise).
#ifndef MICROBIT_BLE_ADVERTISING_TIMEOUT
#define MICROBIT_BLE_ADVERTISING_TIMEOUT 0
#endif
// Enable/Disable BLE Service: MicroBitDFU
// This allows over the air programming during normal operation.
// Set '1' to enable.
#ifndef MICROBIT_BLE_DFU_SERVICE
#define MICROBIT_BLE_DFU_SERVICE 1
#define MICROBIT_BLE_DFU_SERVICE 1
#endif
// Enable/Disable BLE Service: MicroBitEventService

View File

@ -24,8 +24,6 @@
#define MICROBIT_BLE_ENABLE_BONDING true
#define MICROBIT_BLE_REQUIRE_MITM true
#define MICROBIT_PAIRING_MODE_TIMEOUT 90
#define MICROBIT_PAIRING_FADE_SPEED 4
@ -35,6 +33,7 @@ const char* MICROBIT_BLE_HARDWARE_VERSION = "1.0";
const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION;
const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL;
/*
* Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods.
* So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit
@ -50,7 +49,7 @@ static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *r
(void) reason; /* -Wunused-param */
if (manager)
manager->onDisconnectionCallback();
manager->advertise();
}
@ -88,14 +87,14 @@ MicroBitBLEManager::MicroBitBLEManager()
}
/**
* Method that is called whenever a BLE device disconnects from us.
* The nordic stack stops dvertising whenever a device connects, so we use
* this callback to restart advertising.
* Makes the micro:bit discoverable via BLE, such that bonded devices can connect
* When called, the micro:bit will begin advertising for a predefined period, thereby allowing
* bonded devices to connect.
*/
void MicroBitBLEManager::onDisconnectionCallback()
void MicroBitBLEManager::advertise()
{
if(ble)
ble->startAdvertising();
if(ble)
ble->gap().startAdvertising();
}
/**
@ -131,7 +130,7 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
#if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
// Configure for private addresses, so kids' behaviour can't be easily tracked.
ble->setAddress(Gap::ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, NULL);
ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
#endif
// Setup our security requirements.
@ -139,8 +138,9 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
ble->securityManager().init(MICROBIT_BLE_ENABLE_BONDING, MICROBIT_BLE_REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY);
// Configure a whitelist to filter all traffic from unbonded devices. Most BLE stacks only permit one connection at a time,
// so this prevents denial of service attacks.
#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
// Configure a whitelist to filter all connection requetss from unbonded devices.
// Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks.
BLEProtocol::Address_t bondedAddresses[4];
Gap::Whitelist_t whitelist;
whitelist.addresses = bondedAddresses;
@ -149,6 +149,10 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
ble->securityManager().getAddressesFromBondTable(whitelist);
ble->gap().setWhitelist(whitelist);
ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST);
ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
#endif
// Bring up any configured auxiliary services.
#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
new MicroBitDFUService(*ble);
@ -195,13 +199,28 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
ble->setPreferredConnectionParams(&fast);
// Setup advertising.
#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
#else
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
#endif
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble->setAdvertisingInterval(200);
#if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
#endif
// If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
// This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
// If whiltelisting is disabled, then we always advertise.
#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
if (whitelist.size > 0)
#endif
ble->startAdvertising();
}
/**
@ -242,13 +261,16 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
int brightness = 255;
int fadeDirection = 0;
// Clear the whitelist, so we're discoverable by all BLE devices.
// Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
BLEProtocol::Address_t addresses[4];
Gap::Whitelist_t whitelist;
whitelist.addresses = addresses;
whitelist.capacity = 4;
whitelist.size = 0;
ble->gap().setWhitelist(whitelist);
ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
#endif
// Update the advertised name of this micro:bit to include the device name
ble->clearAdvertisingPayload();
@ -257,7 +279,9 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble->setAdvertisingInterval(200);
ble->startAdvertising();
ble->gap().setAdvertisingTimeout(0);
ble->gap().startAdvertising();
// Stop any running animations on the display
display.stopAnimation();
@ -330,7 +354,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
uBit.sleep(30);
timeInPairingMode++;
if (timeInPairingMode >= MICROBIT_PAIRING_MODE_TIMEOUT * 30)
if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
microbit_reset();
}
}