Skip to content

Commit 8b61333

Browse files
authored
Merge pull request #2510 from dhalbert/bonding-nvm
nrf: Add bonding to BLE pairing support
2 parents 765a54a + 85dc408 commit 8b61333

File tree

21 files changed

+581
-71
lines changed

21 files changed

+581
-71
lines changed

locale/circuitpython.pot

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2020-01-07 14:31-0800\n"
11+
"POT-Creation-Date: 2020-01-13 18:15-0500\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -513,21 +513,21 @@ msgstr ""
513513
msgid "Could not initialize UART"
514514
msgstr ""
515515

516-
#: shared-module/audiomp3/MP3File.c
516+
#: shared-module/audiomp3/MP3Decoder.c
517517
msgid "Couldn't allocate decoder"
518518
msgstr ""
519519

520520
#: shared-module/audiocore/WaveFile.c shared-module/audiomixer/Mixer.c
521-
#: shared-module/audiomp3/MP3File.c
521+
#: shared-module/audiomp3/MP3Decoder.c
522522
msgid "Couldn't allocate first buffer"
523523
msgstr ""
524524

525-
#: shared-module/audiomp3/MP3File.c
525+
#: shared-module/audiomp3/MP3Decoder.c
526526
msgid "Couldn't allocate input buffer"
527527
msgstr ""
528528

529529
#: shared-module/audiocore/WaveFile.c shared-module/audiomixer/Mixer.c
530-
#: shared-module/audiomp3/MP3File.c
530+
#: shared-module/audiomp3/MP3Decoder.c
531531
msgid "Couldn't allocate second buffer"
532532
msgstr ""
533533

@@ -620,7 +620,7 @@ msgstr ""
620620
msgid "Failed sending command."
621621
msgstr ""
622622

623-
#: ports/nrf/sd_mutex.c
623+
#: ports/nrf/sd.c ports/nrf/sd_mutex.c
624624
#, c-format
625625
msgid "Failed to acquire mutex, err 0x%04x"
626626
msgstr ""
@@ -643,11 +643,11 @@ msgstr ""
643643
msgid "Failed to connect: timeout"
644644
msgstr ""
645645

646-
#: shared-module/audiomp3/MP3File.c
646+
#: shared-module/audiomp3/MP3Decoder.c
647647
msgid "Failed to parse MP3 file"
648648
msgstr ""
649649

650-
#: ports/nrf/sd_mutex.c
650+
#: ports/nrf/sd.c ports/nrf/sd_mutex.c
651651
#, c-format
652652
msgid "Failed to release mutex, err 0x%04x"
653653
msgstr ""
@@ -660,10 +660,6 @@ msgstr ""
660660
msgid "File exists"
661661
msgstr ""
662662

663-
#: ports/nrf/common-hal/nvm/ByteArray.c
664-
msgid "Flash write failed"
665-
msgstr ""
666-
667663
#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
668664
msgid "Frequency captured is above capability. Capture Paused."
669665
msgstr ""
@@ -1776,7 +1772,7 @@ msgstr ""
17761772
msgid "extra positional arguments given"
17771773
msgstr ""
17781774

1779-
#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3File.c
1775+
#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c
17801776
#: shared-bindings/displayio/OnDiskBitmap.c
17811777
msgid "file must be a file opened in byte mode"
17821778
msgstr ""

ports/atmel-samd/common-hal/nvm/ByteArray.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t *self,
4343
// whenever we need it instead of storing it long term.
4444
struct flash_descriptor desc;
4545
desc.dev.hw = NVMCTRL;
46-
flash_write(&desc, (uint32_t) self->start_address + start_index, values, len);
46+
bool status = flash_write(&desc, (uint32_t) self->start_address + start_index, values, len) == ERR_NONE;
4747
assert_heap_ok();
48-
return true;
48+
return status;
4949
}
5050

5151
// NVM memory is memory mapped so reading it is easy.

