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 uint8_t *addr,
const int8_t *i8, size_t n_i8, const int8_t *i8, size_t n_i8,
const mp_obj_bluetooth_uuid_t *uuid, 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)); mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
if (o->irq_handler == mp_const_none) { if (o->irq_handler == mp_const_none) {
return mp_const_none; return mp_const_none;
} }
mp_obj_array_t mv_addr; 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); 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; 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); data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
} }
#endif #endif
if (data) { for (size_t i = 0; i < n_data; ++i) {
mp_obj_memoryview_init(&mv_data, 'B', 0, data_len, (void *)data); if (data[i]) {
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data); 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); 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_I8 NULL
#define NULL_UUID NULL #define NULL_UUID NULL
#define NULL_DATA 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) { 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) { 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}; 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 #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) { 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}; 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 #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) { void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
uint16_t args[] = {conn_handle, 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) { 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}; 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) { mp_int_t mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
uint16_t args[] = {conn_handle, 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. // Return non-zero from IRQ handler to fail the read.
mp_int_t ret = 0; mp_int_t ret = 0;
mp_obj_get_int_maybe(result, &ret); 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) { void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
uint16_t args[] = {conn_handle, 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 #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) { 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}; 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. // Return non-zero from IRQ handler to fail the accept.
mp_int_t ret = 0; mp_int_t ret = 0;
mp_obj_get_int_maybe(result, &ret); 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) { 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}; 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) { 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}; 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) { void mp_bluetooth_gattc_on_l2cap_send_ready(uint16_t conn_handle, uint16_t cid, uint8_t status) {
uint16_t args[] = {conn_handle, cid}; 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) { void mp_bluetooth_gattc_on_l2cap_recv(uint16_t conn_handle, uint16_t cid) {
uint16_t args[] = {conn_handle, 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 #endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
void mp_bluetooth_gap_on_scan_complete(void) { 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) { 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}; 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) { 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}; 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) { 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}; 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) { 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}; 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) { void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
uint16_t args[] = {conn_handle, 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) { 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; const uint8_t *combined_data;
uint16_t total_len; size_t total_len;
if (num > 1) { if (num > 1) {
// Fragmented buffer, need to combine into a new heap-allocated buffer // 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}; 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) { if (num > 1) {
m_del(uint8_t, (uint8_t *)combined_data, total_len); 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) { 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}; 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 #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_L2CAP_SEND_READY (26)
#define MP_BLUETOOTH_IRQ_CONNECTION_UPDATE (27) #define MP_BLUETOOTH_IRQ_CONNECTION_UPDATE (27)
#define MP_BLUETOOTH_IRQ_ENCRYPTION_UPDATE (28) #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_PUBLIC (0)
#define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1) #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_NO_INPUT_OUTPUT (3)
#define MP_BLUETOOTH_IO_CAPABILITY_KEYBOARD_DISPLAY (4) #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 These aren't included in the module for space reasons, but can be used
in your Python code if necessary. in your Python code if necessary.
@@ -192,6 +200,8 @@ _IRQ_L2CAP_RECV = const(25)
_IRQ_L2CAP_SEND_READY = const(26) _IRQ_L2CAP_SEND_READY = const(26)
_IRQ_CONNECTION_UPDATE = const(27) _IRQ_CONNECTION_UPDATE = const(27)
_IRQ_ENCRYPTION_UPDATE = const(28) _IRQ_ENCRYPTION_UPDATE = const(28)
_IRQ_GET_SECRET = const(29)
_IRQ_SET_SECRET = const(30)
_FLAG_BROADCAST = const(0x0001) _FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002) _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 #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
// Call this when any connection encryption has been changed (e.g. during pairing). // 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); 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. // Call this when a characteristic is written to.
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle); 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) { switch (event->type) {
case BLE_GAP_EVENT_CONNECT: case BLE_GAP_EVENT_CONNECT:
DEBUG_printf("gap_event_cb: connect: status=%d\n", event->connect.status);
if (event->connect.status == 0) { if (event->connect.status == 0) {
// Connection established. // Connection established.
ble_gap_conn_find(event->connect.conn_handle, &desc); 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: case BLE_GAP_EVENT_DISCONNECT:
// 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); 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); 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; break;
@@ -310,7 +312,6 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
case BLE_GAP_EVENT_CONN_UPDATE: { case BLE_GAP_EVENT_CONN_UPDATE: {
DEBUG_printf("gap_event_cb: connection update: status=%d\n", event->conn_update.status); 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) { 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); 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: { case BLE_GAP_EVENT_ENC_CHANGE: {
DEBUG_printf("gap_event_cb: enc change: status=%d\n", event->enc_change.status); DEBUG_printf("gap_event_cb: enc change: status=%d\n", event->enc_change.status);
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING #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) { if (ble_gap_conn_find(event->enc_change.conn_handle, &desc) == 0) {
mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle, mp_bluetooth_gatts_on_encryption_update(event->conn_update.conn_handle,
desc.sec_state.encrypted, desc.sec_state.authenticated, 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 #endif
break; 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; return 0;
} }
@@ -969,6 +990,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
switch (event->type) { switch (event->type) {
case BLE_GAP_EVENT_CONNECT: case BLE_GAP_EVENT_CONNECT:
DEBUG_printf("peripheral_gap_event_cb: status=%d\n", event->connect.status);
if (event->connect.status == 0) { if (event->connect.status == 0) {
// Connection established. // Connection established.
ble_gap_conn_find(event->connect.conn_handle, &desc); 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: case BLE_GAP_EVENT_DISCONNECT:
// 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); 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); 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 #endif
break; break;
} }
default: default:
DEBUG_printf("peripheral_gap_event_cb: unknown type %d\n", event->type);
break; break;
} }
return 0; 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 #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 #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_store_util.c \
ble_uuid.c \ ble_uuid.c \
) \ ) \
nimble/host/store/ram/src/ble_store_ram.c \
nimble/host/util/src/addr.c \ nimble/host/util/src/addr.c \
nimble/transport/uart/src/ble_hci_uart.c \ nimble/transport/uart/src/ble_hci_uart.c \
$(addprefix porting/nimble/src/, \ $(addprefix porting/nimble/src/, \
@@ -95,6 +94,7 @@ LIB_SRC_C += $(addprefix $(NIMBLE_LIB_DIR)/, \
os_msys_init.c \ os_msys_init.c \
) \ ) \
) )
# nimble/host/store/ram/src/ble_store_ram.c \
EXTMOD_SRC_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \ EXTMOD_SRC_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \
nimble/nimble_npl_os.c \ nimble/nimble_npl_os.c \