Skip to content

Commit f810f4d

Browse files
authored
Merge pull request #9289 from tannewt/esp_ble_bonding
Support BLE pairing and bonding on ESP
2 parents 7a27366 + 79ef1f7 commit f810f4d

File tree

3 files changed

+88
-24
lines changed

3 files changed

+88
-24
lines changed

ports/espressif/common-hal/_bleio/Adapter.c

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ static void _on_sync(void) {
6969
xTaskNotifyGive(cp_task);
7070
}
7171

72+
// All examples have this. It'd make sense in a header.
73+
void ble_store_config_init(void);
74+
7275
void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) {
7376
const bool is_enabled = common_hal_bleio_adapter_get_enabled(self);
7477

@@ -93,6 +96,20 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
9396
ble_hs_cfg.sync_cb = _on_sync;
9497
// ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
9598

99+
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
100+
ble_hs_cfg.sm_bonding = 1;
101+
/* Enable the appropriate bit masks to make sure the keys
102+
* that are needed are exchanged
103+
*/
104+
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
105+
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
106+
107+
ble_hs_cfg.sm_mitm = 1;
108+
ble_hs_cfg.sm_sc = 1;
109+
/* Stores the IRK */
110+
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
111+
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
112+
96113
ble_svc_gap_init();
97114
ble_svc_gatt_init();
98115
ble_svc_ans_init();
@@ -115,6 +132,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
115132
connection->conn_handle = BLEIO_HANDLE_INVALID;
116133
}
117134

135+
ble_store_config_init();
136+
118137
cp_task = xTaskGetCurrentTaskHandle();
119138

120139
nimble_port_freertos_init(nimble_host_task);
@@ -277,10 +296,13 @@ static int _mtu_reply(uint16_t conn_handle,
277296
const struct ble_gatt_error *error,
278297
uint16_t mtu, void *arg) {
279298
bleio_connection_internal_t *connection = (bleio_connection_internal_t *)arg;
280-
if (conn_handle != connection->conn_handle || error->status != 0) {
299+
if (conn_handle != connection->conn_handle) {
281300
return 0;
282301
}
283-
connection->mtu = mtu;
302+
if (error->status == 0) {
303+
connection->mtu = mtu;
304+
}
305+
xTaskNotify(cp_task, conn_handle, eSetValueWithOverwrite);
284306
return 0;
285307
}
286308

@@ -324,11 +346,11 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) {
324346
switch (event->type) {
325347
case BLE_GAP_EVENT_CONNECT:
326348
if (event->connect.status == 0) {
349+
// This triggers an MTU exchange. Its reply will unblock CP.
327350
_new_connection(event->connect.conn_handle);
328351
// Set connections objs back to NULL since we have a new
329352
// connection and need a new tuple.
330353
self->connection_objs = NULL;
331-
xTaskNotify(cp_task, event->connect.conn_handle, eSetValueWithOverwrite);
332354
} else {
333355
xTaskNotify(cp_task, -event->connect.status, eSetValueWithOverwrite);
334356
}
@@ -663,7 +685,7 @@ bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) {
663685
bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) {
664686
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
665687
bleio_connection_internal_t *connection = &bleio_connections[i];
666-
if (connection->conn_handle != BLEIO_HANDLE_INVALID) {
688+
if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) {
667689
return true;
668690
}
669691
}
@@ -678,7 +700,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
678700
mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT];
679701
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
680702
bleio_connection_internal_t *connection = &bleio_connections[i];
681-
if (connection->conn_handle != BLEIO_HANDLE_INVALID) {
703+
if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) {
682704
if (connection->connection_obj == mp_const_none) {
683705
connection->connection_obj = bleio_connection_new_from_internal(connection);
684706
}
@@ -691,14 +713,13 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
691713
}
692714

693715
void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) {
694-
mp_raise_NotImplementedError(NULL);
695-
// bonding_erase_storage();
716+
ble_store_clear();
696717
}
697718

698719
bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) {
699-
mp_raise_NotImplementedError(NULL);
700-
// return bonding_peripheral_bond_count() > 0;
701-
return false;
720+
int count;
721+
ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count);
722+
return count > 0;
702723
}
703724