ports/nrf/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ INC += -I$(BUILD)
7373
INC += -I$(BUILD)/genhdr
7474
INC += -I./../../lib/cmsis/inc
7575
INC += -I./boards/$(BOARD)
76-
INC += -I./modules/ubluepy
77-
INC += -I./modules/ble
7876
INC += -I./nrfx
7977
INC += -I./nrfx/hal
8078
INC += -I./nrfx/mdk
@@ -157,6 +155,7 @@ SRC_C += \
157155
boards/$(BOARD)/pins.c \
158156
device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \
159157
bluetooth/ble_drv.c \
158+
common-hal/_bleio/bonding.c \
160159
lib/libc/string0.c \
161160
lib/mp-readline/readline.c \
162161
lib/oofatfs/ff.c \

ports/nrf/background.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
#if CIRCUITPY_BLEIO
4545
#include "supervisor/shared/bluetooth.h"
46+
#include "common-hal/_bleio/bonding.h"
4647
#endif
4748

4849
static bool running_background_tasks = false;
@@ -68,6 +69,7 @@ void run_background_tasks(void) {
6869

6970
#if CIRCUITPY_BLEIO
7071
supervisor_bluetooth_background();
72+
bonding_background();
7173
#endif
7274

7375
#if CIRCUITPY_DISPLAYIO

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "ble.h"
3434
#include "ble_drv.h"
35+
#include "bonding.h"
3536
#include "nrfx_power.h"
3637
#include "nrf_nvic.h"
3738
#include "nrf_sdm.h"
@@ -248,6 +249,7 @@ STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
248249
}
249250
ble_drv_remove_event_handler(connection_on_ble_evt, connection);
250251
connection->conn_handle = BLE_CONN_HANDLE_INVALID;
252+
connection->pair_status = PAIR_NOT_PAIRED;
251253
if (connection->connection_obj != mp_const_none) {
252254
bleio_connection_obj_t* obj = connection->connection_obj;
253255
obj->connection = NULL;
@@ -692,6 +694,10 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
692694
return self->connection_objs;
693695
}
694696

697+
void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) {
698+
bonding_erase_storage();
699+
}
700+
695701
void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) {
696702
gc_collect_root((void**)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t));
697703
gc_collect_root((void**)bleio_connections, sizeof(bleio_connections) / sizeof(size_t));

ports/nrf/common-hal/_bleio/Characteristic.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "shared-bindings/_bleio/Service.h"
3434

3535
#include "common-hal/_bleio/Adapter.h"
36+
#include "common-hal/_bleio/bonding.h"
3637

