summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Mussared <jim.mussared@gmail.com>2020-11-25 17:28:04 +1100
committerDamien George <damien@micropython.org>2020-12-02 14:41:41 +1100
commitc4d08aa4e3641a1d05d35051454d4bce8ef14fcf (patch)
tree377b623a76cf33fc3b175f74dcb0347c5cfbe152
parentfff634e03134b8f1724759f477da61b698c9cdf4 (diff)
extmod/modbluetooth: Add support for bonding (key persistence).
This adds `_IRQ_GET_SECRET` and `_IRQ_SET_SECRET` events to allow the BT stack to request the Python code retrive/store/delete secret key data. The actual keys and values are opaque to Python and stack-specific. Only NimBLE is implemented (pending moving btstack to sync events). The secret store is designed to be compatible with BlueKitchen's TLV store API. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
-rw-r--r--extmod/modbluetooth.c78
-rw-r--r--extmod/modbluetooth.h18
-rw-r--r--extmod/nimble/modbluetooth_nimble.c172
-rw-r--r--extmod/nimble/nimble.mk2
4 files changed, 240 insertions, 30 deletions
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index 0d33130db..a69e8418a 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -1081,14 +1081,15 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
const uint8_t *addr,
const int8_t *i8, size_t n_i8,
const mp_obj_bluetooth_uuid_t *uuid,
- const uint8_t *data, size_t data_len) {
+ const uint8_t **data, size_t *data_len, size_t n_data) {
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
if (o->irq_handler == mp_const_none) {
return mp_const_none;
}
mp_obj_array_t mv_addr;
- mp_obj_array_t mv_data;
+ mp_obj_array_t mv_data[2];
+ assert(n_data <= 2);
mp_obj_tuple_t *data_tuple = mp_local_alloc(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t) * MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN);
data_tuple->base.type = &mp_type_tuple;
@@ -1112,9 +1113,13 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
}
#endif
- if (data) {
- mp_obj_memoryview_init(&mv_data, 'B', 0, data_len, (void *)data);
- data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data);
+ for (size_t i = 0; i < n_data; ++i) {
+ if (data[i]) {
+ mp_obj_memoryview_init(&mv_data[i], 'B', 0, data_len[i], (void *)data[i]);
+ data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data[i]);
+ } else {
+ data_tuple->items[data_tuple->len++] = mp_const_none;
+ }
}
assert(data_tuple->len <= MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN);
@@ -1131,36 +1136,57 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
#define NULL_I8 NULL
#define NULL_UUID NULL
#define NULL_DATA NULL
+#define NULL_DATA_LEN NULL
void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
- invoke_irq_handler(event, &conn_handle, 1, &addr_type, 1, addr, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(event, &conn_handle, 1, &addr_type, 1, addr, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gap_on_connection_update(uint16_t conn_handle, uint16_t conn_interval, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t status) {
uint16_t args[] = {conn_handle, conn_interval, conn_latency, supervision_timeout, status};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_CONNECTION_UPDATE, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_CONNECTION_UPDATE, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypted, bool authenticated, bool bonded, uint8_t key_size) {
uint8_t args[] = {encrypted, authenticated, bonded, key_size};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE, &conn_handle, 1, args, 4, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE, &conn_handle, 1, args, 4, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
+}
+
+bool mp_bluetooth_gap_on_get_secret(uint8_t type, uint8_t index, const uint8_t *key, size_t key_len, const uint8_t **value, size_t *value_len) {
+ uint8_t args[] = {type, index};
+ mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GET_SECRET, NULL_U16, 0, args, 2, NULL_ADDR, NULL_I8, 0, NULL_UUID, &key, &key_len, 1);
+ if (result == mp_const_none) {
+ return false;
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_READ);
+ *value = bufinfo.buf;
+ *value_len = bufinfo.len;
+ return true;
+}
+
+bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key_len, const uint8_t *value, size_t value_len) {
+ const uint8_t *data[] = {key, value};
+ size_t data_len[] = {key_len, value_len};
+ mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_SET_SECRET, NULL_U16, 0, &type, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, data, data_len, 2);
+ return mp_obj_is_true(result);
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
uint16_t args[] = {conn_handle, value_handle};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_WRITE, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_WRITE, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
uint16_t args[] = {conn_handle, value_handle};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE, args, 2, &status, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE, args, 2, &status, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
uint16_t args[] = {conn_handle, value_handle};
- mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST, args, 2, NULL, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST, args, 2, NULL, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
// Return non-zero from IRQ handler to fail the read.
mp_int_t ret = 0;
mp_obj_get_int_maybe(result, &ret);
@@ -1169,13 +1195,13 @@ mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value
void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
uint16_t args[] = {conn_handle, value};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_MTU_EXCHANGED, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_MTU_EXCHANGED, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
#if MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
mp_int_t mp_bluetooth_gattc_on_l2cap_accept(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) {
uint16_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
- mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_ACCEPT, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_ACCEPT, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
// Return non-zero from IRQ handler to fail the accept.
mp_int_t ret = 0;
mp_obj_get_int_maybe(result, &ret);
@@ -1184,58 +1210,58 @@ mp_int_t mp_bluetooth_gattc_on_l2cap_accept(uint16_t conn_handle, uint16_t cid,
void mp_bluetooth_gattc_on_l2cap_connect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t our_mtu, uint16_t peer_mtu) {
uint16_t args[] = {conn_handle, cid, psm, our_mtu, peer_mtu};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_CONNECT, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_CONNECT, args, 5, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_l2cap_disconnect(uint16_t conn_handle, uint16_t cid, uint16_t psm, uint16_t status) {
uint16_t args[] = {conn_handle, cid, psm, status};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT, args, 4, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_DISCONNECT, args, 4, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) {
uint16_t args[] = {conn_handle, cid};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_SEND_READY, args, 2, &status, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_SEND_READY, args, 2, &status, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) {
uint16_t args[] = {conn_handle, cid};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_RECV, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_L2CAP_RECV, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
void mp_bluetooth_gap_on_scan_complete(void) {
- invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_DONE, NULL_U16, 0, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_DONE, NULL_U16, 0, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len) {
int8_t args[] = {adv_type, rssi};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, NULL_U16, 0, &addr_type, 1, addr, args, 2, NULL_UUID, data, data_len);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, NULL_U16, 0, &addr_type, 1, addr, args, 2, NULL_UUID, &data, &data_len, 1);
}
void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) {
uint16_t args[] = {conn_handle, start_handle, end_handle};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, service_uuid, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, service_uuid, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) {
uint16_t args[] = {conn_handle, def_handle, value_handle};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, args, 3, &properties, 1, NULL_ADDR, NULL_I8, 0, characteristic_uuid, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, args, 3, &properties, 1, NULL_ADDR, NULL_I8, 0, characteristic_uuid, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
uint16_t args[] = {conn_handle, handle};
- invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, descriptor_uuid, NULL_DATA, 0);
+ invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, descriptor_uuid, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
uint16_t args[] = {conn_handle, status};
- invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num) {
const uint8_t *combined_data;
- uint16_t total_len;
+ size_t total_len;
if (num > 1) {
// Fragmented buffer, need to combine into a new heap-allocated buffer
@@ -1258,7 +1284,7 @@ void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, u
}
uint16_t args[] = {conn_handle, value_handle};
- invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, combined_data, total_len);
+ invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, &combined_data, &total_len, 1);
if (num > 1) {
m_del(uint8_t, (uint8_t *)combined_data, total_len);
@@ -1267,7 +1293,7 @@ void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, u
void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
uint16_t args[] = {conn_handle, value_handle, status};
- invoke_irq_handler(event, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
+ invoke_irq_handler(event, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, NULL_DATA_LEN, 0);
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index 48e75d432..d79b7f56b 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -146,6 +146,8 @@
#define MP_BLUETOOTH_IRQ_L2CAP_SEND_READY (26)
#define MP_BLUETOOTH_IRQ_CONNECTION_UPDATE (27)
#define MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE (28)
+#define MP_BLUETOOTH_IRQ_GET_SECRET (29)
+#define MP_BLUETOOTH_IRQ_SET_SECRET (30)
#define MP_BLUETOOTH_ADDRESS_MODE_PUBLIC (0)
#define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1)
@@ -159,6 +161,12 @@
#define MP_BLUETOOTH_IO_CAPABILITY_NO_INPUT_OUTPUT (3)
#define MP_BLUETOOTH_IO_CAPABILITY_KEYBOARD_DISPLAY (4)
+// These match NimBLE BLE_SM_IOACT_.
+#define MP_BLUETOOTH_PASSKEY_ACTION_NONE (0)
+#define MP_BLUETOOTH_PASSKEY_ACTION_INPUT (2)
+#define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3)
+#define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4)
+
/*
These aren't included in the module for space reasons, but can be used
in your Python code if necessary.
@@ -192,6 +200,8 @@ _IRQ_L2CAP_RECV = const(25)
_IRQ_L2CAP_SEND_READY = const(26)
_IRQ_CONNECTION_UPDATE = const(27)
_IRQ_ENCRYPTION_UPDATE = const(28)
+_IRQ_GET_SECRET = const(29)
+_IRQ_SET_SECRET = const(30)
_FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002)
@@ -373,7 +383,13 @@ void mp_bluetooth_gap_on_connection_update(uint16_t conn_handle, uint16_t conn_i
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
// Call this when any connection encryption has been changed (e.g. during pairing).
void mp_bluetooth_gatts_on_encryption_update(uint16_t conn_handle, bool encrypted, bool authenticated, bool bonded, uint8_t key_size);
-#endif
+
+// Call this when you need the application to manage persistent key data.
+// For get, if key is NULL, then the implementation must return the index'th matching key. Otherwise it should return a specific key.
+// For set, if value is NULL, then delete.
+bool mp_bluetooth_gap_on_get_secret(uint8_t type, uint8_t index, const uint8_t *key, size_t key_len, const uint8_t **value, size_t *value_len);
+bool mp_bluetooth_gap_on_set_secret(uint8_t type, const uint8_t *key, size_t key_len, const uint8_t *value, size_t value_len);
+#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
// Call this when a characteristic is written to.
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle);
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index b1f13ee98..2b273c6bc 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -269,6 +269,7 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
+ DEBUG_printf("gap_event_cb: connect: status=%d\n", event->connect.status);
if (event->connect.status == 0) {
// Connection established.
ble_gap_conn_find(event->connect.conn_handle, &desc);
@@ -282,6 +283,7 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
case BLE_GAP_EVENT_DISCONNECT:
// Disconnect.
+ DEBUG_printf("gap_event_cb: disconnect: reason=%d\n", event->disconnect.reason);
reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val);
mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_CENTRAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr);
break;
@@ -310,7 +312,6 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
case BLE_GAP_EVENT_CONN_UPDATE: {
DEBUG_printf("gap_event_cb: connection update: status=%d\n", event->conn_update.status);
- struct ble_gap_conn_desc desc;
if (ble_gap_conn_find(event->conn_update.conn_handle, &desc) == 0) {
mp_bluetooth_gap_on_connection_update(event->conn_update.conn_handle, desc.conn_itvl, desc.conn_latency, desc.supervision_timeout, event->conn_update.status == 0 ? 0 : 1);
}
@@ -320,7 +321,6 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
case BLE_GAP_EVENT_ENC_CHANGE: {
DEBUG_printf("gap_event_cb: enc change: status=%d\n", event->enc_change.status);
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
- struct ble_gap_conn_desc desc;
if (ble_gap_conn_find(event->enc_change.conn_handle, &desc) == 0) {
mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle,
desc.sec_state.encrypted, desc.sec_state.authenticated,
@@ -329,6 +329,27 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
#endif
break;
}
+
+ case BLE_GAP_EVENT_REPEAT_PAIRING: {
+ // We recognized this peer but the peer doesn't recognize us.
+ DEBUG_printf("gap_event_cb: repeat pairing: conn_handle=%d\n", event->repeat_pairing.conn_handle);
+
+ // TODO: Consider returning BLE_GAP_REPEAT_PAIRING_IGNORE (and
+ // possibly an API to configure this).
+
+ // Delete the old bond.
+ int rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+ if (rc == 0) {
+ ble_store_util_delete_peer(&desc.peer_id_addr);
+ }
+
+ // Allow re-pairing.
+ return BLE_GAP_REPEAT_PAIRING_RETRY;
+ }
+
+ default:
+ DEBUG_printf("gap_event_cb: unknown type %d\n", event->type);
+ break;
}
return 0;
}
@@ -969,6 +990,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
+ DEBUG_printf("peripheral_gap_event_cb: status=%d\n", event->connect.status);
if (event->connect.status == 0) {
// Connection established.
ble_gap_conn_find(event->connect.conn_handle, &desc);
@@ -982,6 +1004,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
case BLE_GAP_EVENT_DISCONNECT:
// Disconnect.
+ DEBUG_printf("peripheral_gap_event_cb: reason=%d\n", event->disconnect.reason);
reverse_addr_byte_order(addr, event->disconnect.conn.peer_id_addr.val);
mp_bluetooth_gap_on_connected_disconnected(MP_BLUETOOTH_IRQ_PERIPHERAL_DISCONNECT, event->disconnect.conn.conn_handle, event->disconnect.conn.peer_id_addr.type, addr);
@@ -1020,9 +1043,12 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
#endif
break;
}
+
default:
+ DEBUG_printf("peripheral_gap_event_cb: unknown type %d\n", event->type);
break;
}
+
return 0;
}
@@ -1514,4 +1540,146 @@ int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf
#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
+#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
+
+STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {
+ DEBUG_printf("ble_store_ram_read: %d\n", obj_type);
+ const uint8_t *key_data;
+ size_t key_data_len;
+
+ switch (obj_type) {
+ case BLE_STORE_OBJ_TYPE_PEER_SEC: {
+ if (ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)) {
+ // <type=peer,addr,*> (single)
+ // Find the entry for this specific peer.
+ assert(key->sec.idx == 0);
+ assert(!key->sec.ediv_rand_present);
+ key_data = (const uint8_t *)&key->sec.peer_addr;
+ key_data_len = sizeof(ble_addr_t);
+ } else {
+ // <type=peer,*> (with index)
+ // Iterate all known peers.
+ assert(!key->sec.ediv_rand_present);
+ key_data = NULL;
+ key_data_len = 0;
+ }
+ break;
+ }
+ case BLE_STORE_OBJ_TYPE_OUR_SEC: {
+ // <type=our,addr,ediv_rand>
+ // Find our secret for this remote device, matching this ediv/rand key.
+ assert(ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)); // Must have address.
+ assert(key->sec.idx == 0);
+ assert(key->sec.ediv_rand_present);
+ key_data = (const uint8_t *)&key->sec.peer_addr;
+ key_data_len = sizeof(ble_addr_t);
+ break;
+ }
+ case BLE_STORE_OBJ_TYPE_CCCD: {
+ // TODO: Implement CCCD persistence.
+ DEBUG_printf("ble_store_ram_read: CCCD not supported.\n");
+ return -1;
+ }
+ default:
+ return BLE_HS_ENOTSUP;
+ }
+
+ const uint8_t *value_data;
+ size_t value_data_len;
+ if (!mp_bluetooth_gap_on_get_secret(obj_type, key->sec.idx, key_data, key_data_len, &value_data, &value_data_len)) {
+ DEBUG_printf("ble_store_ram_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len);
+ return BLE_HS_ENOENT;
+ }
+
+ if (value_data_len != sizeof(struct ble_store_value_sec)) {
+ DEBUG_printf("ble_store_ram_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec));
+ return BLE_HS_ENOENT;
+ }
+
+ memcpy((uint8_t *)&value->sec, value_data, sizeof(struct ble_store_value_sec));
+
+ DEBUG_printf("ble_store_ram_read: found secret\n");
+
+ if (obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC) {
+ // TODO: Verify ediv_rand matches.
+ }
+
+ return 0;
+}
+
+STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
+ DEBUG_printf("ble_store_ram_write: %d\n", obj_type);
+ switch (obj_type) {
+ case BLE_STORE_OBJ_TYPE_PEER_SEC:
+ case BLE_STORE_OBJ_TYPE_OUR_SEC: {
+ // <type=peer,addr,edivrand>
+
+ struct ble_store_key_sec key_sec;
+ const struct ble_store_value_sec *value_sec = &val->sec;
+ ble_store_key_from_value_sec(&key_sec, value_sec);
+
+ assert(ble_addr_cmp(&key_sec.peer_addr, BLE_ADDR_ANY)); // Must have address.
+ assert(key_sec.ediv_rand_present);
+
+ if (!mp_bluetooth_gap_on_set_secret(obj_type, (const uint8_t *)&key_sec.peer_addr, sizeof(ble_addr_t), (const uint8_t *)value_sec, sizeof(struct ble_store_value_sec))) {
+ DEBUG_printf("Failed to write key: type=%d\n", obj_type);
+ return BLE_HS_ESTORE_CAP;
+ }
+
+ DEBUG_printf("ble_store_ram_write: wrote secret\n");
+
+ return 0;
+ }
+ case BLE_STORE_OBJ_TYPE_CCCD: {
+ // TODO: Implement CCCD persistence.
+ DEBUG_printf("ble_store_ram_write: CCCD not supported.\n");
+ // Just pretend we wrote it.
+ return 0;
+ }
+ default:
+ return BLE_HS_ENOTSUP;
+ }
+}
+
+STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
+ DEBUG_printf("ble_store_ram_delete: %d\n", obj_type);
+ switch (obj_type) {
+ case BLE_STORE_OBJ_TYPE_PEER_SEC:
+ case BLE_STORE_OBJ_TYPE_OUR_SEC: {
+ // <type=peer,addr,*>
+
+ assert(ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)); // Must have address.
+ // ediv_rand is optional (will not be present for delete).
+
+ if (!mp_bluetooth_gap_on_set_secret(obj_type, (const uint8_t *)&key->sec.peer_addr, sizeof(ble_addr_t), NULL, 0)) {
+ DEBUG_printf("Failed to delete key: type=%d\n", obj_type);
+ return BLE_HS_ENOENT;
+ }
+
+ DEBUG_printf("ble_store_ram_delete: deleted secret\n");
+
+ return 0;
+ }
+ case BLE_STORE_OBJ_TYPE_CCCD: {
+ // TODO: Implement CCCD persistence.
+ DEBUG_printf("ble_store_ram_delete: CCCD not supported.\n");
+ // Just pretend it wasn't there.
+ return BLE_HS_ENOENT;
+ }
+ default:
+ return BLE_HS_ENOTSUP;
+ }
+}
+
+// nimble_port_init always calls ble_store_ram_init. We provide this alternative
+// implementation rather than the one in nimble/store/ram/src/ble_store_ram.c.
+// TODO: Consider re-implementing nimble_port_init instead.
+void ble_store_ram_init(void) {
+ ble_hs_cfg.store_read_cb = ble_store_ram_read;
+ ble_hs_cfg.store_write_cb = ble_store_ram_write;
+ ble_hs_cfg.store_delete_cb = ble_store_ram_delete;
+}
+
+#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
+
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
diff --git a/extmod/nimble/nimble.mk b/extmod/nimble/nimble.mk
index ba094f16f..806630074 100644
--- a/extmod/nimble/nimble.mk
+++ b/extmod/nimble/nimble.mk
@@ -83,7 +83,6 @@ LIB_SRC_C += $(addprefix $(NIMBLE_LIB_DIR)/, \
ble_store_util.c \
ble_uuid.c \
) \
- nimble/host/store/ram/src/ble_store_ram.c \
nimble/host/util/src/addr.c \
nimble/transport/uart/src/ble_hci_uart.c \
$(addprefix porting/nimble/src/, \
@@ -95,6 +94,7 @@ LIB_SRC_C += $(addprefix $(NIMBLE_LIB_DIR)/, \
os_msys_init.c \
) \
)
+ # nimble/host/store/ram/src/ble_store_ram.c \
EXTMOD_SRC_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \
nimble/nimble_npl_os.c \