Skip to content

Commit e86b27c

Browse files
[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>
1 parent 27d3253 commit e86b27c

7 files changed

+110
-77
lines changed

src/NimBLEClient.cpp

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
11711171
{
11721172
NimBLEConnInfo peerInfo;
11731173
rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc);
1174-
assert(rc == 0);
1174+
if (rc != 0) {
1175+
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
1176+
rc = 0;
1177+
break;
1178+
}
11751179

11761180
if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
11771181
// Key is missing, try deleting.
@@ -1203,20 +1207,17 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
12031207
if(pClient->m_conn_id != event->passkey.conn_handle)
12041208
return 0;
12051209

1206-
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
1207-
pkey.action = event->passkey.params.action;
1208-
pkey.passkey = NimBLEDevice::m_passkey; // This is the passkey to be entered on peer
1209-
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
1210-
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
1210+
NimBLEConnInfo peerInfo;
1211+
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
1212+
if (rc != 0) {
1213+
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
1214+
rc = 0;
1215+
break;
1216+
}
12111217

1212-
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
1218+
if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
12131219
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
1214-
pkey.action = event->passkey.params.action;
1215-
pkey.numcmp_accept = pClient->m_pClientCallbacks->onConfirmPIN(event->passkey.params.numcmp);
1216-
1217-
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
1218-
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
1219-
1220+
pClient->m_pClientCallbacks->onConfirmPIN(peerInfo, event->passkey.params.numcmp);
12201221
//TODO: Handle out of band pairing
12211222
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
12221223
static uint8_t tem_oob[16] = {0};
@@ -1229,12 +1230,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
12291230
////////
12301231
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
12311232
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
1232-
pkey.action = event->passkey.params.action;
1233-
pkey.passkey = pClient->m_pClientCallbacks->onPassKeyRequest();
1234-
1235-
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
1236-
NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
1237-
1233+
pClient->m_pClientCallbacks->onPassKeyEntry(peerInfo);
12381234
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
12391235
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
12401236
}
@@ -1321,17 +1317,18 @@ bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, con
13211317
return true;
13221318
}
13231319

1324-
uint32_t NimBLEClientCallbacks::onPassKeyRequest(){
1325-
NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyRequest: default: 123456");
1326-
return 123456;
1327-
}
1320+
void NimBLEClientCallbacks::onPassKeyEntry(const NimBLEConnInfo& connInfo){
1321+
NIMBLE_LOGD("NimBLEClientCallbacks", "onPassKeyEntry: default: 123456");
1322+
NimBLEDevice::injectPassKey(connInfo, 123456);
1323+
} //onPassKeyEntry
13281324

1329-
void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& peerInfo){
1325+
void NimBLEClientCallbacks::onAuthenticationComplete(const NimBLEConnInfo& connInfo){
13301326
NIMBLE_LOGD("NimBLEClientCallbacks", "onAuthenticationComplete: default");
13311327
}
1332-
bool NimBLEClientCallbacks::onConfirmPIN(uint32_t pin){
1328+
1329+
void NimBLEClientCallbacks::onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin){
13331330
NIMBLE_LOGD("NimBLEClientCallbacks", "onConfirmPIN: default: true");
1334-
return true;
1331+
NimBLEDevice::injectConfirmPIN(connInfo, true);
13351332
}
13361333

13371334
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */

src/NimBLEClient.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,23 @@ class NimBLEClientCallbacks {
147147

148148
/**
149149
* @brief Called when server requests a passkey for pairing.
150-
* @return The passkey to be sent to the server.
150+
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
151151
*/
152-
virtual uint32_t onPassKeyRequest();
152+
virtual void onPassKeyEntry(const NimBLEConnInfo& connInfo);
153153

154154
/**
155155
* @brief Called when the pairing procedure is complete.
156156
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.\n
157157
* This can be used to check the status of the connection encryption/pairing.
158158
*/
159-
virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo);
159+
virtual void onAuthenticationComplete(const NimBLEConnInfo& connInfo);
160160

161161
/**
162162
* @brief Called when using numeric comparision for pairing.
163+
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
163164
* @param [in] pin The pin to compare with the server.
164-
* @return True to accept the pin.
165165
*/
166-
virtual bool onConfirmPIN(uint32_t pin);
166+
virtual void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin);
167167
};
168168

169169
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */

src/NimBLEConnInfo.h

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,44 @@ friend class NimBLECharacteristic;
1313
friend class NimBLEDescriptor;
1414