704725
void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) {

ports/espressif/common-hal/_bleio/Connection.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,31 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in)
5555
}
5656

5757
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: {
58-
#if CIRCUITPY_VERBOSE_BLE
59-
mp_printf(&mp_plat_print, "TODO connection event: PHY update complete\n");
60-
#endif
58+
// Nothing to do here. CircuitPython doesn't tell the user what PHY
59+
// we're on.
6160
break;
6261
}
6362

6463
case BLE_GAP_EVENT_CONN_UPDATE: {
65-
#if CIRCUITPY_VERBOSE_BLE
66-
mp_printf(&mp_plat_print, "TODO connection event: connection update\n");
67-
#endif
64+
struct ble_gap_conn_desc desc;
65+
int rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
66+
assert(rc == 0);
67+
connection->conn_params_updating = false;
6868
break;
6969
}
70-
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
71-
#if CIRCUITPY_VERBOSE_BLE
72-
mp_printf(&mp_plat_print, "TODO connection event: l2cap update request\n");
73-
#endif
70+
case BLE_GAP_EVENT_ENC_CHANGE: {
71+
struct ble_gap_conn_desc desc;
72+
ble_gap_conn_find(event->enc_change.conn_handle, &desc);
73+
if (desc.sec_state.encrypted) {
74+
connection->pair_status = PAIR_PAIRED;
75+
}
76+
break;
77+
}
78+
case BLE_GAP_EVENT_MTU: {
79+
if (event->mtu.conn_handle != connection->conn_handle) {
80+
return 0;
81+
}
82+
connection->mtu = event->mtu.value;
7483
break;
7584
}
7685

@@ -113,15 +122,34 @@ void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) {
113122
}
114123

115124
void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) {
116-
// TODO: Implement this.
125+
// We may already be trying to pair if we just reconnected to a peer we're
126+
// bonded with.
127+
while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) {
128+
RUN_BACKGROUND_TASKS;
129+
}
130+
if (self->pair_status == PAIR_PAIRED) {
131+
return;
132+
}
133+
self->pair_status = PAIR_WAITING;
134+
CHECK_NIMBLE_ERROR(ble_gap_security_initiate(self->conn_handle));
135+
while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) {
136+
RUN_BACKGROUND_TASKS;
137+
}
138+
if (mp_hal_is_interrupted()) {
139+
return;
140+
}
117141
}
118142

119143
mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) {
120-
// TODO: Implement this.
121144
while (self->conn_params_updating && !mp_hal_is_interrupted()) {
122145
RUN_BACKGROUND_TASKS;
123146
}
124-
return 0;
147+
if (mp_hal_is_interrupted()) {
148+
return 0;
149+
}
150+
struct ble_gap_conn_desc desc;
151+
CHECK_NIMBLE_ERROR(ble_gap_conn_find(self->conn_handle, &desc));
152+
return 1.25f * desc.conn_itvl;
125153
}
126154

127155
// Return the current negotiated MTU length, minus overhead.
@@ -131,7 +159,16 @@ mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_inte
131159

132160
void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) {
133161
self->conn_params_updating = true;
134-
// TODO: Implement this.
162+
struct ble_gap_conn_desc desc;
163+
CHECK_NIMBLE_ERROR(ble_gap_conn_find(self->conn_handle, &desc));
164+
uint16_t interval = new_interval / 1.25f;
165+
struct ble_gap_upd_params updated = {
166+
.itvl_min = interval,
167+
.itvl_max = interval,
168+
.latency = desc.conn_latency,
169+
.supervision_timeout = desc.supervision_timeout
170+
};
171+
CHECK_NIMBLE_ERROR(ble_gap_update_params(self->conn_handle, &updated));
135172
}
136173

137174
static volatile int _last_discovery_status;

ports/espressif/common-hal/_bleio/__init__.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ void check_ble_error(int error_code, const char *file, size_t line) {
9797
return;
9898
}
9999
switch (error_code) {
100+
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
101+
mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Insufficient authentication"));
102+
return;
103+
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
104+
mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Insufficient encryption"));
105+
return;
100106
default:
101107
#if CIRCUITPY_VERBOSE_BLE
102108
if (file) {

0 commit comments

Comments
 (0)