mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-22 05:00:55 +01:00
[BREAKING] Asynchronous pin injections for Numeric Comparison and PassKey Input (#165)
* Make NimBLEConnInfo functions const. * Update callback functions and update client to use new functions. * Update examples. * Update migration guide. --------- Co-authored-by: Casey Smith <csmith@morningstarcorp.com>
This commit is contained in:
parent
6ca61bbd9c
commit
9c1f1adf7a
14 changed files with 202 additions and 181 deletions
|
@ -383,18 +383,23 @@ The security callback methods are now incorporated in the `NimBLEServerCallbacks
|
||||||
|
|
||||||
The callback methods are:
|
The callback methods are:
|
||||||
|
|
||||||
> `bool onConfirmPIN(uint32_t pin)`
|
> `bool onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin)`
|
||||||
|
|
||||||
Receives the pin when using numeric comparison authentication, `return true;` to accept.
|
Receives the pin when using numeric comparison authentication.
|
||||||
|
Call `NimBLEDevice::injectConfirmPIN(connInfo, true);` to accept or `NimBLEDevice::injectConfirmPIN(connInfo, false);` to reject.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
> `uint32_t onPassKeyRequest()`
|
> `void onPassKeyEntry(const NimBLEConnInfo& connInfo)`
|
||||||
|
|
||||||
For server callback; return the passkey expected from the client.
|
Client callback; client should respond with the passkey (pin) by calling `NimBLEDevice::injectPassKey(connInfo, 123456);`
|
||||||
For client callback; return the passkey to send to the server.
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
> `void onAuthenticationComplete(NimBLEConnInfo& connInfo)`
|
> `uint32_t onPassKeyDisplay()`
|
||||||
|
|
||||||
|
Server callback; should return the passkey (pin) expected from the client.
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
> `void onAuthenticationComplete(const NimBLEConnInfo& connInfo)`
|
||||||
|
|
||||||
Authentication complete, success or failed information is available from the `NimBLEConnInfo` methods.
|
Authentication complete, success or failed information is available from the `NimBLEConnInfo` methods.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
|
@ -39,20 +39,22 @@ class ClientCallbacks : public NimBLEClientCallbacks {
|
||||||
|
|
||||||
/********************* Security handled here **********************
|
/********************* Security handled here **********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
void onPassKeyEntry(const NimBLEConnInfo& connInfo){
|
||||||
printf("Client Passkey Request\n");
|
printf("Server Passkey Entry\n");
|
||||||
/** return the passkey to send to the server */
|
/** This should prompt the user to enter the passkey displayed
|
||||||
return 123456;
|
* on the peer device.
|
||||||
}
|
*/
|
||||||
|
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||||
|
};
|
||||||
|
|
||||||
bool onConfirmPIN(uint32_t pass_key){
|
void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||||
printf("The passkey YES/NO number: %" PRIu32"\n", pass_key);
|
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||||
/** Return false if passkeys don't match. */
|
/** Inject false if passkeys don't match. */
|
||||||
return true;
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** Pairing process complete, we can check the results in connInfo */
|
/** Pairing process complete, we can check the results in connInfo */
|
||||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
void onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
if(!connInfo.isEncrypted()) {
|
if(!connInfo.isEncrypted()) {
|
||||||
printf("Encrypt connection failed - disconnecting\n");
|
printf("Encrypt connection failed - disconnecting\n");
|
||||||
/** Find the client with the connection handle provided in desc */
|
/** Find the client with the connection handle provided in desc */
|
||||||
|
|
|
@ -44,21 +44,21 @@ class ServerCallbacks: public NimBLEServerCallbacks {
|
||||||
|
|
||||||
/********************* Security handled here **********************
|
/********************* Security handled here **********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
uint32_t onPassKeyDisplay(){
|
||||||
printf("Server Passkey Request\n");
|
printf("Server Passkey Display\n");
|
||||||
/** This should return a random 6 digit number for security
|
/** This should return a random 6 digit number for security
|
||||||
* or make your own static passkey as done here.
|
* or make your own static passkey as done here.
|
||||||
*/
|
*/
|
||||||
return 123456;
|
return 123456;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool onConfirmPIN(uint32_t pass_key){
|
void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||||
printf("The passkey YES/NO number: %" PRIu32"\n", pass_key);
|
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||||
/** Return false if passkeys don't match. */
|
/** Inject false if passkeys don't match. */
|
||||||
return true;
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
void onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
void onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
/** Check that encryption was successful, if not we disconnect the client */
|
/** Check that encryption was successful, if not we disconnect the client */
|
||||||
if(!connInfo.isEncrypted()) {
|
if(!connInfo.isEncrypted()) {
|
||||||
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* NimBLE Scan active/passive switching demo
|
|
||||||
*
|
|
||||||
* Demonstrates the use of the scan callbacks while alternating between passive and active scanning.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "NimBLEDevice.h"
|
|
||||||
int scanTime = 5 * 1000; // In milliseconds, 0 = scan forever
|
|
||||||
BLEScan* pBLEScan;
|
|
||||||
|
|
||||||
bool active = false;
|
|
||||||
|
|
||||||
class scanCallbacks: public NimBLEScanCallbacks {
|
|
||||||
|
|
||||||
void onDiscovered(NimBLEAdvertisedDevice* advertisedDevice) {
|
|
||||||
Serial.printf("Discovered Advertised Device: %s \n", advertisedDevice->toString().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
|
||||||
Serial.printf("Advertised Device Result: %s \n", advertisedDevice->toString().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void onScanEnd(NimBLEScanResults results){
|
|
||||||
Serial.println("Scan Ended");
|
|
||||||
active = !active;
|
|
||||||
pBLEScan->setActiveScan(active);
|
|
||||||
Serial.printf("scan start, active = %u\n", active);
|
|
||||||
pBLEScan->start(scanTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
Serial.println("Scanning...");
|
|
||||||
|
|
||||||
NimBLEDevice::init("");
|
|
||||||
pBLEScan = NimBLEDevice::getScan();
|
|
||||||
pBLEScan->setScanCallbacks(new scanCallbacks());
|
|
||||||
pBLEScan->setActiveScan(active);
|
|
||||||
pBLEScan->setInterval(100);
|
|
||||||
pBLEScan->setWindow(99);
|
|
||||||
pBLEScan->start(scanTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
}
|
|
|
@ -51,17 +51,28 @@ class MyClientCallback : public BLEClientCallbacks {
|
||||||
}
|
}
|
||||||
/***************** New - Security handled here ********************
|
/***************** New - Security handled here ********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
void onPassKeyEntry(const NimBLEConnInfo& connInfo){
|
||||||
printf("Client PassKeyRequest\n");
|
printf("Server Passkey Entry\n");
|
||||||
return 123456;
|
/** This should prompt the user to enter the passkey displayed
|
||||||
}
|
* on the peer device.
|
||||||
bool onConfirmPIN(uint32_t pass_key){
|
*/
|
||||||
printf("The passkey YES/NO number: %" PRIu32"\n", pass_key);
|
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||||
return true;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
void onAuthenticationComplete(BLEConnInfo& connInfo){
|
void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||||
printf("Starting BLE work!\n");
|
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||||
|
/** Inject false if passkeys don't match. */
|
||||||
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Pairing process complete, we can check the results in connInfo */
|
||||||
|
void onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
|
if(!connInfo.isEncrypted()) {
|
||||||
|
printf("Encrypt connection failed - disconnecting\n");
|
||||||
|
/** Find the client with the connection handle provided in desc */
|
||||||
|
NimBLEDevice::getClientByID(connInfo.getConnHandle())->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,19 +57,29 @@ class MyServerCallbacks: public BLEServerCallbacks {
|
||||||
}
|
}
|
||||||
/***************** New - Security handled here ********************
|
/***************** New - Security handled here ********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
uint32_t onPassKeyDisplay(){
|
||||||
printf("Server PassKeyRequest\n");
|
printf("Server Passkey Display\n");
|
||||||
|
/** This should return a random 6 digit number for security
|
||||||
|
* or make your own static passkey as done here.
|
||||||
|
*/
|
||||||
return 123456;
|
return 123456;
|
||||||
}
|
};
|
||||||
|
|
||||||
bool onConfirmPIN(uint32_t pass_key){
|
void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||||
printf("The passkey YES/NO number: %" PRIu32"\n", pass_key);
|
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||||
return true;
|
/** Inject false if passkeys don't match. */
|
||||||
}
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
|
};
|
||||||
|
|
||||||
void onAuthenticationComplete(BLEConnInfo& connInfo){
|
void onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
printf("Starting BLE work!\n");
|
/** Check that encryption was successful, if not we disconnect the client */
|
||||||
|
if(!connInfo.isEncrypted()) {
|
||||||
|
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||||
|
printf("Encrypt connection failed - disconnecting client\n");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
printf("Starting BLE work!");
|
||||||
|
};
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,19 +59,29 @@ class MyServerCallbacks: public BLEServerCallbacks {
|
||||||
}
|
}
|
||||||
/***************** New - Security handled here ********************
|
/***************** New - Security handled here ********************
|
||||||
****** Note: these are the same return values as defaults ********/
|
****** Note: these are the same return values as defaults ********/
|
||||||
uint32_t onPassKeyRequest(){
|
uint32_t onPassKeyDisplay(){
|
||||||
printf("Server PassKeyRequest\n");
|
printf("Server Passkey Display\n");
|
||||||
|
/** This should return a random 6 digit number for security
|
||||||
|
* or make your own static passkey as done here.
|
||||||
|
*/
|
||||||
return 123456;
|
return 123456;
|
||||||
}
|
};
|
||||||
|
|
||||||
bool onConfirmPIN(uint32_t pass_key){
|
void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pass_key){
|
||||||
printf("The passkey YES/NO number: %" PRIu32"\n", pass_key);
|
printf("The passkey YES/NO number: %" PRIu32 "\n", pass_key);
|
||||||
return true;
|
/** Inject false if passkeys don't match. */
|
||||||
}
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
|
};
|
||||||
|
|
||||||
void onAuthenticationComplete(BLEConnInfo& connInfo){
|
void onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
printf("Starting BLE work!\n");
|
/** Check that encryption was successful, if not we disconnect the client */
|
||||||
|
if(!connInfo.isEncrypted()) {
|
||||||
|
NimBLEDevice::getServer()->disconnect(connInfo.getConnHandle());
|
||||||
|
printf("Encrypt connection failed - disconnecting client\n");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
printf("Starting BLE work!");
|
||||||
|
};
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1171,7 +1171,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
{
|
{
|
||||||
NimBLEConnInfo peerInfo;
|
NimBLEConnInfo peerInfo;
|
||||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc);
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc);
|
||||||
assert(rc == 0);
|
if (rc != 0) {
|
||||||
|
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
||||||
// Key is missing, try deleting.
|
// Key is missing, try deleting.
|
||||||
|
@ -1203,20 +1207,17 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
if(pClient->m_conn_id != event->passkey.conn_handle)
|
if(pClient->m_conn_id != event->passkey.conn_handle)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
NimBLEConnInfo peerInfo;
|
||||||
pkey.action = event->passkey.params.action;
|
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
|
||||||
pkey.passkey = NimBLEDevice::m_passkey; // This is the passkey to be entered on peer
|
if (rc != 0) {
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
|
||||||
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||||
pkey.action = event->passkey.params.action;
|
pClient->m_pClientCallbacks->onConfirmPIN(peerInfo, event->passkey.params.numcmp);
|
||||||
pkey.numcmp_accept = pClient->m_pClientCallbacks->onConfirmPIN(event->passkey.params.numcmp);
|
|
||||||
|
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
|
||||||
|
|
||||||
//TODO: Handle out of band pairing
|
//TODO: Handle out of band pairing
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
||||||
static uint8_t tem_oob[16] = {0};
|
static uint8_t tem_oob[16] = {0};
|
||||||
|
@ -1229,12 +1230,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
////////
|
////////
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
||||||
pkey.action = event->passkey.params.action;
|
pClient->m_pClientCallbacks->onPassKeyEntry(peerInfo);
|
||||||
pkey.passkey = pClient->m_pClientCallbacks->onPassKeyRequest();
|
|
||||||
|
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
||||||
}
|
}
|
||||||
|
@ -1321,17 +1317,18 @@ bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, con
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NimBLEClientCallbacks::onPassKeyRequest(){
|
void NimBLEClientCallbacks::onPassKeyEntry(const NimBLEConnInfo& connInfo){
|
||||||
NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyRequest: default: 123456");
|
NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyEntry: default: 123456");
|
||||||
return 123456;
|
NimBLEDevice::injectPassKey(connInfo, 123456);
|
||||||
}
|
} //onPassKeyEntry
|
||||||
|
|
||||||
void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& peerInfo){
|
void NimBLEClientCallbacks::onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default");
|
NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default");
|
||||||
}
|
}
|
||||||
bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
|
|
||||||
|
void NimBLEClientCallbacks::onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin){
|
||||||
NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true");
|
NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true");
|
||||||
return true;
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
|
|
|
@ -147,23 +147,23 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when server requests a passkey for pairing.
|
* @brief Called when server requests a passkey for pairing.
|
||||||
* @return The passkey to be sent to the server.
|
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||||
*/
|
*/
|
||||||
virtual uint32_t onPassKeyRequest();
|
virtual void onPassKeyEntry(const NimBLEConnInfo& connInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when the pairing procedure is complete.
|
* @brief Called when the pairing procedure is complete.
|
||||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.\n
|
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.\n
|
||||||
* This can be used to check the status of the connection encryption/pairing.
|
* This can be used to check the status of the connection encryption/pairing.
|
||||||
*/
|
*/
|
||||||
virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo);
|
virtual void onAuthenticationComplete(const NimBLEConnInfo& connInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when using numeric comparision for pairing.
|
* @brief Called when using numeric comparision for pairing.
|
||||||
|
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
|
||||||
* @param [in] pin The pin to compare with the server.
|
* @param [in] pin The pin to compare with the server.
|
||||||
* @return True to accept the pin.
|
|
||||||
*/
|
*/
|
||||||
virtual bool onConfirmPIN(uint32_t pin);
|
virtual void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||||
|
|
|
@ -17,40 +17,40 @@ friend class NimBLEDescriptor;
|
||||||
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
|
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
|
||||||
public:
|
public:
|
||||||
/** @brief Gets the over-the-air address of the connected peer */
|
/** @brief Gets the over-the-air address of the connected peer */
|
||||||
NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
|
NimBLEAddress getAddress() const { return NimBLEAddress(m_desc.peer_ota_addr); }
|
||||||
|
|
||||||
/** @brief Gets the ID address of the connected peer */
|
/** @brief Gets the ID address of the connected peer */
|
||||||
NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
|
NimBLEAddress getIdAddress() const { return NimBLEAddress(m_desc.peer_id_addr); }
|
||||||
|
|
||||||
/** @brief Gets the connection handle of the connected peer */
|
/** @brief Gets the connection handle of the connected peer */
|
||||||
uint16_t getConnHandle() { return m_desc.conn_handle; }
|
uint16_t getConnHandle() const { return m_desc.conn_handle; }
|
||||||
|
|
||||||
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
|
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
|
||||||
uint16_t getConnInterval() { return m_desc.conn_itvl; }
|
uint16_t getConnInterval() const { return m_desc.conn_itvl; }
|
||||||
|
|
||||||
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
|
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
|
||||||
uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
|
uint16_t getConnTimeout() const { return m_desc.supervision_timeout; }
|
||||||
|
|
||||||
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
|
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
|
||||||
uint16_t getConnLatency() { return m_desc.conn_latency; }
|
uint16_t getConnLatency() const { return m_desc.conn_latency; }
|
||||||
|
|
||||||
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
|
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
|
||||||
uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
|
uint16_t getMTU() const { return ble_att_mtu(m_desc.conn_handle); }
|
||||||
|
|
||||||
/** @brief Check if we are in the master role in this connection */
|
/** @brief Check if we are in the master role in this connection */
|
||||||
bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
|
bool isMaster() const { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
|
||||||
|
|
||||||
/** @brief Check if we are in the slave role in this connection */
|
/** @brief Check if we are in the slave role in this connection */
|
||||||
bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
|
bool isSlave() const { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
|
||||||
|
|
||||||
/** @brief Check if we are connected to a bonded peer */
|
/** @brief Check if we are connected to a bonded peer */
|
||||||
bool isBonded() { return (m_desc.sec_state.bonded == 1); }
|
bool isBonded() const { return (m_desc.sec_state.bonded == 1); }
|
||||||
|
|
||||||
/** @brief Check if the connection in encrypted */
|
/** @brief Check if the connection in encrypted */
|
||||||
bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
|
bool isEncrypted() const { return (m_desc.sec_state.encrypted == 1); }
|
||||||
|
|
||||||
/** @brief Check if the the connection has been authenticated */
|
/** @brief Check if the the connection has been authenticated */
|
||||||
bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
|
bool isAuthenticated() const { return (m_desc.sec_state.authenticated == 1); }
|
||||||
|
|
||||||
/** @brief Gets the key size used to encrypt the connection */
|
/** @brief Gets the key size used to encrypt the connection */
|
||||||
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
|
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
|
||||||
|
|
|
@ -1156,6 +1156,43 @@ int NimBLEDevice::startSecurity(uint16_t conn_id) {
|
||||||
} // startSecurity
|
} // startSecurity
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inject the provided passkey into the Security Manager
|
||||||
|
* @param [in] peerInfo Connection information for the peer
|
||||||
|
* @param [in] pin The 6-digit pin to inject
|
||||||
|
* @return true if the passkey was injected successfully.
|
||||||
|
*/
|
||||||
|
bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin) {
|
||||||
|
int rc = 0;
|
||||||
|
struct ble_sm_io pkey = {0,0};
|
||||||
|
|
||||||
|
pkey.action = BLE_SM_IOACT_INPUT;
|
||||||
|
pkey.passkey = pin;
|
||||||
|
|
||||||
|
rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
|
||||||
|
return rc == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inject the provided numeric comparison response into the Security Manager
|
||||||
|
* @param [in] peerInfo Connection information for the peer
|
||||||
|
* @param [in] accept Whether the user confirmed or declined the comparison
|
||||||
|
*/
|
||||||
|
bool NimBLEDevice::injectConfirmPIN(const NimBLEConnInfo& peerInfo, bool accept) {
|
||||||
|
int rc = 0;
|
||||||
|
struct ble_sm_io pkey = {0,0};
|
||||||
|
|
||||||
|
pkey.action = BLE_SM_IOACT_NUMCMP;
|
||||||
|
pkey.numcmp_accept = accept;
|
||||||
|
|
||||||
|
rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
|
||||||
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
|
||||||
|
return rc == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if the device address is on our ignore list.
|
* @brief Check if the device address is on our ignore list.
|
||||||
* @param [in] address The address to look for.
|
* @param [in] address The address to look for.
|
||||||
|
|
|
@ -136,6 +136,8 @@ public:
|
||||||
static void setSecurityPasskey(uint32_t pin);
|
static void setSecurityPasskey(uint32_t pin);
|
||||||
static uint32_t getSecurityPasskey();
|
static uint32_t getSecurityPasskey();
|
||||||
static int startSecurity(uint16_t conn_id);
|
static int startSecurity(uint16_t conn_id);
|
||||||
|
static bool injectConfirmPIN(const NimBLEConnInfo& peerInfo, bool accept);
|
||||||
|
static bool injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin);
|
||||||
static int setMTU(uint16_t mtu);
|
static int setMTU(uint16_t mtu);
|
||||||
static uint16_t getMTU();
|
static uint16_t getMTU();
|
||||||
static bool isIgnored(const NimBLEAddress &address);
|
static bool isIgnored(const NimBLEAddress &address);
|
||||||
|
|
|
@ -263,6 +263,7 @@ void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||||
} // advertiseOnDisconnect
|
} // advertiseOnDisconnect
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the number of connected clients.
|
* @brief Return the number of connected clients.
|
||||||
* @return The number of connected clients.
|
* @return The number of connected clients.
|
||||||
|
@ -528,19 +529,20 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
// if the (static)passkey is the default, check the callback for custom value
|
// if the (static)passkey is the default, check the callback for custom value
|
||||||
// both values default to the same.
|
// both values default to the same.
|
||||||
if(pkey.passkey == 123456) {
|
if(pkey.passkey == 123456) {
|
||||||
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyRequest();
|
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyDisplay();
|
||||||
}
|
}
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||||
pkey.action = event->passkey.params.action;
|
|
||||||
pkey.numcmp_accept = pServer->m_pServerCallbacks->onConfirmPIN(event->passkey.params.numcmp);
|
|
||||||
|
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
|
||||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
|
if(rc != 0) {
|
||||||
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pServer->m_pServerCallbacks->onConfirmPIN(peerInfo, event->passkey.params.numcmp);
|
||||||
//TODO: Handle out of band pairing
|
//TODO: Handle out of band pairing
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
||||||
static uint8_t tem_oob[16] = {0};
|
static uint8_t tem_oob[16] = {0};
|
||||||
|
@ -551,14 +553,6 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
|
||||||
pkey.action = event->passkey.params.action;
|
|
||||||
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyRequest();
|
|
||||||
|
|
||||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
|
||||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
|
|
||||||
|
|
||||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
||||||
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
||||||
}
|
}
|
||||||
|
@ -851,18 +845,18 @@ void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo)
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
|
||||||
} // onMTUChange
|
} // onMTUChange
|
||||||
|
|
||||||
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
|
uint32_t NimBLEServerCallbacks::onPassKeyDisplay(){
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyDisplay: default: 123456");
|
||||||
return 123456;
|
return 123456;
|
||||||
} //onPassKeyRequest
|
} //onPassKeyDisplay
|
||||||
|
|
||||||
void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo){
|
void NimBLEServerCallbacks::onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin){
|
||||||
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
|
||||||
|
NimBLEDevice::injectConfirmPIN(connInfo, true);
|
||||||
|
} // onConfirmPIN
|
||||||
|
|
||||||
|
void NimBLEServerCallbacks::onAuthenticationComplete(const NimBLEConnInfo& connInfo){
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
|
||||||
} // onAuthenticationComplete
|
} // onAuthenticationComplete
|
||||||
|
|
||||||
bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
|
||||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
|
|
||||||
return true;
|
|
||||||
} // onConfirmPIN
|
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
|
|
|
@ -152,24 +152,25 @@ public:
|
||||||
virtual void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo);
|
virtual void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when a client requests a passkey for pairing.
|
* @brief Called when a client requests a passkey for pairing (display).
|
||||||
* @return The passkey to be sent to the client.
|
* @return The passkey to be sent to the client.
|
||||||
*/
|
*/
|
||||||
virtual uint32_t onPassKeyRequest();
|
virtual uint32_t onPassKeyDisplay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when using numeric comparision for pairing.
|
||||||
|
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||||
|
* Should be passed back to NimBLEDevice::injectConfirmPIN
|
||||||
|
* @param [in] pin The pin to compare with the client.
|
||||||
|
*/
|
||||||
|
virtual void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when the pairing procedure is complete.
|
* @brief Called when the pairing procedure is complete.
|
||||||
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
|
||||||
* about the peer connection parameters.
|
* about the peer connection parameters.
|
||||||
*/
|
*/
|
||||||
virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo);
|
virtual void onAuthenticationComplete(const NimBLEConnInfo& connInfo);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called when using numeric comparision for pairing.
|
|
||||||
* @param [in] pin The pin to compare with the client.
|
|
||||||
* @return True to accept the pin.
|
|
||||||
*/
|
|
||||||
virtual bool onConfirmPIN(uint32_t pin);
|
|
||||||
}; // NimBLEServerCallbacks
|
}; // NimBLEServerCallbacks
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||||
|
|
Loading…
Reference in a new issue