1515
ble_gap_conn_desc m_desc;
16-
NimBLEConnInfo() { m_desc = {}; }
17-
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
16+
NimBLEConnInfo() { m_desc = {}; }
17+
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
1818
public:
1919
/** @brief Gets the over-the-air address of the connected peer */
20-
NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
20+
NimBLEAddress getAddress() const { return NimBLEAddress(m_desc.peer_ota_addr); }
2121

2222
/** @brief Gets the ID address of the connected peer */
23-
NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
23+
NimBLEAddress getIdAddress() const { return NimBLEAddress(m_desc.peer_id_addr); }
2424

2525
/** @brief Gets the connection handle of the connected peer */
26-
uint16_t getConnHandle() { return m_desc.conn_handle; }
26+
uint16_t getConnHandle() const { return m_desc.conn_handle; }
2727

2828
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
29-
uint16_t getConnInterval() { return m_desc.conn_itvl; }
29+
uint16_t getConnInterval() const { return m_desc.conn_itvl; }
3030

3131
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
32-
uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
32+
uint16_t getConnTimeout() const { return m_desc.supervision_timeout; }
3333

3434
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
35-
uint16_t getConnLatency() { return m_desc.conn_latency; }
35+
uint16_t getConnLatency() const { return m_desc.conn_latency; }
3636

3737
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
38-
uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
38+
uint16_t getMTU() const { return ble_att_mtu(m_desc.conn_handle); }
3939

4040
/** @brief Check if we are in the master role in this connection */
41-
bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
41+
bool isMaster() const { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
4242

4343
/** @brief Check if we are in the slave role in this connection */
44-
bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
44+
bool isSlave() const { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
4545

4646
/** @brief Check if we are connected to a bonded peer */
47-
bool isBonded() { return (m_desc.sec_state.bonded == 1); }
47+
bool isBonded() const { return (m_desc.sec_state.bonded == 1); }
4848

4949
/** @brief Check if the connection in encrypted */
50-
bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
50+
bool isEncrypted() const { return (m_desc.sec_state.encrypted == 1); }
5151

5252
/** @brief Check if the the connection has been authenticated */
53-
bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
53+
bool isAuthenticated() const { return (m_desc.sec_state.authenticated == 1); }
5454

5555
/** @brief Gets the key size used to encrypt the connection */
5656
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }

src/NimBLEDevice.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
# include "esp_bt.h"
2424
# include "nvs_flash.h"
2525
# if defined(CONFIG_NIMBLE_CPP_IDF)
26-
# include "esp_nimble_hci.h"
26+
# if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) || CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE)
27+
# include "esp_nimble_hci.h"
28+
# endif
2729
# include "nimble/nimble_port.h"
2830
# include "nimble/nimble_port_freertos.h"
2931
# include "host/ble_hs.h"
@@ -1154,6 +1156,43 @@ int NimBLEDevice::startSecurity(uint16_t conn_id) {
11541156
} // startSecurity
11551157

11561158

1159+
/**
1160+
* @brief Inject the provided passkey into the Security Manager
1161+
* @param [in] peerInfo Connection information for the peer
1162+
* @param [in] pin The 6-digit pin to inject
1163+
* @return true if the passkey was injected successfully.
1164+
*/
1165+
bool NimBLEDevice::injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin) {
1166+
int rc = 0;
1167+
struct ble_sm_io pkey = {0,0};
1168+
1169+
pkey.action = BLE_SM_IOACT_INPUT;
1170+
pkey.passkey = pin;
1171+
1172+
rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
1173+
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
1174+
return rc == 0;
1175+
}
1176+
1177+
1178+
/**
1179+
* @brief Inject the provided numeric comparison response into the Security Manager
1180+
* @param [in] peerInfo Connection information for the peer
1181+
* @param [in] accept Whether the user confirmed or declined the comparison
1182+
*/
1183+
bool NimBLEDevice::injectConfirmPIN(const NimBLEConnInfo& peerInfo, bool accept) {
1184+
int rc = 0;
1185+
struct ble_sm_io pkey = {0,0};
1186+
1187+
pkey.action = BLE_SM_IOACT_NUMCMP;
1188+
pkey.numcmp_accept = accept;
1189+
1190+
rc = ble_sm_inject_io(peerInfo.getConnHandle(), &pkey);
1191+
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
1192+
return rc == 0;
1193+
}
1194+
1195+
11571196
/**
11581197
* @brief Check if the device address is on our ignore list.
11591198
* @param [in] address The address to look for.

src/NimBLEDevice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ class NimBLEDevice {
136136
static void setSecurityPasskey(uint32_t pin);
137137
static uint32_t getSecurityPasskey();
138138
static int startSecurity(uint16_t conn_id);
139+
static bool injectConfirmPIN(const NimBLEConnInfo& peerInfo, bool accept);
140+
static bool injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin);
139141
static int setMTU(uint16_t mtu);
140142
static uint16_t getMTU();
141143
static bool isIgnored(const NimBLEAddress &address);

src/NimBLEServer.cpp

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ void NimBLEServer::advertiseOnDisconnect(bool aod) {
263263
} // advertiseOnDisconnect
264264
#endif
265265

266+
266267
/**
267268
* @brief Return the number of connected clients.
268269
* @return The number of connected clients.
@@ -528,19 +529,20 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
528529
// if the (static)passkey is the default, check the callback for custom value
529530
// both values default to the same.
530531
if(pkey.passkey == 123456) {
531-
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyRequest();
532+
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyDisplay();
532533
}
533534
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
534535
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
535536

536537
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
537538
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
538-
pkey.action = event->passkey.params.action;
539-
pkey.numcmp_accept = pServer->m_pServerCallbacks->onConfirmPIN(event->passkey.params.numcmp);
540539

541-
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
542-
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
540+
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
541+
if(rc != 0) {
542+
return BLE_ATT_ERR_INVALID_HANDLE;
543+
}
543544

545+
pServer->m_pServerCallbacks->onConfirmPIN(peerInfo, event->passkey.params.numcmp);
544546
//TODO: Handle out of band pairing
545547
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
546548
static uint8_t tem_oob[16] = {0};
@@ -551,14 +553,6 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
551553
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
552554
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
553555
//////////////////////////////////
554-
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
555-
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
556-
pkey.action = event->passkey.params.action;
557-
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyRequest();
558-
559-
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
560-
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
561-
562556
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
563557
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
564558
}
@@ -851,18 +845,18 @@ void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo)
851845
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
852846
} // onMTUChange
853847

854-
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
855-
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
848+
uint32_t NimBLEServerCallbacks::onPassKeyDisplay(){
849+
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyDisplay: default: 123456");
856850
return 123456;
857-
} //onPassKeyRequest
851+
} //onPassKeyDisplay
858852

859-
void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo){
860-
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
861-
} // onAuthenticationComplete
862-
863-
bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
853+
void NimBLEServerCallbacks::onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin){
864854
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
865-
return true;
855+
NimBLEDevice::injectConfirmPIN(connInfo, true);
866856
} // onConfirmPIN
867857

858+
void NimBLEServerCallbacks::onAuthenticationComplete(const NimBLEConnInfo& connInfo){
859+
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
860+
} // onAuthenticationComplete
861+
868862
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */

