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>
This commit is contained in:
Jim Mussared 2020-11-25 17:28:04 +11:00 committed by Damien George
parent fff634e031
commit c4d08aa4e3
4 changed files with 240 additions and 30 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 \