3738
STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) {
3839
uint16_t cccd;

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

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,16 @@
4646
#include "shared-bindings/_bleio/Characteristic.h"
4747
#include "shared-bindings/_bleio/Service.h"
4848
#include "shared-bindings/_bleio/UUID.h"
49+
#include "supervisor/shared/tick.h"
50+
51+
#include "common-hal/_bleio/bonding.h"
4952

5053
#define BLE_ADV_LENGTH_FIELD_SIZE 1
5154
#define BLE_ADV_AD_TYPE_FIELD_SIZE 1
5255
#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1
5356

5457
static const ble_gap_sec_params_t pairing_sec_params = {
55-
.bond = 0,
58+
.bond = 1,
5659
.mitm = 0,
5760
.lesc = 0,
5861
.keypress = 0,
@@ -64,6 +67,13 @@ static const ble_gap_sec_params_t pairing_sec_params = {
6467
.kdist_peer = { .enc = 1, .id = 1},
6568
};
6669

70+
#define CONNECTION_DEBUG (1)
71+
#if CONNECTION_DEBUG
72+
#define CONNECTION_DEBUG_PRINTF(...) printf(__VA_ARGS__)
73+
#else
74+
#define CONNECTION_DEBUG_PRINTF(...)
75+
#endif
76+
6777
static volatile bool m_discovery_in_process;
6878
static volatile bool m_discovery_successful;
6979

@@ -84,6 +94,7 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
8494

8595
switch (ble_evt->header.evt_id) {
8696
case BLE_GAP_EVT_DISCONNECTED:
97+
// Adapter.c does the work for this event.
8798
break;
8899

89100
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
@@ -137,6 +148,22 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
137148
break;
138149
}
139150

151+
case BLE_GATTS_EVT_WRITE:
152+
// A client wrote a value.
153+
// If we are bonded and it's a CCCD (UUID 0x2902), store the CCCD value.
154+
if (self->conn_handle != BLE_CONN_HANDLE_INVALID &&
155+
self->pair_status == PAIR_PAIRED &&
156+
ble_evt->evt.gatts_evt.params.write.uuid.type == BLE_UUID_TYPE_BLE &&
157+
ble_evt->evt.gatts_evt.params.write.uuid.uuid == 0x2902) {
158+
//
159+
// Save sys_attr data (CCCD state) in bonding area at
160+
// next opportunity, but also remember time of this
161+
// request, so we can consolidate closely-spaced requests.
162+
self->do_bond_cccds = true;
163+
self->do_bond_cccds_request_time = supervisor_ticks_ms64();
164+
}
165+
break;
166+
140167
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
141168
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
142169
break;
@@ -197,6 +224,15 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
197224
break;
198225
}
199226
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: {
227+
// First time pairing.
228+
// 1. Either we or peer initiate the process
229+
// 2. Peer asks for security parameters using BLE_GAP_EVT_SEC_PARAMS_REQUEST.
230+
// 3. Pair Key exchange ("just works" implemented now; TODO: out-of-band key pairing)
231+
// 4. Connection is secured: BLE_GAP_EVT_CONN_SEC_UPDATE
232+
// 5. Long-term Keys exchanged: BLE_GAP_EVT_AUTH_STATUS
233+
234+
bonding_clear_keys(&self->bonding_keys);
235+
self->ediv = EDIV_INVALID;
200236
ble_gap_sec_keyset_t keyset = {
201237
.keys_own = {
202238
.p_enc_key = &self->bonding_keys.own_enc,
@@ -214,7 +250,8 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
214250
};
215251

216252
sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS,
217-
&pairing_sec_params, &keyset);
253+
self->is_central ? NULL : &pairing_sec_params,
254+
&keyset);
218255
break;
219256
}
220257

@@ -224,13 +261,16 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
224261
break;
225262

226263
case BLE_GAP_EVT_AUTH_STATUS: { // 0x19
227-
// Pairing process completed
264+
// Key exchange completed.
228265
ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status;
229266
self->sec_status = status->auth_status;
230267
if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
231-
// TODO _ediv = bonding_keys->own_enc.master_id.ediv;
268+
self->ediv = self->bonding_keys.own_enc.master_id.ediv;
232269
self->pair_status = PAIR_PAIRED;
270+
// Save keys in bonding area at next opportunity.
271+
self->do_bond_keys = true;
233272
} else {
273+
// Inform busy-waiter pairing has failed.
234274
self->pair_status = PAIR_NOT_PAIRED;
235275
}
236276
break;
@@ -242,17 +282,22 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
242282
// - Else return NULL --> Initiate key exchange
243283
ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request;
244284
(void) sec_info_request;
245-
//if ( bond_load_keys(_role, sec_req->master_id.ediv, &bkeys) ) {
246-
//sd_ble_gap_sec_info_reply(_conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL);
247-
//
248-
//_ediv = bkeys.own_enc.master_id.ediv;
249-
// } else {
285+
if ( bonding_load_keys(self->is_central, sec_info_request->master_id.ediv, &self->bonding_keys) ) {
286+
sd_ble_gap_sec_info_reply(
287+
self->conn_handle,
288+
&self->bonding_keys.own_enc.enc_info,
289+
&self->bonding_keys.peer_id.id_info,
290+
NULL);
291+
self->ediv = self->bonding_keys.own_enc.master_id.ediv;
292+
} else {
293+
// We don't have stored keys. Ask for keys.
250294
sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL);
251-
// }
252-
break;
295+
}
296+
break;
253297
}
254298

