From 1697ff335db523ff0809051d42871beb9c86012d Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 27 Aug 2020 09:13:25 +1000 Subject: [PATCH] extmod/modbluetooth: Allow setting char/desc enc/auth options. This widens the characteristic/descriptor flags to 16-bit, to allow setting encryption/authentication requirements. Sets the required flags for NimBLE and btstack implementations. The BLE.FLAG_* constants will eventually be deprecated in favour of copy and paste Python constants (like the IRQs). Signed-off-by: Jim Mussared --- examples/bluetooth/ble_simple_peripheral.py | 9 ++++- examples/bluetooth/ble_temperature.py | 6 ++- examples/bluetooth/ble_uart_peripheral.py | 7 +++- extmod/btstack/modbluetooth_btstack.c | 36 +++++++++++++---- extmod/modbluetooth.c | 8 ++-- extmod/modbluetooth.h | 44 ++++++++++++++++++--- extmod/nimble/modbluetooth_nimble.c | 6 ++- 7 files changed, 93 insertions(+), 23 deletions(-) diff --git a/examples/bluetooth/ble_simple_peripheral.py b/examples/bluetooth/ble_simple_peripheral.py index d2b134e714..0ebe431764 100644 --- a/examples/bluetooth/ble_simple_peripheral.py +++ b/examples/bluetooth/ble_simple_peripheral.py @@ -12,14 +12,19 @@ _IRQ_CENTRAL_CONNECT = const(1) _IRQ_CENTRAL_DISCONNECT = const(2) _IRQ_GATTS_WRITE = const(3) +_FLAG_READ = const(0x0002) +_FLAG_WRITE_NO_RESPONSE = const(0x0004) +_FLAG_WRITE = const(0x0008) +_FLAG_NOTIFY = const(0x0010) + _UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") _UART_TX = ( bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"), - bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY, + _FLAG_READ | _FLAG_NOTIFY, ) _UART_RX = ( bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"), - bluetooth.FLAG_WRITE | bluetooth.FLAG_WRITE_NO_RESPONSE, + _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE, ) _UART_SERVICE = ( _UART_UUID, diff --git a/examples/bluetooth/ble_temperature.py b/examples/bluetooth/ble_temperature.py index d375a62ffb..e6378ebee7 100644 --- a/examples/bluetooth/ble_temperature.py +++ b/examples/bluetooth/ble_temperature.py @@ -15,12 +15,16 @@ _IRQ_CENTRAL_CONNECT = const(1) _IRQ_CENTRAL_DISCONNECT = const(2) _IRQ_GATTS_INDICATE_DONE = const(20) +_FLAG_READ = const(0x0002) +_FLAG_NOTIFY = const(0x0010) +_FLAG_INDICATE = const(0x0020) + # org.bluetooth.service.environmental_sensing _ENV_SENSE_UUID = bluetooth.UUID(0x181A) # org.bluetooth.characteristic.temperature _TEMP_CHAR = ( bluetooth.UUID(0x2A6E), - bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY | bluetooth.FLAG_INDICATE, + _FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE, ) _ENV_SENSE_SERVICE = ( _ENV_SENSE_UUID, diff --git a/examples/bluetooth/ble_uart_peripheral.py b/examples/bluetooth/ble_uart_peripheral.py index 6d167a871a..b4e352be9f 100644 --- a/examples/bluetooth/ble_uart_peripheral.py +++ b/examples/bluetooth/ble_uart_peripheral.py @@ -9,14 +9,17 @@ _IRQ_CENTRAL_CONNECT = const(1) _IRQ_CENTRAL_DISCONNECT = const(2) _IRQ_GATTS_WRITE = const(3) +_FLAG_WRITE = const(0x0008) +_FLAG_NOTIFY = const(0x0010) + _UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") _UART_TX = ( bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"), - bluetooth.FLAG_NOTIFY, + _FLAG_NOTIFY, ) _UART_RX = ( bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"), - bluetooth.FLAG_WRITE, + _FLAG_WRITE, ) _UART_SERVICE = ( _UART_UUID, diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index 9faae26e46..da9a6f732b 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -893,7 +893,30 @@ STATIC inline uint16_t get_uuid16(const mp_obj_bluetooth_uuid_t *uuid) { return (uuid->data[1] << 8) | uuid->data[0]; } -int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { +// Map MP_BLUETOOTH_CHARACTERISTIC_FLAG_ values to btstack read/write permission values. +STATIC void get_characteristic_permissions(uint16_t flags, uint16_t *read_permission, uint16_t *write_permission) { + if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_ENCRYPTED) { + *read_permission = ATT_SECURITY_ENCRYPTED; + } else if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHENTICATED) { + *read_permission = ATT_SECURITY_AUTHENTICATED; + } else if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHORIZED) { + *read_permission = ATT_SECURITY_AUTHORIZED; + } else { + *read_permission = ATT_SECURITY_NONE; + } + + if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_ENCRYPTED) { + *write_permission = ATT_SECURITY_ENCRYPTED; + } else if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHENTICATED) { + *write_permission = ATT_SECURITY_AUTHENTICATED; + } else if (flags & MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHORIZED) { + *write_permission = ATT_SECURITY_AUTHORIZED; + } else { + *write_permission = ATT_SECURITY_NONE; + } +} + +int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint16_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint16_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { DEBUG_printf("mp_bluetooth_gatts_register_service\n"); // Note: btstack expects BE UUIDs (which it immediately convertes to LE). // So we have to convert all our modbluetooth LE UUIDs to BE just for the att_db_util_add_* methods (using get_uuid16 above, and reverse_128 from btstackutil.h). @@ -916,9 +939,9 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m static uint8_t cccb_buf[2] = {0}; for (size_t i = 0; i < num_characteristics; ++i) { - uint16_t props = characteristic_flags[i] | ATT_PROPERTY_DYNAMIC; - uint16_t read_permission = ATT_SECURITY_NONE; - uint16_t write_permission = ATT_SECURITY_NONE; + uint16_t props = (characteristic_flags[i] & 0x7f) | ATT_PROPERTY_DYNAMIC; + uint16_t read_permission, write_permission; + get_characteristic_permissions(characteristic_flags[i], &read_permission, &write_permission); if (characteristic_uuids[i]->type == MP_BLUETOOTH_UUID_TYPE_16) { handles[handle_index] = att_db_util_add_characteristic_uuid16(get_uuid16(characteristic_uuids[i]), props, read_permission, write_permission, NULL, 0); } else if (characteristic_uuids[i]->type == MP_BLUETOOTH_UUID_TYPE_128) { @@ -942,9 +965,8 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m ++handle_index; for (size_t j = 0; j < num_descriptors[i]; ++j) { - props = descriptor_flags[descriptor_index] | ATT_PROPERTY_DYNAMIC; - read_permission = ATT_SECURITY_NONE; - write_permission = ATT_SECURITY_NONE; + props = (descriptor_flags[descriptor_index] & 0x7f) | ATT_PROPERTY_DYNAMIC; + get_characteristic_permissions(descriptor_flags[descriptor_index], &read_permission, &write_permission); if (descriptor_uuids[descriptor_index]->type == MP_BLUETOOTH_UUID_TYPE_16) { handles[handle_index] = att_db_util_add_descriptor_uuid16(get_uuid16(descriptor_uuids[descriptor_index]), props, read_permission, write_permission, NULL, 0); diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index dc1084acc1..1e67c8ce32 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -461,11 +461,11 @@ STATIC int bluetooth_gatts_register_service(mp_obj_t uuid_in, mp_obj_t character // Lists of characteristic uuids and flags. mp_obj_bluetooth_uuid_t **characteristic_uuids = m_new(mp_obj_bluetooth_uuid_t *, len); - uint8_t *characteristic_flags = m_new(uint8_t, len); + uint16_t *characteristic_flags = m_new(uint16_t, len); // Flattened list of descriptor uuids and flags. Grows (realloc) as more descriptors are encountered. mp_obj_bluetooth_uuid_t **descriptor_uuids = NULL; - uint8_t *descriptor_flags = NULL; + uint16_t *descriptor_flags = NULL; // How many descriptors in the flattened list per characteristic. uint8_t *num_descriptors = m_new(uint8_t, len); @@ -506,7 +506,7 @@ STATIC int bluetooth_gatts_register_service(mp_obj_t uuid_in, mp_obj_t character // Grow the flattened uuids and flags arrays with this many more descriptors. descriptor_uuids = m_renew(mp_obj_bluetooth_uuid_t *, descriptor_uuids, descriptor_index, descriptor_index + num_descriptors[characteristic_index]); - descriptor_flags = m_renew(uint8_t, descriptor_flags, descriptor_index, descriptor_index + num_descriptors[characteristic_index]); + descriptor_flags = m_renew(uint16_t, descriptor_flags, descriptor_index, descriptor_index + num_descriptors[characteristic_index]); // Also grow the handles array. *handles = m_renew(uint16_t, *handles, *num_handles, *num_handles + num_descriptors[characteristic_index]); @@ -894,6 +894,8 @@ STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluetooth) }, { MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&mp_type_bluetooth_ble) }, { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&mp_type_bluetooth_uuid) }, + + // TODO: Deprecate these flags (recommend copying the constants from modbluetooth.h instead). { MP_ROM_QSTR(MP_QSTR_FLAG_READ), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) }, { MP_ROM_QSTR(MP_QSTR_FLAG_WRITE), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE) }, { MP_ROM_QSTR(MP_QSTR_FLAG_NOTIFY), MP_ROM_INT(MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY) }, diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 2619e71894..0d4296626b 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -71,12 +71,28 @@ // Advertisement packet lengths #define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32) +// Basic characteristic/descriptor flags. // These match the spec values for these flags so can be passed directly to the stack. -#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ (1 << 1) -#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE (1 << 2) -#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE (1 << 3) -#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY (1 << 4) -#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE (1 << 5) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_BROADCAST (0x0001) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ (0x0002) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE (0x0004) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE (0x0008) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_NOTIFY (0x0010) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_INDICATE (0x0020) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_AUTHENTICATED_SIGNED_WRITE (0x0040) + +// TODO: NimBLE and BlueKitchen disagree on this one. +// #define MP_BLUETOOTH_CHARACTERISTIC_FLAG_RELIABLE_WRITE (0x0080) + +// Extended flags for security and privacy. +// These match NimBLE but might require mapping in the bindings for other stacks. +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_AUX_WRITE (0x0100) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_ENCRYPTED (0x0200) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHENTICATED (0x0400) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ_AUTHORIZED (0x0800) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_ENCRYPTED (0x1000) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHENTICATED (0x2000) +#define MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_AUTHORIZED (0x4000) // For mp_bluetooth_gattc_write, the mode parameter #define MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE (0) @@ -153,6 +169,22 @@ _IRQ_L2CAP_DISCONNECT = const(24) _IRQ_L2CAP_RECV = const(25) _IRQ_L2CAP_SEND_READY = const(26) _IRQ_GATTS_CONN_UPDATE = const(27) + +_FLAG_BROADCAST = const(0x0001) +_FLAG_READ = const(0x0002) +_FLAG_WRITE_NO_RESPONSE = const(0x0004) +_FLAG_WRITE = const(0x0008) +_FLAG_NOTIFY = const(0x0010) +_FLAG_INDICATE = const(0x0020) +_FLAG_AUTHENTICATED_SIGNED_WRITE = const(0x0040) + +_FLAG_AUX_WRITE = const(0x0100) +_FLAG_READ_ENCRYPTED = const(0x0200) +_FLAG_READ_AUTHENTICATED = const(0x0400) +_FLAG_READ_AUTHORIZED = const(0x0800) +_FLAG_WRITE_ENCRYPTED = const(0x1000) +_FLAG_WRITE_AUTHENTICATED = const(0x2000) +_FLAG_WRITE_AUTHORIZED = const(0x4000) */ // bluetooth.UUID type. @@ -214,7 +246,7 @@ void mp_bluetooth_gap_advertise_stop(void); int mp_bluetooth_gatts_register_service_begin(bool append); // Add a service with the given list of characteristics to the queue to be registered. // The value_handles won't be valid until after mp_bluetooth_register_service_end is called. -int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); +int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint16_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint16_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics); // Register any queued services. int mp_bluetooth_gatts_register_service_end(void); diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 3983d18690..4484df937f 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -685,7 +685,7 @@ int mp_bluetooth_gatts_register_service_end(void) { return 0; } -int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint8_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint8_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { +int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint16_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint16_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) { if (MP_STATE_PORT(bluetooth_nimble_root_pointers)->n_services == MP_BLUETOOTH_NIMBLE_MAX_SERVICES) { return MP_E2BIG; } @@ -697,6 +697,7 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m characteristics[i].uuid = create_nimble_uuid(characteristic_uuids[i], NULL); characteristics[i].access_cb = characteristic_access_cb; characteristics[i].arg = NULL; + // NimBLE flags match the MP_BLUETOOTH_CHARACTERISTIC_FLAG_ ones exactly (including the security/privacy options). characteristics[i].flags = characteristic_flags[i]; characteristics[i].min_key_size = 0; characteristics[i].val_handle = &handles[handle_index]; @@ -710,7 +711,8 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m for (size_t j = 0; j < num_descriptors[i]; ++j) { descriptors[j].uuid = create_nimble_uuid(descriptor_uuids[descriptor_index], NULL); descriptors[j].access_cb = characteristic_access_cb; - descriptors[j].att_flags = descriptor_flags[descriptor_index]; + // NimBLE doesn't support security/privacy options on descriptors. + descriptors[j].att_flags = (uint8_t)descriptor_flags[descriptor_index]; descriptors[j].min_key_size = 0; // Unlike characteristic, Nimble doesn't provide an automatic way to remember the handle, so use the arg. descriptors[j].arg = &handles[handle_index];