src/NimBLEServer.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,24 +152,25 @@ class NimBLEServerCallbacks {
152152
virtual void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo);
153153

154154
/**
155-
* @brief Called when a client requests a passkey for pairing.
155+
* @brief Called when a client requests a passkey for pairing (display).
156156
* @return The passkey to be sent to the client.
157157
*/
158-
virtual uint32_t onPassKeyRequest();
158+
virtual uint32_t onPassKeyDisplay();
159159

160160
/**
161-
* @brief Called when the pairing procedure is complete.
161+
* @brief Called when using numeric comparision for pairing.
162162
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
163-
* about the peer connection parameters.
163+
* Should be passed back to NimBLEDevice::injectConfirmPIN
164+
* @param [in] pin The pin to compare with the client.
164165
*/
165-
virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo);
166+
virtual void onConfirmPIN(const NimBLEConnInfo& connInfo, uint32_t pin);
166167

167168
/**
168-
* @brief Called when using numeric comparision for pairing.
169-
* @param [in] pin The pin to compare with the client.
170-
* @return True to accept the pin.
169+
* @brief Called when the pairing procedure is complete.
170+
* @param [in] connInfo A reference to a NimBLEConnInfo instance with information
171+
* about the peer connection parameters.
171172
*/
172-
virtual bool onConfirmPIN(uint32_t pin);
173+
virtual void onAuthenticationComplete(const NimBLEConnInfo& connInfo);
173174
}; // NimBLEServerCallbacks
174175

175176
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */

0 commit comments

Comments
 (0)