From 748fad2dfb0f810287b1a7fd2cbc51d330506be7 Mon Sep 17 00:00:00 2001 From: Pieter Pas Date: Sun, 9 Jun 2024 20:55:50 +0200 Subject: [PATCH] Add BLESettings::initiate_security to always request pairing Update parameters in BTstack BLE backend --- src/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp | 5 +++ .../BLEMIDI/BTstack/gatt_midi.cpp | 12 +++++++ .../BLEMIDI/ESP32-NimBLE/app.ipp | 1 + .../BLEMIDI/ESP32-NimBLE/events.hpp | 1 + .../BLEMIDI/ESP32-NimBLE/events.ipp | 36 +++++++++++++++---- src/MIDI_Interfaces/BLEMIDI/ESP32/app.cpp | 1 + .../BLEMIDI/ESP32/midi-events.c | 12 +++++-- src/MIDI_Interfaces/BLEMIDI/ESP32/midi.h | 2 ++ 8 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp b/src/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp index 501f1fcdfc..2130212d75 100644 --- a/src/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp +++ b/src/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp @@ -156,6 +156,11 @@ struct BLESettings { uint16_t minimum = 0x000C; uint16_t maximum = 0x000C; } connection_interval {}; + /// Set to true if you want the Arduino to always initiate the Bluetooth + /// bonding or secure connection. As a result, it will show up as a "paired" + /// device on your computer/phone/tablet. If set to false, security is still + /// supported, but the central device should take the initiative. + bool initiate_security = false; }; END_CS_NAMESPACE diff --git a/src/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp b/src/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp index b94d0357f2..eb1fbaa7b1 100644 --- a/src/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp +++ b/src/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp @@ -29,6 +29,7 @@ constexpr uint16_t midi_cccd_handle = ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_CLIENT_CONFIGURATION_HANDLE; MIDIBLEInstance *instance = nullptr; +BLESettings settings; btstack_packet_callback_registration_t hci_event_callback_registration; btstack_packet_callback_registration_t sm_event_callback_registration; @@ -42,6 +43,16 @@ void connection_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) { return; uint16_t conn_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); + // Request bonding + if (settings.initiate_security) + sm_request_pairing(conn_handle); + // Update the connection parameters + uint16_t conn_latency = 0; + uint16_t supervision_timeout = 400; + gap_request_connection_parameter_update( + conn_handle, settings.connection_interval.minimum, + settings.connection_interval.maximum, conn_latency, + supervision_timeout); instance->handleConnect(BLEConnectionHandle {conn_handle}); } // HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE @@ -251,6 +262,7 @@ btstack_context_callback_registration_t create_context_callback(F &f) { bool init(MIDIBLEInstance &instance, BLESettings settings) { cs::midi_ble_btstack::instance = &instance; + cs::midi_ble_btstack::settings = settings; le_midi_setup(settings); hci_power_control(HCI_POWER_ON); // btstack_run_loop_execute(); // not necessary in background mode diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/app.ipp b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/app.ipp index d7eebc514a..ebba9a2bc3 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/app.ipp +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/app.ipp @@ -70,6 +70,7 @@ inline bool init(MIDIBLEInstance &instance, BLESettings ble_settings) { // Initialize the MIDI service and characteristic cs_midi_ble_state.instance = &instance; + cs_midi_ble_state.settings = ble_settings; cs::midi_ble_nimble::state = &cs_midi_ble_state; const auto *gatt_server_services = midi_ble_get_service(); CS_CHECK_ZERO(ble_gatts_count_cfg(gatt_server_services)); diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.hpp b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.hpp index f7c3cfea29..2ab2a7e90b 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.hpp +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.hpp @@ -21,6 +21,7 @@ struct MIDIBLEState { MIDIBLEInstance *instance = nullptr; uint16_t midi_characteristic_handle = invalid_handle; uint8_t address_type = 0; + BLESettings settings; }; extern MIDIBLEState *state; diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.ipp b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.ipp index d1048907c5..17cffcdc9e 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.ipp +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32-NimBLE/events.ipp @@ -178,6 +178,23 @@ cs_midi_ble_service_register_callback(struct ble_gatt_register_ctxt *ctxt, } } +namespace { +inline void update_connection_params(uint16_t conn_handle, + const cs::BLESettings &settings) { + ble_gap_upd_params params {}; + params.latency = 0; + params.itvl_max = settings.connection_interval.maximum; + params.itvl_min = settings.connection_interval.minimum; + params.supervision_timeout = 400; + // Connection event length + params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; + params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; + if (auto rc = ble_gap_update_params(conn_handle, ¶ms); rc != 0) { + ESP_LOGE("CS-BLEMIDI", "failed to update params; rc=%d", rc); + } +} +} // namespace + /// Called for GAP events like (dis)connection, MTU updates, etc. inline int cs_midi_ble_gap_callback(struct ble_gap_event *event, void *) { ESP_LOGI("CS-BLEMIDI", "gap event %d", +event->type); @@ -189,22 +206,27 @@ inline int cs_midi_ble_gap_callback(struct ble_gap_event *event, void *) { event->connect.status); if (event->connect.status == 0) { auto conn_handle = event->connect.conn_handle; + const auto &settings = cs::midi_ble_nimble::state->settings; struct ble_gap_conn_desc desc; auto rc = ble_gap_conn_find(conn_handle, &desc); assert(rc == 0); cs::midi_ble_nimble::print_conn_desc(&desc); -#if 0 // TODO: is this the correct place? // Without this, Android does not initiate bonding or SC, but // with it, Windows starts a connect/disconnect loop on the // second connection ... - if (auto rc = ble_gap_security_initiate(conn_handle); rc != 0) { - ESP_LOGE("CS-BLEMIDI", - "failed to initiate secure connection; rc=%d", rc); - return ble_gap_terminate(conn_handle, - BLE_ERR_REM_USER_CONN_TERM); + if (settings.initiate_security) { + if (auto rc = ble_gap_security_initiate(conn_handle); + rc != 0) { + ESP_LOGE("CS-BLEMIDI", + "failed to initiate secure connection; rc=%d", + rc); + return ble_gap_terminate(conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } } -#endif + // Update the connection parameters + update_connection_params(conn_handle, settings); if (auto *inst = cs::midi_ble_nimble::state->instance) inst->handleConnect(cs::BLEConnectionHandle {conn_handle}); } else { diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32/app.cpp b/src/MIDI_Interfaces/BLEMIDI/ESP32/app.cpp index c01f1e027b..e60dddf51d 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32/app.cpp +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32/app.cpp @@ -64,6 +64,7 @@ bool init(MIDIBLEInstance &instance, BLESettings settings) { set_midi_ble_name(settings.device_name); advertising_set_connection_interval(settings.connection_interval.minimum, settings.connection_interval.maximum); + set_security_initiate_encryption(settings.initiate_security); return midi_init(); } diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32/midi-events.c b/src/MIDI_Interfaces/BLEMIDI/ESP32/midi-events.c index 7552ee4276..56639c9943 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32/midi-events.c +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32/midi-events.c @@ -14,6 +14,13 @@ #include "logging.h" #include "midi-private.h" #include +#include + +static bool security_initiate_encryption = false; + +void set_security_initiate_encryption(bool security_initiate_encryption_) { + security_initiate_encryption = security_initiate_encryption_; +} void midi_handle_gatts_event(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { @@ -61,8 +68,9 @@ void midi_handle_gatts_event(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, case ESP_GATTS_START_EVT: break; case ESP_GATTS_STOP_EVT: break; case ESP_GATTS_CONNECT_EVT: - esp_ble_set_encryption(param->connect.remote_bda, - ESP_BLE_SEC_ENCRYPT_MITM); + if (security_initiate_encryption) + esp_ble_set_encryption(param->connect.remote_bda, + ESP_BLE_SEC_ENCRYPT_MITM); midi_handle_connect_event(gatts_if, param); break; case ESP_GATTS_DISCONNECT_EVT: diff --git a/src/MIDI_Interfaces/BLEMIDI/ESP32/midi.h b/src/MIDI_Interfaces/BLEMIDI/ESP32/midi.h index bd46a8a790..739be6869c 100644 --- a/src/MIDI_Interfaces/BLEMIDI/ESP32/midi.h +++ b/src/MIDI_Interfaces/BLEMIDI/ESP32/midi.h @@ -20,6 +20,8 @@ bool midi_notify(uint16_t conn_handle, uint16_t char_handle, /// Set the name of the BLE device. Must be set before calling @ref midi_init(). void set_midi_ble_name(const char *name); +/// Configure whether the Arduino should initiate the bonding/secure connection. +void set_security_initiate_encryption(bool security_initiate_encryption_); /// Initialize the Bluetooth stack and register the MIDI BLE application with /// the Bluedroid driver.