From f13d8062c0a557d6958ad223d2f7283bf4104f90 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:49:49 +0100 Subject: [PATCH] fix "no android pairing request" --- zephcore/ARCHITECTURE.md | 9 ++++-- zephcore/adapters/ble/ZephyrBLE.cpp | 34 +++++++++------------ zephcore/boards/common/zephcore_common.conf | 8 +++-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/zephcore/ARCHITECTURE.md b/zephcore/ARCHITECTURE.md index 6844104..8e0bad4 100644 --- a/zephcore/ARCHITECTURE.md +++ b/zephcore/ARCHITECTURE.md @@ -348,12 +348,17 @@ Power: `powersaving on/off` ### 7.1 BLE (`adapters/ble/`) -- Nordic UART Service (NUS) with AUTHEN permissions (forces pairing) -- Passkey-based MITM pairing, runtime configurable PIN +- Nordic UART Service (NUS) with AUTHEN permissions on CCC + RX (forces pairing) +- Passkey-based MITM pairing (SC + MITM + Bonding), runtime configurable PIN via `app_passkey` callback +- DisplayOnly IO capability — phone enters passkey displayed on device / known to user +- Advertising with public identity address (no RPA) — required for Android Flutter BLE app compatibility +- `CONFIG_BT_PRIVACY` disabled: Android's Flutter BLE plugin fails to `connectGatt()` to RPA-advertised devices from app context; iOS and Android system BT settings handle RPA fine but the MeshCore app doesn't. Arduino MeshCore also uses public addresses. +- Pairing triggered reactively: phone hits ATT error 0x05 on secured attribute → initiates SMP pairing (Apple Accessory Design Guidelines §55 compliant — no proactive Security Request) - TX congestion control: queue (12 frames) + overflow buffer + retry + timeout watchdog - Fast/slow advertising switching with post-disconnect flap prevention - DLE (Data Length Extension) to 251 bytes - Interface coexistence: BLE vs USB, one active at a time +- Debug: `boards/common/ble_debug.conf` overlay enables DBG on bt_smp/att/gatt/conn ### 7.2 DataStore (`adapters/datastore/`) diff --git a/zephcore/adapters/ble/ZephyrBLE.cpp b/zephcore/adapters/ble/ZephyrBLE.cpp index 15b9751..4e54654 100644 --- a/zephcore/adapters/ble/ZephyrBLE.cpp +++ b/zephcore/adapters/ble/ZephyrBLE.cpp @@ -2,7 +2,13 @@ * SPDX-License-Identifier: Apache-2.0 * ZephCore BLE Adapter — NUS service, advertising, security, TX/RX * - * Extracted from main_companion.cpp for independent BLE debug logging. + * Security: SMP pairing with SC + MITM + Bonding, DisplayOnly IO (app_passkey). + * Pairing is triggered reactively by ATT_ERR_AUTHENTICATION on secured GATT + * attributes (Apple §55 compliant — no proactive Security Request on connect). + * + * Advertising: Public identity address (CONFIG_BT_PRIVACY disabled). + * Android's Flutter BLE plugin fails to connectGatt() to RPA-advertised devices + * from app context. Arduino MeshCore also uses public addresses. */ #include @@ -154,8 +160,8 @@ static void kick_tx_drain(void); * Matches Arduino's SECMODE_ENC_WITH_MITM on bleuart. * * When the phone tries to subscribe (CCC write) or send data (RX write), - * Zephyr returns ATT_ERR_AUTHENTICATION. The phone's BLE stack should - * then initiate pairing (PIN dialog). After pairing succeeds, + * Zephyr returns ATT_ERR_AUTHENTICATION. The phone's BLE stack then + * initiates pairing (PIN dialog). After pairing succeeds, * security_changed() fires at L3+ and the phone retries the operation. */ BT_GATT_SERVICE_DEFINE(secure_nus_svc, @@ -286,25 +292,13 @@ static void connected(struct bt_conn *conn, uint8_t err) /* Do NOT proactively request security here. * - * Arduino reference: the SoftDevice never sends SMP Security Request - * on connection. Pairing is triggered naturally when the phone tries - * to access a GATT characteristic with AUTHEN permissions — the stack - * returns "Insufficient Authentication" and the phone's BLE stack - * initiates pairing (PIN dialog). - * - * Our NUS service has BT_GATT_PERM_*_AUTHEN on CCC and RX, so - * pairing triggers automatically when the MeshCore app accesses them. - * - * The old bt_conn_set_security(L3) call sent a proactive SMP Security - * Request that the MeshCore app doesn't handle — phone would connect - * but never show a PIN dialog, causing a "freeze." + * Apple Accessory Design Guidelines §55 (Pairing): the accessory should + * not request pairing until an ATT request is rejected with "Insufficient + * Authentication." Pairing is triggered reactively when the phone tries + * to access our AUTHEN-secured GATT attributes (CCC write / RX write). * * For bonded reconnects, Zephyr auto-encrypts with stored keys when - * CONFIG_BT_SMP and CONFIG_BT_BONDABLE are enabled. - * - * NOTE: If Windows support is needed later, Windows may not initiate - * pairing from "Insufficient Authentication" — add a platform-specific - * Security Request path for Windows clients only. */ + * CONFIG_BT_SMP and CONFIG_BT_BONDABLE are enabled. */ /* Notify main of BLE connection */ if (ble_cbs && ble_cbs->on_connected) { diff --git a/zephcore/boards/common/zephcore_common.conf b/zephcore/boards/common/zephcore_common.conf index f4654a5..e3e0b85 100644 --- a/zephcore/boards/common/zephcore_common.conf +++ b/zephcore/boards/common/zephcore_common.conf @@ -113,9 +113,11 @@ CONFIG_BT_USER_DATA_LEN_UPDATE=y # manually after security is established (future enhancement). CONFIG_BT_USER_PHY_UPDATE=y -# Privacy - use Resolvable Private Addresses (Apple requirement) -CONFIG_BT_PRIVACY=y -CONFIG_BT_RPA_TIMEOUT=900 +# Privacy disabled — Android's Flutter BLE plugin fails to connect to +# RPA-advertised devices from app context (system BT settings works fine). +# Arduino MeshCore doesn't use RPA either. Actual link security comes from +# SMP pairing (passkey + SC + MITM + bonding), not address privacy. +# CONFIG_BT_PRIVACY=y # NOTE: SC_PAIR_ONLY intentionally NOT set — Windows can't handle SC passkey # pairing (never prompts for PIN). Allowing both Legacy and SC lets Windows # pair with Legacy while iOS/Android use SC.