255299
case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a
300+
// We get this both on first-time pairing and on subsequent pairings using stored keys.
256301
ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec;
257302
if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) {
258303
// Security setup did not succeed:
@@ -261,18 +306,17 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
261306
// mode >=1 and/or level >=1 means encryption is set up
262307
self->pair_status = PAIR_NOT_PAIRED;
263308
} else {
264-
//if ( !bond_load_cccd(_role, _conn_hdl, _ediv) ) {
265-
if (true) { // TODO: no bonding yet
266-
// Initialize system attributes fresh.
309+
if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) {
310+
// Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values.
311+
} else {
312+
// No matching bonding found, so use fresh system attributes.
267313
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
268314
}
269-
// Not quite paired yet: wait for BLE_GAP_EVT_AUTH_STATUS SUCCESS.
270-
self->ediv = self->bonding_keys.own_enc.master_id.ediv;
315+
self->pair_status = PAIR_PAIRED;
271316
}
272317
break;
273318
}
274319

275-
276320
default:
277321
return false;
278322
}
@@ -284,8 +328,7 @@ void bleio_connection_clear(bleio_connection_internal_t *self) {
284328

285329
self->conn_handle = BLE_CONN_HANDLE_INVALID;
286330
self->pair_status = PAIR_NOT_PAIRED;
287-
288-
memset(&self->bonding_keys, 0, sizeof(self->bonding_keys));
331+
bonding_clear_keys(&self->bonding_keys);
289332
}
290333

291334
bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) {
@@ -565,8 +608,7 @@ STATIC bool discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t payload) {
565608
break;
566609

567610
default:
568-
// For debugging.
569-
// mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id);
611+
// CONNECTION_DEBUG_PRINTF(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id);
570612
return false;
571613
break;
572614
}

ports/nrf/common-hal/_bleio/Connection.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "py/objlist.h"
3737

3838
#include "common-hal/_bleio/__init__.h"
39+
#include "common-hal/_bleio/bonding.h"
3940
#include "shared-module/_bleio/Address.h"
4041
#include "common-hal/_bleio/Service.h"
4142

@@ -56,16 +57,23 @@ typedef struct {
5657
// The advertising data and scan response buffers are held by us, not by the SD, so we must
5758
// maintain them and not change it. If we need to change the contents during advertising,
5859
// there are tricks to get the SD to notice (see DevZone - TBS).
59-
// EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing.
6060
bonding_keys_t bonding_keys;
61+
// EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing.
6162
uint16_t ediv;
62-
pair_status_t pair_status;
63+
volatile pair_status_t pair_status;
6364
uint8_t sec_status; // Internal security status.
6465
mp_obj_t connection_obj;
6566
ble_drv_evt_handler_entry_t handler_entry;
6667
ble_gap_conn_params_t conn_params;
6768
volatile bool conn_params_updating;
6869
uint16_t mtu;
70+
// Request that CCCD values for this conenction be saved, using sys_attr values.
71+
volatile bool do_bond_cccds;
72+
// Request that security key info for this connection be saved.
73+
volatile bool do_bond_keys;
74+
// Time of setting do_bond_ccds: we delay a bit to consolidate multiple CCCD changes
75+
// into one write. Time is currently in ticks_ms.
76+
uint64_t do_bond_cccds_request_time;
6977
} bleio_connection_internal_t;
7078

7179
typedef struct {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ void bleio_reset() {
9797
common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false);
9898
}
9999
supervisor_start_bluetooth();
100+
bonding_reset();
100101
}
101102

102103
// The singleton _bleio.Adapter object, bound to _bleio.adapter

ports/nrf/common-hal/_bleio/__init__.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
void bleio_reset(void);
3131

3232
typedef struct {
33-
ble_gap_enc_key_t own_enc;
34-
ble_gap_enc_key_t peer_enc;
35-
ble_gap_id_key_t peer_id;
33+
ble_gap_enc_key_t own_enc;
34+
ble_gap_enc_key_t peer_enc;
35+
ble_gap_id_key_t peer_id;
3636
} bonding_keys_t;
3737

3838
// We assume variable length data.

0 commit comments

Comments
 (0)