From 002cfb39c2e1a029f7fccd349abdb8a37c23dfb6 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 11 Dec 2025 16:40:59 +0100 Subject: [PATCH 1/2] example: ble_gatt: add passkey confirmation handling Add BT auth callbacks, which are required to display passkey to the user (over serial console). Confirmation is handled by pressing button (/aliases/sw0 in devicetree). Add also EXAMPLE_BT_AUTO_CONFIRM option for handling auto-confirmation for nrf52_bsim board. There is no easy to use "manual" confirmation method for this platform, so confirming automatically is the easiest way to go. This makes sense especially for automated tests with pouch-gateway, as that will result in working BT communication without any additional external Pytest code. Signed-off-by: Marcin Niestroj --- examples/ble_gatt/Kconfig | 5 ++ examples/ble_gatt/src/main.c | 95 ++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/examples/ble_gatt/Kconfig b/examples/ble_gatt/Kconfig index 2c5e5c6..fa553a0 100644 --- a/examples/ble_gatt/Kconfig +++ b/examples/ble_gatt/Kconfig @@ -20,3 +20,8 @@ config EXAMPLE_CREDENTIALS_DIR default "/lfs1/credentials" help Directory on mounted file system containing credentials. + +# This option is used only for automated tests +config EXAMPLE_BT_AUTO_CONFIRM + bool + default y if BOARD_NRF52_BSIM_NATIVE diff --git a/examples/ble_gatt/src/main.c b/examples/ble_gatt/src/main.c index 7798337..30eb98c 100644 --- a/examples/ble_gatt/src/main.c +++ b/examples/ble_gatt/src/main.c @@ -26,6 +26,22 @@ LOG_MODULE_REGISTER(main); #include static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {}); +static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw0), gpios, {}); +static struct gpio_callback button_cb_data; +static struct bt_conn *default_conn; + +static void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + if (default_conn) + { + LOG_INF("Confirming passkey"); + bt_conn_auth_passkey_confirm(default_conn); + } + else + { + LOG_WRN("No BT connection for passkey confirmation"); + } +} static struct { @@ -56,6 +72,7 @@ static void connected(struct bt_conn *conn, uint8_t err) else { LOG_DBG("Connected"); + default_conn = conn; } } @@ -74,6 +91,8 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) { LOG_DBG("Disconnected (reason 0x%02x)", reason); + default_conn = NULL; + k_work_schedule(&disconnect_work, K_SECONDS(1)); } @@ -82,6 +101,51 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .disconnected = disconnected, }; +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + char passkey_str[7]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + snprintf(passkey_str, 7, "%06u", passkey); + + LOG_INF("Passkey for %s: %s", addr, passkey_str); +} + +static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) +{ + char addr[BT_ADDR_LE_STR_LEN]; + char passkey_str[7]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + snprintf(passkey_str, 7, "%06u", passkey); + + LOG_INF("Confirm passkey for %s: %s", addr, passkey_str); + + if (IS_ENABLED(CONFIG_EXAMPLE_BT_AUTO_CONFIRM)) + { + LOG_INF("Confirming passkey"); + bt_conn_auth_passkey_confirm(conn); + } +} + +static void auth_cancel(struct bt_conn *conn) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_INF("Pairing cancelled: %s", addr); +} + +static struct bt_conn_auth_cb auth_cb_display = { + .passkey_display = auth_passkey_display, + .passkey_confirm = auth_passkey_confirm, + .cancel = auth_cancel, +}; + void sync_request_work_handler(struct k_work *work) { service_data.data.flags |= POUCH_GATT_ADV_FLAG_SYNC_REQUEST; @@ -147,6 +211,13 @@ int main(void) return 0; } + err = bt_conn_auth_cb_register(&auth_cb_display); + if (err) + { + LOG_ERR("Bluetooth auth cb register failed (err %d)", err); + return err; + } + LOG_INF("Bluetooth initialized"); struct pouch_config config = {0}; @@ -194,6 +265,30 @@ int main(void) } } + if (DT_HAS_ALIAS(sw0)) + { + LOG_INF("Set up button at %s pin %d", button.port->name, button.pin); + + err = gpio_pin_configure_dt(&button, GPIO_INPUT); + if (err < 0) + { + LOG_ERR("Could not initialize Button"); + } + + err = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE); + if (err) + { + LOG_ERR("Error %d: failed to configure interrupt on %s pin %d", + err, + button.port->name, + button.pin); + return 0; + } + + gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); + gpio_add_callback(button.port, &button_cb_data); + } + k_work_schedule(&sync_request_work, K_SECONDS(CONFIG_EXAMPLE_SYNC_PERIOD_S)); while (1) From 47314fc0cb790219fa4786ff69643afc84480f4d Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Tue, 16 Dec 2025 14:51:53 +0100 Subject: [PATCH 2/2] transport: ble_gatt: add Kconfig selection for LESC / AUTHEN Introduce Kconfig option for required GATT permissions. Provide 2 options: * LE Secure Connection * Authentication (with encryption) This makes sure that proper BT Security Level is reached before trying being able to access pouch characteristics. Signed-off-by: Marcin Niestroj --- src/transport/gatt/Kconfig | 11 +++++++++++ src/transport/gatt/device_cert_characteristic.c | 2 +- src/transport/gatt/downlink_characteristic.c | 2 +- src/transport/gatt/info_characteristic.c | 2 +- src/transport/gatt/pouch_gatt_declarations.h | 7 +++++++ src/transport/gatt/server_cert_characteristic.c | 2 +- src/transport/gatt/uplink_characteristic.c | 2 +- 7 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/transport/gatt/Kconfig b/src/transport/gatt/Kconfig index b18a540..b504d9f 100644 --- a/src/transport/gatt/Kconfig +++ b/src/transport/gatt/Kconfig @@ -10,6 +10,17 @@ config POUCH_TRANSPORT_GATT_CUD_ATTRIBUTES can be useful during debugging and development to identify the characteristics without consulting their UUIDs. +choice POUCH_TRANSPORT_GATT_PERM + bool "GATT permissions" + +config POUCH_TRANSPORT_GATT_PERM_LESC + bool "Require LE Secure Connection for access" + +config POUCH_TRANSPORT_GATT_PERM_AUTHEN + bool "Require authentication for access" + +endchoice # POUCH_TRANSPORT_GATT_PERM + module = POUCH_GATT module-str = Pouch GATT source "subsys/logging/Kconfig.template.log_config" diff --git a/src/transport/gatt/device_cert_characteristic.c b/src/transport/gatt/device_cert_characteristic.c index 74ef6ab..27f4a3b 100644 --- a/src/transport/gatt/device_cert_characteristic.c +++ b/src/transport/gatt/device_cert_characteristic.c @@ -97,7 +97,7 @@ static ssize_t device_cert_read(struct bt_conn *conn, POUCH_GATT_CHARACTERISTIC(device_cert, (const struct bt_uuid *) &pouch_gatt_device_cert_chrc_uuid, BT_GATT_CHRC_READ, - BT_GATT_PERM_READ_LESC, + POUCH_GATT_PERM_READ, device_cert_read, NULL, &device_cert_chrc_ctx); diff --git a/src/transport/gatt/downlink_characteristic.c b/src/transport/gatt/downlink_characteristic.c index c3896bf..8649452 100644 --- a/src/transport/gatt/downlink_characteristic.c +++ b/src/transport/gatt/downlink_characteristic.c @@ -52,7 +52,7 @@ ssize_t downlink_write(struct bt_conn *conn, POUCH_GATT_CHARACTERISTIC(downlink, (const struct bt_uuid *) &pouch_gatt_downlink_chrc_uuid, BT_GATT_CHRC_WRITE, - BT_GATT_PERM_WRITE_LESC, + POUCH_GATT_PERM_WRITE, NULL, downlink_write, NULL); diff --git a/src/transport/gatt/info_characteristic.c b/src/transport/gatt/info_characteristic.c index 8478b3e..096f04f 100644 --- a/src/transport/gatt/info_characteristic.c +++ b/src/transport/gatt/info_characteristic.c @@ -124,7 +124,7 @@ static ssize_t info_read(struct bt_conn *conn, POUCH_GATT_CHARACTERISTIC(info, (const struct bt_uuid *) &pouch_gatt_info_chrc_uuid, BT_GATT_CHRC_READ, - BT_GATT_PERM_READ_LESC, + POUCH_GATT_PERM_READ, info_read, NULL, &info_chrc_ctx); diff --git a/src/transport/gatt/pouch_gatt_declarations.h b/src/transport/gatt/pouch_gatt_declarations.h index 3481c12..c774721 100644 --- a/src/transport/gatt/pouch_gatt_declarations.h +++ b/src/transport/gatt/pouch_gatt_declarations.h @@ -38,3 +38,10 @@ STRUCT_SECTION_START_EXTERN(bt_gatt_attr); #define POUCH_GATT_ATTR_ARRAY_PTR STRUCT_SECTION_START(bt_gatt_attr) #define POUCH_GATT_ATTR_ARRAY_LEN(dst) STRUCT_SECTION_COUNT(bt_gatt_attr, dst) + +#define POUCH_GATT_PERM_READ \ + (IS_ENABLED(CONFIG_POUCH_TRANSPORT_GATT_PERM_AUTHEN) ? BT_GATT_PERM_READ_AUTHEN \ + : BT_GATT_PERM_READ_LESC) +#define POUCH_GATT_PERM_WRITE \ + (IS_ENABLED(CONFIG_POUCH_TRANSPORT_GATT_PERM_AUTHEN) ? BT_GATT_PERM_WRITE_AUTHEN \ + : BT_GATT_PERM_WRITE_LESC) diff --git a/src/transport/gatt/server_cert_characteristic.c b/src/transport/gatt/server_cert_characteristic.c index 4670306..ba05fbf 100644 --- a/src/transport/gatt/server_cert_characteristic.c +++ b/src/transport/gatt/server_cert_characteristic.c @@ -153,7 +153,7 @@ static ssize_t server_cert_write(struct bt_conn *conn, POUCH_GATT_CHARACTERISTIC(server_cert, (const struct bt_uuid *) &pouch_gatt_server_cert_chrc_uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE, - BT_GATT_PERM_READ_LESC | BT_GATT_PERM_WRITE_LESC, + POUCH_GATT_PERM_READ | POUCH_GATT_PERM_WRITE, server_cert_serial_read, server_cert_write, &server_cert_chrc_ctx); diff --git a/src/transport/gatt/uplink_characteristic.c b/src/transport/gatt/uplink_characteristic.c index 16719a5..cc57400 100644 --- a/src/transport/gatt/uplink_characteristic.c +++ b/src/transport/gatt/uplink_characteristic.c @@ -198,7 +198,7 @@ static void uplink_indicate_destroy(struct bt_gatt_indicate_params *params) POUCH_GATT_CHARACTERISTIC(uplink, (const struct bt_uuid *) &pouch_gatt_uplink_chrc_uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_INDICATE, - BT_GATT_PERM_READ_LESC, + POUCH_GATT_PERM_READ, uplink_read, NULL, &uplink_chrc_ctx);