diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index b89b4b0163..61831113f0 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -571,6 +571,8 @@ if(CONFIG_BT_ENABLED) "host/nimble/nimble/nimble/host/src/ble_hs_mqueue.c" "host/nimble/nimble/nimble/host/src/ble_hs_periodic_sync.c" "host/nimble/nimble/nimble/host/src/ble_att.c" + "host/nimble/nimble/nimble/host/src/ble_ead.c" + "host/nimble/nimble/nimble/host/src/ble_aes_ccm.c" "host/nimble/nimble/nimble/host/src/ble_gattc.c" "host/nimble/nimble/nimble/host/src/ble_store.c" "host/nimble/nimble/nimble/host/src/ble_sm_lgcy.c" diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index d76edd00ee..c978d51f35 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -679,3 +679,17 @@ config BT_NIMBLE_OPTIMIZE_MULTI_CONN This option enables the use of vendor-specific APIs for multi-connections, which can greatly enhance the stability of coexistence between numerous central and peripheral devices. It will prohibit the usage of standard APIs. + +config BT_NIMBLE_ENC_ADV_DATA + bool "Encrypted Advertising Data" + depends on SOC_ESP_NIMBLE_CONTROLLER + select BT_NIMBLE_EXT_ADV + help + This option is used to enable encrypted advertising data. + +config BT_NIMBLE_MAX_EADS + int "Maximum number of EAD devices to save across reboots" + default 10 + depends on BT_NIMBLE_ENABLED && BT_NIMBLE_ENC_ADV_DATA + help + Defines maximum number of encrypted advertising data key material to save diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index e24f65acda..3172618555 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit e24f65acdafed8334c122acf06972545a184ba2f +Subproject commit 3172618555b02dad599e9a76f56f1d6a64557f78 diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index 9c60bc2412..b8e7fff03d 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -104,6 +104,12 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (CONFIG_BT_NIMBLE_EXT_ADV_MAX_SIZE) #endif +#ifndef CONFIG_BT_NIMBLE_ENC_ADV_DATA +#define MYNEWT_VAL_ENC_ADV_DATA (0) +#else +#define MYNEWT_VAL_ENC_ADV_DATA (CONFIG_BT_NIMBLE_ENC_ADV_DATA) +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) #define BLE_SCAN_RSP_DATA_MAX_LEN_N (1650) #else @@ -842,6 +848,10 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS CONFIG_BT_NIMBLE_MAX_CCCDS #endif +#ifdef CONFIG_BT_NIMBLE_MAX_EADS +#define MYNEWT_VAL_BLE_STORE_MAX_EADS CONFIG_BT_NIMBLE_MAX_EADS +#endif + #ifndef MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST #ifdef CONFIG_BT_NIMBLE_NVS_PERSIST #define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (1) diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index 41430b1950..702e6e85f8 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -142,6 +142,12 @@ examples/bluetooth/nimble: temporary: true reason: The runner doesn't support yet +examples/bluetooth/nimble/ble_enc_adv_data: + enable: + - if: IDF_TARGET in ["esp32c2", "esp32c6", "esp32h2"] + temporary: true + reason: the other targets are not tested yet + examples/bluetooth/nimble/ble_htp: enable: - if: IDF_TARGET in ["esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32h4", "esp32s3"] diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt new file mode 100644 index 0000000000..9fd41ea1d8 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(enc_adv_data_cent) diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md new file mode 100644 index 0000000000..294852040c --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md @@ -0,0 +1,171 @@ +| Supported Targets | ESP32-C2 | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | -------- | + +# BLE Encrypted Advertising Data Central Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example creates GATT client and performs passive scan, it then connects to peripheral device if the device advertises connectability and the device advertises support for the custom service (0x2C01) as primary service UUID which has key material characteristic (0x2B88). + +After connection it enables bonding and link encryprion if the `Enable Link Encryption` flag is set in the example config. + +It performs the following operations against the specified peer: + +* Scans the peripheral devices and saves the peer address if it supports gap service as a primary service. + +* Check if session key or IV exists for the connected peer. If it's not present, read the key material characteric. The value read will contain session key and IV for decrypting advertising data. + +* Disconnect from the peer once read is completed. + +* While scanning for the second time, if the peer's address is saved and respestive session key and IV are present, decrypt the advertising data. + +If the peer does not support a required service, characteristic, or descriptor, then the peer lied when it claimed support for the gap service! When this happens, or if a GATT procedure fails, this function immediately terminates the connection. + +It uses ESP32's Bluetooth controller and NimBLE stack based BLE host. + +This example aims at understanding BLE client scanning devices which advertise encrypted data. + +To test this demo, use any BLE GATT server app that advertises support for the gap service (0x1800), includes it in the GATT database and has key material characteristic support. + + +## How to Use Example + +Before project configuration and build, be sure to set the correct chip target using: + +```bash +idf.py set-target +``` + +### Hardware Required + +* A development board with ESP32/ESP32-C2/ESP32-C3/ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) +* A USB cable for Power supply and programming + +See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it. + +### Configure the Project + +Open the project configuration menu: + +```bash +idf.py menuconfig +``` +In the `Component config` menu: + +* Select encrypted adv data from `Component config -> Bluetooth -> NimBLE Options -> BT_NIMBLE_ENC_ADV_DATA` + +In the `Example Configuration` menu: + +* Change the `Peer Address` option if needed. + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +This is the console output on successful connection: + +``` +I (436) NimBLE: BLE Host Task Started +I (446) main_task: Returned from app_main() +I (506) NimBLE: Adding peer addr : 60:55:f9:f7:4f:42 +I (546) NimBLE: Connection established +I (546) NimBLE: +I (546) NimBLE: GATT procedure initiated: exchange mtu + +I (546) NimBLE: GATT procedure initiated: discover all services + +I (636) NimBLE: mtu update event; conn_handle=1 cid=4 mtu=256 + +I (696) NimBLE: GATT procedure initiated: discover all characteristics; +I (696) NimBLE: start_handle=1 end_handle=7 + +I (846) NimBLE: GATT procedure initiated: discover all characteristics; +I (846) NimBLE: start_handle=8 end_handle=11 + +I (966) NimBLE: GATT procedure initiated: discover all characteristics; +I (966) NimBLE: start_handle=12 end_handle=65535 + +I (1116) NimBLE: GATT procedure initiated: discover all descriptors; +I (1116) NimBLE: chr_val_handle=10 end_handle=11 + +I (1176) NimBLE: GATT procedure initiated: discover all descriptors; +I (1176) NimBLE: chr_val_handle=14 end_handle=65535 + +I (1386) NimBLE: Service discovery complete; status=0 conn_handle=1 + +I (1386) NimBLE: GATT procedure initiated: read; +I (1386) NimBLE: att_handle=7 + +I (1476) NimBLE: Read complete; status=0 conn_handle=1 +I (1476) NimBLE: attr_handle=7 value= +I (1476) NimBLE: 0xc0 +I (1486) NimBLE: :0xc1 +I (1486) NimBLE: :0xc2 +I (1486) NimBLE: :0xc3 +I (1486) NimBLE: :0xc4 +I (1496) NimBLE: :0xc5 +I (1496) NimBLE: :0xc6 +I (1496) NimBLE: :0xc7 +I (1506) NimBLE: :0xc8 +I (1506) NimBLE: :0xc9 +I (1506) NimBLE: :0xca +I (1516) NimBLE: :0xcb +I (1516) NimBLE: :0xcc +I (1516) NimBLE: :0xcd +I (1526) NimBLE: :0xce +I (1526) NimBLE: :0xcf +I (1526) NimBLE: :0xfb +I (1526) NimBLE: :0x56 +I (1536) NimBLE: :0xe1 +I (1536) NimBLE: :0xda +I (1536) NimBLE: :0xdc +I (1546) NimBLE: :0x7e +I (1546) NimBLE: :0xad +I (1546) NimBLE: :0xf5 +I (1556) NimBLE: Writing of session key, iv, and peer addr to NVS success +I (1556) NimBLE: GAP procedure initiated: terminate connection; conn_handle=1 hci_reason=19 + +I (1596) NimBLE: disconnect; reason=534 +I (1596) NimBLE: +I (1626) NimBLE: Peer was already added with addr : 60:55:f9:f7:4f:42 +I (1626) NimBLE: Read session key and iv from NVS successfully +I (1636) NimBLE: Decryption of adv data done successfully +I (1726) NimBLE: Connection established +I (1726) NimBLE: +I (1726) NimBLE: GATT procedure initiated: exchange mtu + +I (1736) NimBLE: GATT procedure initiated: discover all services + +I (1826) NimBLE: mtu update event; conn_handle=1 cid=4 mtu=256 + +I (1886) NimBLE: GATT procedure initiated: discover all characteristics; +I (1886) NimBLE: start_handle=1 end_handle=7 + +I (2006) NimBLE: GATT procedure initiated: discover all characteristics; +I (2006) NimBLE: start_handle=8 end_handle=11 + +I (2156) NimBLE: GATT procedure initiated: discover all characteristics; +I (2156) NimBLE: start_handle=12 end_handle=65535 + +I (2276) NimBLE: GATT procedure initiated: discover all descriptors; +I (2276) NimBLE: chr_val_handle=10 end_handle=11 + +I (2366) NimBLE: GATT procedure initiated: discover all descriptors; +I (2366) NimBLE: chr_val_handle=14 end_handle=65535 + +I (2546) NimBLE: Service discovery complete; status=0 conn_handle=1 + + +Done + +``` + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/CMakeLists.txt new file mode 100644 index 0000000000..18d510d988 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(srcs "main.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/Kconfig.projbuild new file mode 100644 index 0000000000..a2da412d5b --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/Kconfig.projbuild @@ -0,0 +1,16 @@ +menu "Example Configuration" + + config EXAMPLE_PEER_ADDR + string "Peer Address" + default "ADDR_ANY" + help + Enter the peer address in aa:bb:cc:dd:ee:ff form to connect to a specific peripheral + + config EXAMPLE_ENC_ADV_DATA + bool + prompt "Enable encrypted advertising data feature support" + default y + select BT_NIMBLE_ENC_ADV_DATA + help + This option enables support of encrypted advertising data. +endmenu diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/enc_adv_data_cent.h b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/enc_adv_data_cent.h new file mode 100644 index 0000000000..6aaf66e017 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/enc_adv_data_cent.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef H_ENC_ADV_DATA_CENT_ +#define H_ENC_ADV_DATA_CENT_ + +#if CONFIG_EXAMPLE_ENC_ADV_DATA +#include "modlog/modlog.h" +#include "esp_central.h" +#include "host/ble_ead.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_hs_adv_fields; +struct ble_gap_conn_desc; +struct ble_hs_cfg; +union ble_store_value; +union ble_store_key; + +#define BLE_SVC_GAP_UUID16 0x1800 +#define BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME 0x2a00 + +#define BLE_SVC_GAP_CHR_UUID16_KEY_MATERIAL 0x2B88 + +struct km_peer { + bool key_material_exist; + uint8_t peer_addr[PEER_ADDR_VAL_SIZE]; +}; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c new file mode 100644 index 0000000000..5388a4f496 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c @@ -0,0 +1,597 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "esp_log.h" +#include "nvs_flash.h" + +/* BLE */ +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "console/console.h" +#include "services/gap/ble_svc_gap.h" +#include "enc_adv_data_cent.h" + +#if CONFIG_EXAMPLE_ENC_ADV_DATA +static int counter = 0; +static struct km_peer kmp[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1] = {0}; + +static const char *tag = "ENC_ADV_DATA_CENT"; +static int enc_adv_data_cent_gap_event(struct ble_gap_event *event, void *arg); +static uint8_t peer_addr[6]; +static int mtu_def = 512; + +void ble_store_config_init(void); + +static int +enc_adv_data_find_peer(const uint8_t *peer_addr) +{ + for (int i = 0; i <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) { + if (memcmp(peer_addr, &kmp[i].peer_addr, PEER_ADDR_VAL_SIZE) == 0) { + return i; + } + } + return -1; +} + +static int +enc_adv_data_set_km_exist(const uint8_t *peer_addr) +{ + int ind = enc_adv_data_find_peer(peer_addr); + if (ind == -1) { + return -1; + } + kmp[ind].key_material_exist = true; + return 0; +} + +static bool +enc_adv_data_check_km_exist(const uint8_t *peer_addr) +{ + int ind; + ind = enc_adv_data_find_peer(peer_addr); + if (ind == -1) { + return false; + } + + return kmp[ind].key_material_exist; +} + +/** + * Application callback. Called when the read has completed. + */ +static int +enc_adv_data_cent_on_read(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + int rc; + struct ble_store_value_ead value_ead = {0}; + struct peer *p; + + MODLOG_DFLT(INFO, "Read complete; status=%d conn_handle=%d", error->status, + conn_handle); + if (error->status == 0) { + MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle); + print_mbuf(attr->om); + } else { + goto err; + } + + p = peer_find(conn_handle); + if (p == NULL) { + goto err; + } + + rc = enc_adv_data_set_km_exist(p->peer_addr); + if (rc != 0) { + MODLOG_DFLT(INFO, "Setting key material exist flag failed"); + } + + value_ead.km_present = 1; + + value_ead.km = (struct key_material *) malloc (sizeof(struct key_material)); + + memset(value_ead.km, 0, sizeof(struct key_material)); + + os_mbuf_copydata(attr->om, 0, BLE_EAD_KEY_SIZE, &value_ead.km->session_key); + os_mbuf_copydata(attr->om, BLE_EAD_KEY_SIZE, BLE_EAD_IV_SIZE, &value_ead.km->iv); + + MODLOG_DFLT(DEBUG, "Session key:"); + print_bytes(value_ead.km->session_key, BLE_EAD_KEY_SIZE); + + MODLOG_DFLT(DEBUG, "IV:"); + print_bytes(value_ead.km->iv, BLE_EAD_IV_SIZE); + + memcpy(&value_ead.peer_addr.val, &p->peer_addr, PEER_ADDR_VAL_SIZE); + + rc = ble_store_write_ead(&value_ead); + if (rc == 0) { + MODLOG_DFLT(INFO, "Writing of session key, iv, and peer addr to NVS success"); + } + +err: + /* Terminate the connection. */ + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); +} + +static void +enc_adv_data_cent_read(const struct peer *peer) +{ + const struct peer_chr *chr = NULL; + int rc; + + /* Read the supported-new-alert-category characteristic. */ + chr = peer_chr_find_uuid(peer, + BLE_UUID16_DECLARE(BLE_SVC_GAP_UUID16), + BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_KEY_MATERIAL)); + if (chr == NULL) { + MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Key" + "Material characteristic\n"); + goto err; + } + + rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle, + enc_adv_data_cent_on_read, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error: Failed to read characteristic; rc=%d\n", + rc); + goto err; + } + + return; +err: + /* Terminate the connection. */ + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); +} + +/** + * Called when service discovery of the specified peer has completed. + */ +static void +enc_adv_data_cent_on_disc_complete(const struct peer *peer, int status, void *arg) +{ + if (status != 0) { + /* Service discovery failed. Terminate the connection. */ + MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d " + "conn_handle=%d\n", status, peer->conn_handle); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return; + } + + /* Service discovery has completed successfully. Now we have a complete + * list of services, characteristics, and descriptors that the peer + * supports. + */ + MODLOG_DFLT(INFO, "Service discovery complete; status=%d " + "conn_handle=%d\n", status, peer->conn_handle); + + if (!enc_adv_data_check_km_exist(peer->peer_addr)) { + /* Now perform GATT read procedures against the peer */ + enc_adv_data_cent_read(peer); + } +} + +/** + * Initiates the GAP general discovery procedure. + */ +static void +enc_adv_data_cent_scan(void) +{ + uint8_t own_addr_type; + struct ble_gap_disc_params disc_params; + int rc; + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); + return; + } + + /* Tell the controller to filter duplicates; we don't want to process + * repeated advertisements from the same device. + */ + disc_params.filter_duplicates = 1; + + /** + * Perform a passive scan. I.e., don't send follow-up scan requests to + * each advertiser. + */ + disc_params.passive = 1; + + /* Use defaults for the rest of the parameters. */ + disc_params.itvl = 0; + disc_params.window = 0; + disc_params.filter_policy = 0; + disc_params.limited = 0; + + rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, + enc_adv_data_cent_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n", + rc); + } +} + +static int +enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_t *peer_addr) +{ + uint8_t op; + uint8_t len, offset = 0; + uint8_t *enc_data; + int rc; + uint8_t dec_data_len; + struct ble_store_key_ead key_ead = {0}; + struct ble_store_value_ead value_ead = {0}; + + while (offset < length_data) { + len = data[offset]; + op = data[offset + 1]; + uint8_t temp[len]; + + switch (op) { + case BLE_GAP_ENC_ADV_DATA: + enc_data = (uint8_t *) malloc (sizeof(uint8_t) * len); + memcpy(enc_data, data + offset + 2, len); + + memcpy(&key_ead.peer_addr.val, peer_addr, PEER_ADDR_VAL_SIZE); + + rc = ble_store_read_ead(&key_ead, &value_ead); + if (rc != 0 || !value_ead.km_present) { + MODLOG_DFLT(INFO, "Reading of session key and iv from NVS failed rc = %d", rc); + return 0; + } else { + MODLOG_DFLT(INFO, "Read session key and iv from NVS successfully"); + } + + rc = ble_ead_decrypt(value_ead.km->session_key, value_ead.km->iv, enc_data, len, + temp); + if (rc == 0) { + MODLOG_DFLT(INFO, "Decryption of adv data done successfully"); + } else { + MODLOG_DFLT(INFO, "Decryption of adv data failed"); + return 0; + } + + dec_data_len = temp[0]; + + MODLOG_DFLT(DEBUG, "Data after decryption:"); + print_bytes(temp, dec_data_len); + return 1; + + default: + break; + } + offset += len + 1; + } + return 1; +} + +/** + * Indicates whether we should try to connect to the sender of the specified + * advertisement. The function returns a positive result if the device + * advertises connectability and support for the Key Characteristic service. + */ +static int +ext_enc_adv_data_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) +{ + int offset = 0; + int ad_struct_len = 0; + + if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && + disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + return 0; + } + + if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { + MODLOG_DFLT(INFO, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); + /* Convert string to address */ + sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &peer_addr[5], &peer_addr[4], &peer_addr[3], + &peer_addr[2], &peer_addr[1], &peer_addr[0]); + if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { + return 0; + } + } + + /* The device has to advertise support for the Key Characteristic + * service (0x2B88) + */ + do { + ad_struct_len = disc->data[offset]; + + if (!ad_struct_len) { + break; + } + + /* Search if custom service UUID (0x2C01) is advertised */ + if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) { + if ( disc->data[offset + 2] == 0x2C && disc->data[offset + 3] == 0x01 ) { + if (enc_adv_data_find_peer(disc->addr.val) != -1) { + MODLOG_DFLT(INFO, "Peer was already added with addr : %s", + addr_str(&disc->addr.val)); + } else { + MODLOG_DFLT(INFO, "Adding peer addr : %s", addr_str(&disc->addr.val)); + + memcpy(&kmp[counter].peer_addr, &disc->addr.val, PEER_ADDR_VAL_SIZE); + counter++; + + if (counter > CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { + counter = 0; + } + } + if (enc_adv_data_check_km_exist(disc->addr.val)) { + return enc_adv_data_cent_decrypt(disc->length_data, disc->data, disc->addr.val); + } else { + return 1; + } + } + } + + offset += ad_struct_len + 1; + + } while ( offset < disc->length_data ); + + return 0; +} + +/** + * Connects to the sender of the specified advertisement of it looks + * interesting. A device is "interesting" if it advertises connectability and + * support for the Key Characteristic service. + */ +static void +enc_adv_data_cent_connect_if_interesting(void *disc) +{ + uint8_t own_addr_type; + int rc; + ble_addr_t *addr; + + /* Don't do anything if we don't care about this advertiser. */ + if (!ext_enc_adv_data_cent_should_connect((struct ble_gap_ext_disc_desc *)disc)) { + return; + } + + /* Scanning must be stopped before a connection can be initiated. */ + rc = ble_gap_disc_cancel(); + if (rc != 0) { + MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc); + return; + } + + /* Figure out address to use for connect (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); + return; + } + + /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for + * timeout. + */ + addr = &((struct ble_gap_ext_disc_desc *)disc)->addr; + + rc = ble_gap_connect(own_addr_type, addr, 30000, NULL, + enc_adv_data_cent_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " + "addr=%s; rc=%d\n", + addr->type, addr_str(addr->val), rc); + return; + } +} + +/** + * The nimble host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that is + * established. enc_adv_data_cent uses the same callback for all connections. + * + * @param event The event being signalled. + * @param arg Application-specified argument; unused by + * enc_adv_data_cent. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int +enc_adv_data_cent_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + struct ble_hs_adv_fields fields; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_DISC: + rc = ble_hs_adv_parse_fields(&fields, event->disc.data, + event->disc.length_data); + if (rc != 0) { + return 0; + } + + /* An advertisment report was received during GAP discovery. */ + print_adv_fields(&fields); + + /* Try to connect to the advertiser if it looks interesting. */ + enc_adv_data_cent_connect_if_interesting(&event->disc); + return 0; + + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + /* Connection successfully established. */ + MODLOG_DFLT(INFO, "Connection established "); + + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + MODLOG_DFLT(INFO, ""); + + rc = ble_att_set_preferred_mtu(mtu_def); + if (rc != 0) { + ESP_LOGE(tag, "Failed to set preferred MTU; rc = %d", rc); + } + + rc = ble_gattc_exchange_mtu(event->connect.conn_handle, NULL, NULL); + if (rc != 0) { + ESP_LOGE(tag, "Failed to negotiate MTU; rc = %d", rc); + } + + /* Remember peer. */ + rc = peer_add(event->connect.conn_handle); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc); + return 0; + } + + rc = peer_set_addr(event->connect.conn_handle, desc.peer_id_addr.val); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to set peer addr; rc=%d\n", rc); + return 0; + } + + /* Perform service discovery */ + rc = peer_disc_all(event->connect.conn_handle, + enc_adv_data_cent_on_disc_complete, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc); + return 0; + } + } else { + /* Connection attempt failed; resume scanning. */ + MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n", + event->connect.status); + enc_adv_data_cent_scan(); + } + + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + /* Connection terminated. */ + MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason); + print_conn_desc(&event->disconnect.conn); + MODLOG_DFLT(INFO, ""); + + /* Forget about peer. */ + peer_delete(event->disconnect.conn.conn_handle); + + /* Resume scanning. */ + enc_adv_data_cent_scan(); + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + MODLOG_DFLT(INFO, "discovery complete; reason=%d\n", + event->disc_complete.reason); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + /* Peer sent us a notification or indication. */ + MODLOG_DFLT(INFO, "received %s; conn_handle=%d attr_handle=%d " + "attr_len=%d\n", + event->notify_rx.indication ? + "indication" : + "notification", + event->notify_rx.conn_handle, + event->notify_rx.attr_handle, + OS_MBUF_PKTLEN(event->notify_rx.om)); + + /* Attribute data is contained in event->notify_rx.om. Use + * `os_mbuf_copydata` to copy the data received in notification mbuf */ + return 0; + + case BLE_GAP_EVENT_MTU: + MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_EXT_DISC: + /* An advertisment report was received during GAP discovery. */ + ext_print_adv_report(&event->disc); + + enc_adv_data_cent_connect_if_interesting(&event->disc); + return 0; + + default: + return 0; + } +} + +static void +enc_adv_data_cent_on_reset(int reason) +{ + MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); +} + +static void +enc_adv_data_cent_on_sync(void) +{ + int rc; + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + enc_adv_data_cent_scan(); +} + +void enc_adv_data_cent_host_task(void *param) +{ + MODLOG_DFLT(INFO, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +void +app_main(void) +{ + int rc; + /* Initialize NVS — it is used to store PHY calibration data */ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ret = nimble_port_init(); + if (ret != ESP_OK) { + ESP_LOGE(tag, "Failed to init nimble %d ", ret); + return; + } + + /* Configure the host. */ + ble_hs_cfg.reset_cb = enc_adv_data_cent_on_reset; + ble_hs_cfg.sync_cb = enc_adv_data_cent_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Initialize data structures to track connected peers. */ + rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); + assert(rc == 0); + + /* Set the default device name. */ + rc = ble_svc_gap_device_name_set("nimble-enc_adv_data_cent"); + assert(rc == 0); + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(enc_adv_data_cent_host_task); +} +#else +void +app_main(void) +{ + return; +} +#endif diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/sdkconfig.defaults b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/sdkconfig.defaults new file mode 100644 index 0000000000..3ff7b7d389 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/sdkconfig.defaults @@ -0,0 +1,14 @@ +# Override some defaults so BT stack is enabled +# in this example + +# +# BT config +# +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_EXT_ADV=y +CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt new file mode 100644 index 0000000000..603a43c509 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(enc_adv_data_prph) diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md new file mode 100644 index 0000000000..1402564ca2 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md @@ -0,0 +1,108 @@ +| Supported Targets | ESP32-C2 | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | -------- | + +# BLE Encrypted Advertising Data Peripheral Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example creates GATT server and then starts normal advertising and encrypted advertising data, waiting to be connected to a GATT client. + +This example aims at understanding advertising encrypted data. + +For RPA feature (currently Host based privacy feature is supported), use API `ble_hs_pvcy_rpa_config` to enable/disable host based privacy, `own_addr_type` needs to be set to `BLE_ADDR_RANDOM` to use this feature. Please include `ble_hs_pvcy.h` while using this API. As `ble_hs_pvcy_rpa_config` configures host privacy and sets address in controller, it is necessary to call this API after host-controller are synced (e.g. in `bleprph_on_sync` callback). + +## How to Use Example + +Before project configuration and build, be sure to set the correct chip target using: + +```bash +idf.py set-target +``` + +### Configure the project + +Open the project configuration menu: + +```bash +idf.py menuconfig +``` +In the `Component config` menu: + +* Select encrypted adv data from `Component config -> Bluetooth -> NimBLE Options -> BT_NIMBLE_ENC_ADV_DATA` + +In the `Example Configuration` menu: + +* Select I/O capabilities of device from `Example Configuration --> I/O Capability`, default is `Just_works`. +* Enable/Disable other security related parameters `Bonding, MITM option, secure connection(SM SC)`. + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +There is this console output when bleprph is connected and characteristic is read: + +``` +I (445) NimBLE: BLE Host Task Started +I (445) NimBLE: Device Address: +I (445) NimBLE: 60:55:f9:f7:4f:42 +I (445) NimBLE: + +I (455) NimBLE: Encryption of adv data done successfully +I (465) main_task: Returned from app_main() +I (575) NimBLE: connection established; status=0 +I (575) NimBLE: handle=1 our_ota_addr_type=0 our_ota_addr= +I (575) NimBLE: 60:55:f9:f7:4f:42 +I (585) NimBLE: our_id_addr_type=0 our_id_addr= +I (585) NimBLE: 60:55:f9:f7:4f:42 +I (595) NimBLE: peer_ota_addr_type=0 peer_ota_addr= +I (595) NimBLE: 60:55:f9:f7:51:0a +I (605) NimBLE: peer_id_addr_type=0 peer_id_addr= +I (605) NimBLE: 60:55:f9:f7:51:0a +I (615) NimBLE: conn_itvl=24 conn_latency=0 supervision_timeout=256 encrypted=0 authenticated=0 bonded=0 + +I (625) NimBLE: + +I (625) NimBLE: advertise complete; reason=0 +I (635) NimBLE: Encryption of adv data done successfully + +I (1635) NimBLE: disconnect; reason=531 +I (1635) NimBLE: handle=1 our_ota_addr_type=0 our_ota_addr= +I (1635) NimBLE: 60:55:f9:f7:4f:42 +I (1635) NimBLE: our_id_addr_type=0 our_id_addr= +I (1635) NimBLE: 60:55:f9:f7:4f:42 +I (1645) NimBLE: peer_ota_addr_type=0 peer_ota_addr= +I (1645) NimBLE: 60:55:f9:f7:51:0a +I (1655) NimBLE: peer_id_addr_type=0 peer_id_addr= +I (1655) NimBLE: 60:55:f9:f7:51:0a +I (1665) NimBLE: conn_itvl=24 conn_latency=0 supervision_timeout=256 encrypted=0 authenticated=0 bonded=0 + +I (1675) NimBLE: + +I (1675) NimBLE: connection established; status=0 +I (1685) NimBLE: handle=1 our_ota_addr_type=0 our_ota_addr= +I (1685) NimBLE: 60:55:f9:f7:4f:42 +I (1695) NimBLE: our_id_addr_type=0 our_id_addr= +I (1695) NimBLE: 60:55:f9:f7:4f:42 +I (1705) NimBLE: peer_ota_addr_type=0 peer_ota_addr= +I (1705) NimBLE: 60:55:f9:f7:51:0a +I (1715) NimBLE: peer_id_addr_type=0 peer_id_addr= +I (1715) NimBLE: 60:55:f9:f7:51:0a +I (1725) NimBLE: conn_itvl=24 conn_latency=0 supervision_timeout=256 encrypted=0 authenticated=0 bonded=0 + +I (1735) NimBLE: + +I (1735) NimBLE: advertise complete; reason=0 +I (1745) NimBLE: Encryption of adv data done successfully +I (1755) NimBLE: mtu update event; conn_handle=1 cid=4 mtu=256 + +``` + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/CMakeLists.txt new file mode 100644 index 0000000000..9e539a9fc0 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "main.c" + "gatt_svr.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/Kconfig.projbuild new file mode 100644 index 0000000000..25bcc5ecfb --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/Kconfig.projbuild @@ -0,0 +1,64 @@ +menu "Example Configuration" + + choice EXAMPLE_USE_IO_TYPE + prompt "I/O Capability" + default BLE_SM_IO_CAP_NO_IO + help + I/O capability of device. + + config BLE_SM_IO_CAP_DISP_ONLY + bool "DISPLAY ONLY" + config BLE_SM_IO_CAP_DISP_YES_NO + bool "DISPLAY YESNO" + config BLE_SM_IO_CAP_KEYBOARD_ONLY + bool "KEYBOARD ONLY" + config BLE_SM_IO_CAP_NO_IO + bool "Just works" + config BLE_SM_IO_CAP_KEYBOARD_DISP + bool "Both KEYBOARD & DISPLAY" + endchoice + + config EXAMPLE_IO_TYPE + int + default 0 if BLE_SM_IO_CAP_DISP_ONLY + default 1 if BLE_SM_IO_CAP_DISP_YES_NO + default 2 if BLE_SM_IO_CAP_KEYBOARD_ONLY + default 3 if BLE_SM_IO_CAP_NO_IO + default 4 if BLE_SM_IO_CAP_KEYBOARD_DISP + + config EXAMPLE_BONDING + bool + default n + prompt "Use Bonding" + help + Use this option to enable/disable bonding. + + config EXAMPLE_USE_SC + bool + depends on BT_NIMBLE_SM_SC + default n + prompt "Use Secure Connection feature" + help + Use this option to enable/disable Security Manager Secure Connection 4.2 feature. + + config EXAMPLE_RANDOM_ADDR + bool + prompt "Advertise RANDOM Address" + help + Use this option to advertise a random address instead of public address + + config EXAMPLE_RESOLVE_PEER_ADDR + bool + prompt "Enable resolving peer address" + help + Use this option to enable resolving peer's address. + + config EXAMPLE_ENC_ADV_DATA + bool + prompt "Enable encrypted advertising data feature support" + default y + select BT_NIMBLE_ENC_ADV_DATA + help + This option enables support of encrypted advertising data. + +endmenu diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/enc_adv_data_prph.h b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/enc_adv_data_prph.h new file mode 100644 index 0000000000..60faa47866 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/enc_adv_data_prph.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef H_ENC_ADV_DATA_PRPH_ +#define H_ENC_ADV_DATA_PRPH_ + +#if CONFIG_EXAMPLE_ENC_ADV_DATA +#include +#include "nimble/ble.h" +#include "modlog/modlog.h" +#include "esp_peripheral.h" +#include "host/ble_ead.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_hs_cfg; +struct ble_gatt_register_ctxt; + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); +int gatt_svr_init(void); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c new file mode 100644 index 0000000000..0c5020855d --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c @@ -0,0 +1,246 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" +#include "enc_adv_data_prph.h" + +/*** Maximum number of characteristics with the notify flag ***/ +#define MAX_NOTIFY 5 + +static const ble_uuid128_t gatt_svr_svc_uuid = + BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12, + 0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59); + +/* A characteristic that can be subscribed to */ +static uint8_t gatt_svr_chr_val; +static uint16_t gatt_svr_chr_val_handle; + +static const ble_uuid128_t gatt_svr_chr_uuid = + BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33); + +/* A custom descriptor */ +static uint8_t gatt_svr_dsc_val; +static const ble_uuid128_t gatt_svr_dsc_uuid = + BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12, + 0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34); + +static int +gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service ***/ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &gatt_svr_svc_uuid.u, + .characteristics = (struct ble_gatt_chr_def[]) + { { + /*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/ + .uuid = &gatt_svr_chr_uuid.u, + .access_cb = gatt_svc_access, +#if CONFIG_EXAMPLE_ENCRYPTION + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC | + BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE, +#else + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE, +#endif + .val_handle = &gatt_svr_chr_val_handle, + .descriptors = (struct ble_gatt_dsc_def[]) { + { + .uuid = &gatt_svr_dsc_uuid.u, +#if CONFIG_EXAMPLE_ENCRYPTION + .att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC, +#else + .att_flags = BLE_ATT_F_READ, +#endif + .access_cb = gatt_svc_access, + }, { + 0, /* No more descriptors in this characteristic */ + } + }, + }, { + 0, /* No more characteristics in this service. */ + } + }, + }, + { + 0, /* No more services. */ + }, +}; + +static int +gatt_svr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len, + void *dst, uint16_t *len) +{ + uint16_t om_len; + int rc; + + om_len = OS_MBUF_PKTLEN(om); + if (om_len < min_len || om_len > max_len) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; +} + +/** + * Access callback whenever a characteristic/descriptor is read or written to. + * Here reads and writes need to be handled. + * ctxt->op tells weather the operation is read or write and + * weather it is on a characteristic or descriptor, + * ctxt->dsc->uuid tells which characteristic/descriptor is accessed. + * attr_handle give the value handle of the attribute being accessed. + * Accordingly do: + * Append the value to ctxt->om if the operation is READ + * Write ctxt->om to the value if the operation is WRITE + **/ +static int +gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const ble_uuid_t *uuid; + int rc; + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { + MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n", + conn_handle, attr_handle); + } else { + MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n", + attr_handle); + } + uuid = ctxt->chr->uuid; + + if (attr_handle == gatt_svr_chr_val_handle) { + rc = os_mbuf_append(ctxt->om, + &gatt_svr_chr_val, + sizeof(gatt_svr_chr_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + goto unknown; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { + MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d", + conn_handle, attr_handle); + } else { + MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d", + attr_handle); + } + uuid = ctxt->chr->uuid; + if (attr_handle == gatt_svr_chr_val_handle) { + rc = gatt_svr_write(ctxt->om, + sizeof(gatt_svr_chr_val), + sizeof(gatt_svr_chr_val), + &gatt_svr_chr_val, NULL); + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + return rc; + } + goto unknown; + + case BLE_GATT_ACCESS_OP_READ_DSC: + if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { + MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n", + conn_handle, attr_handle); + } else { + MODLOG_DFLT(INFO, "Descriptor read by NimBLE stack; attr_handle=%d\n", + attr_handle); + } + uuid = ctxt->dsc->uuid; + if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { + rc = os_mbuf_append(ctxt->om, + &gatt_svr_dsc_val, + sizeof(gatt_svr_chr_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + goto unknown; + + case BLE_GATT_ACCESS_OP_WRITE_DSC: + goto unknown; + + default: + goto unknown; + } + +unknown: + /* Unknown characteristic/descriptor; + * The NimBLE host should not have called this function; + */ + assert(0); + return BLE_ATT_ERR_UNLIKELY; +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + MODLOG_DFLT(DEBUG, "registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(void) +{ + int rc; + + ble_svc_gap_init(); + ble_svc_gatt_init(); + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + /* Setting a value for the read-only descriptor */ + gatt_svr_dsc_val = 0x99; + + return 0; +} diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c new file mode 100644 index 0000000000..4e7320a1e0 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c @@ -0,0 +1,420 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "esp_log.h" +#include "nvs_flash.h" +/* BLE */ +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "console/console.h" +#include "services/gap/ble_svc_gap.h" +#include "enc_adv_data_prph.h" + +#if CONFIG_EXAMPLE_ENC_ADV_DATA +static uint8_t km_adv_pattern_1[] = { + 0x02, 0x01, 0x06, + 0x03, 0x03, 0x2C, 0x01, + 0x04, 0X09, 'k', 'e', 'y', +}; + +static const char *tag = "ENC_ADV_DATA_PRPH"; +static int enc_adv_data_prph_gap_event(struct ble_gap_event *event, void *arg); + +static uint8_t ext_adv_pattern_1[] = { + 0x02, 0x01, 0x06, + 0x03, 0x03, 0x2C, 0x00, + 0x05, 0X09, 'p', 'r', 'p', 'h', +}; + +struct key_material km = { + .session_key = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, + 0xCC, 0xCD, 0xCE, 0xCF + }, + .iv = {0xFB, 0x56, 0xE1, 0xDA, 0xDC, 0x7E, 0xAD, 0xF5}, +}; + +#if CONFIG_EXAMPLE_RANDOM_ADDR +static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; +#else +static uint8_t own_addr_type; +#endif + +void ble_store_config_init(void); + +/** + * Logs information about a connection to the console. + */ +static void +enc_adv_data_prph_print_conn_desc(struct ble_gap_conn_desc *desc) +{ + MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=", + desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=", + desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=", + desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=", + desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + +static const struct enc_adv_data ead[] = { + ENC_ADV_DATA(BLE_GAP_ENC_ADV_DATA, ext_adv_pattern_1, sizeof(ext_adv_pattern_1)), +}; + +static void enc_adv_data_prph_encrypt_set(uint8_t instance, struct os_mbuf *data) +{ + int rc; + + uint8_t enc_data_flag = BLE_GAP_ENC_ADV_DATA; //0x31 + + uint8_t ext_adv_pattern_sz = ead[0].len; + + size_t adv_data_sz = BLE_GAP_DATA_SERIALIZED_SIZE(ext_adv_pattern_sz); + uint8_t adv_data[adv_data_sz]; + + size_t enc_adv_data_sz = BLE_EAD_ENCRYPTED_PAYLOAD_SIZE(adv_data_sz); + uint8_t enc_adv_data[enc_adv_data_sz]; + + ble_ead_serialize_data(&ead[0], adv_data); + + MODLOG_DFLT(DEBUG, "Data before encryption:"); + print_bytes(adv_data, adv_data_sz); + MODLOG_DFLT(DEBUG, "\n"); + + rc = ble_ead_encrypt(km.session_key, km.iv, adv_data, adv_data_sz, enc_adv_data); + if (rc == 0) { + MODLOG_DFLT(INFO, "Encryption of adv data done successfully"); + } else { + MODLOG_DFLT(INFO, "Encryption of adv data failed"); + return; + } + + MODLOG_DFLT(DEBUG, "Data after encryption:"); + print_bytes(enc_adv_data, enc_adv_data_sz); + MODLOG_DFLT(DEBUG, "\n"); + + //Copying encrypted data + rc = os_mbuf_append(data, &enc_adv_data_sz, sizeof(uint8_t)); + + rc = os_mbuf_append(data, &enc_data_flag, sizeof(uint8_t)); + + rc = os_mbuf_append(data, enc_adv_data, enc_adv_data_sz); + assert(rc == 0); + + MODLOG_DFLT(INFO, "Advertising data:"); + print_mbuf(data); +} + +/** + * Enables advertising with the following parameters: + * o General discoverable mode. + * o Undirected connectable mode. + */ +static void +ext_enc_adv_data_prph_advertise(void) +{ + struct ble_gap_ext_adv_params params; + uint8_t instance = 0; + int rc; + + struct os_mbuf *data; + + /* First check if any instance is already active */ + if (ble_gap_ext_adv_active(instance)) { + return; + } + + /* use defaults for non-set params */ + memset (¶ms, 0, sizeof(params)); + + /* enable connectable advertising */ + params.connectable = 1; + + /* advertise using random addr */ + params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + + params.primary_phy = BLE_HCI_LE_PHY_1M; + params.secondary_phy = BLE_HCI_LE_PHY_2M; + //params.tx_power = 127; + params.sid = 1; + + params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + + /* configure instance 0 */ + rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, + enc_adv_data_prph_gap_event, NULL); + assert (rc == 0); + + /* in this case only scan response is allowed */ + /* get mbuf for scan rsp data */ + data = os_msys_get_pkthdr(sizeof(km_adv_pattern_1), 0); + assert(data); + + rc = os_mbuf_append(data, km_adv_pattern_1, sizeof(km_adv_pattern_1)); + assert(rc == 0); + + //Encrypted advertising data + enc_adv_data_prph_encrypt_set(instance, data); + + rc = ble_gap_ext_adv_set_data(instance, data); + assert (rc == 0); + + /* start advertising */ + rc = ble_gap_ext_adv_start(instance, 0, 0); + assert (rc == 0); +} + +/** + * The nimble host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that forms. + * enc_adv_data_prph uses the same callback for all connections. + * + * @param event The type of event being signalled. + * @param ctxt Various information pertaining to the event. + * @param arg Application-specified argument; unused by + * enc_adv_data_prph. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int +enc_adv_data_prph_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + MODLOG_DFLT(INFO, "connection %s; status=%d ", + event->connect.status == 0 ? "established" : "failed", + event->connect.status); + if (event->connect.status == 0) { + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + enc_adv_data_prph_print_conn_desc(&desc); + } + MODLOG_DFLT(INFO, "\n"); + + if (event->connect.status != 0) { + /* Connection failed; resume advertising. */ + ext_enc_adv_data_prph_advertise(); + } + + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason); + enc_adv_data_prph_print_conn_desc(&event->disconnect.conn); + MODLOG_DFLT(INFO, "\n"); + + /* Connection terminated; resume advertising. */ + ext_enc_adv_data_prph_advertise(); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + /* The central has updated the connection parameters. */ + MODLOG_DFLT(INFO, "connection updated; status=%d ", + event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + enc_adv_data_prph_print_conn_desc(&desc); + MODLOG_DFLT(INFO, "\n"); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + MODLOG_DFLT(INFO, "advertise complete; reason=%d", + event->adv_complete.reason); + return 0; + + case BLE_GAP_EVENT_NOTIFY_TX: + MODLOG_DFLT(INFO, "notify_tx event; conn_handle=%d attr_handle=%d " + "status=%d is_indication=%d", + event->notify_tx.conn_handle, + event->notify_tx.attr_handle, + event->notify_tx.status, + event->notify_tx.indication); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + return 0; + + case BLE_GAP_EVENT_MTU: + MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + } + + return 0; +} + +static void +enc_adv_data_prph_on_reset(int reason) +{ + MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); +} + +#if CONFIG_EXAMPLE_RANDOM_ADDR +static void +ble_app_set_addr(void) +{ + ble_addr_t addr; + int rc; + + /* generate new non-resolvable private address */ + rc = ble_hs_id_gen_rnd(0, &addr); + assert(rc == 0); + + /* set generated address */ + rc = ble_hs_id_set_rnd(addr.val); + + assert(rc == 0); +} +#endif + +static void +enc_adv_data_prph_on_sync(void) +{ + int rc; + +#if CONFIG_EXAMPLE_RANDOM_ADDR + /* Generate a non-resolvable private address. */ + ble_app_set_addr(); +#endif + + /* Make sure we have proper identity address set (public preferred) */ +#if CONFIG_EXAMPLE_RANDOM_ADDR + rc = ble_hs_util_ensure_addr(1); +#else + rc = ble_hs_util_ensure_addr(0); +#endif + assert(rc == 0); + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); + return; + } + + /* Printing ADDR */ + uint8_t addr_val[6] = {0}; + rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL); + + MODLOG_DFLT(INFO, "Device Address: "); + print_addr(addr_val); + MODLOG_DFLT(INFO, "\n"); + + /* Begin advertising. */ + ext_enc_adv_data_prph_advertise(); +} + +void enc_adv_data_prph_host_task(void *param) +{ + MODLOG_DFLT(INFO, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +void +app_main(void) +{ + int rc; + + /* Initialize NVS — it is used to store PHY calibration data */ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ret = nimble_port_init(); + if (ret != ESP_OK) { + ESP_LOGE(tag, "Failed to init nimble %d ", ret); + return; + } + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = enc_adv_data_prph_on_reset; + ble_hs_cfg.sync_cb = enc_adv_data_prph_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + ble_hs_cfg.sm_io_cap = CONFIG_EXAMPLE_IO_TYPE; +#ifdef CONFIG_EXAMPLE_BONDING + ble_hs_cfg.sm_bonding = 1; + /* Enable the appropriate bit masks to make sure the keys + * that are needed are exchanged + */ + ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC; + ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC; +#endif + + ble_hs_cfg.sm_mitm = 1; +#ifdef CONFIG_EXAMPLE_USE_SC + ble_hs_cfg.sm_sc = 1; +#else + ble_hs_cfg.sm_sc = 0; +#endif +#ifdef CONFIG_EXAMPLE_RESOLVE_PEER_ADDR + /* Stores the IRK */ + ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; + ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID; +#endif + + rc = gatt_svr_init(); + assert(rc == 0); + + /* Set the default device name. */ + rc = ble_svc_gap_device_name_set("enc_adv_data_prph"); + assert(rc == 0); + + /* Set the session key and initialization vector */ + rc = ble_svc_gap_device_key_material_set(km.session_key, km.iv); + assert(rc == 0); + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(enc_adv_data_prph_host_task); +} +#else +void +app_main(void) +{ + return; +} +#endif diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/sdkconfig.defaults b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/sdkconfig.defaults new file mode 100644 index 0000000000..3f4f3bfba3 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/sdkconfig.defaults @@ -0,0 +1,14 @@ +# Override some defaults so BT stack is enabled +# in this example + +# +# BT config +# +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_BT_NIMBLE_EXT_ADV=y diff --git a/examples/bluetooth/nimble/common/nimble_central_utils/esp_central.h b/examples/bluetooth/nimble/common/nimble_central_utils/esp_central.h index 573f2a62c3..396d416ea7 100644 --- a/examples/bluetooth/nimble/common/nimble_central_utils/esp_central.h +++ b/examples/bluetooth/nimble/common/nimble_central_utils/esp_central.h @@ -12,6 +12,8 @@ extern "C" { #endif +#define PEER_ADDR_VAL_SIZE 6 + /** Misc. */ void print_bytes(const uint8_t *bytes, int len); void print_mbuf(const struct os_mbuf *om); @@ -60,9 +62,10 @@ typedef int peer_traverse_fn(const struct peer *peer, void *arg); struct peer { SLIST_ENTRY(peer) next; - uint16_t conn_handle; + uint8_t peer_addr[PEER_ADDR_VAL_SIZE]; + /** List of discovered GATT services. */ struct peer_svc_list svcs; @@ -95,8 +98,9 @@ int peer_add(uint16_t conn_handle); int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs); struct peer * peer_find(uint16_t conn_handle); - - +#if MYNEWT_VAL(ENC_ADV_DATA) +int peer_set_addr(uint16_t conn_handle, uint8_t *peer_addr); +#endif #ifdef __cplusplus } #endif diff --git a/examples/bluetooth/nimble/common/nimble_central_utils/misc.c b/examples/bluetooth/nimble/common/nimble_central_utils/misc.c index 41f3dfff46..e901adde92 100644 --- a/examples/bluetooth/nimble/common/nimble_central_utils/misc.c +++ b/examples/bluetooth/nimble/common/nimble_central_utils/misc.c @@ -88,7 +88,7 @@ print_conn_desc(const struct ble_gap_conn_desc *desc) desc->sec_state.bonded); } -#if CONFIG_EXAMPLE_EXTENDED_ADV +#if MYNEWT_VAL(BLE_EXT_ADV) void print_addr(const void *addr, const char *name) { diff --git a/examples/bluetooth/nimble/common/nimble_central_utils/peer.c b/examples/bluetooth/nimble/common/nimble_central_utils/peer.c index 80515884ba..87bcf094a8 100644 --- a/examples/bluetooth/nimble/common/nimble_central_utils/peer.c +++ b/examples/bluetooth/nimble/common/nimble_central_utils/peer.c @@ -748,6 +748,22 @@ peer_traverse_all(peer_traverse_fn *trav_cb, void *arg) } } +#if MYNEWT_VAL(ENC_ADV_DATA) +int +peer_set_addr(uint16_t conn_handle, uint8_t *peer_addr) +{ + struct peer *peer; + + peer = peer_find(conn_handle); + if (peer == NULL) { + return BLE_HS_ENOTCONN; + } + + memcpy(&peer->peer_addr, peer_addr, PEER_ADDR_VAL_SIZE); + return 0; +} +#endif + static void peer_free_mem(void) { diff --git a/examples/bluetooth/nimble/common/nimble_peripheral_utils/esp_peripheral.h b/examples/bluetooth/nimble/common/nimble_peripheral_utils/esp_peripheral.h index be2018a8dc..78c2b2488c 100644 --- a/examples/bluetooth/nimble/common/nimble_peripheral_utils/esp_peripheral.h +++ b/examples/bluetooth/nimble/common/nimble_peripheral_utils/esp_peripheral.h @@ -22,6 +22,7 @@ int scli_receive_key(int *key); void print_bytes(const uint8_t *bytes, int len); void print_addr(const void *addr); char *addr_str(const void *addr); +void print_mbuf(const struct os_mbuf *om); #ifdef __cplusplus } diff --git a/examples/bluetooth/nimble/common/nimble_peripheral_utils/misc.c b/examples/bluetooth/nimble/common/nimble_peripheral_utils/misc.c index 962eb4da72..9444c27c5c 100644 --- a/examples/bluetooth/nimble/common/nimble_peripheral_utils/misc.c +++ b/examples/bluetooth/nimble/common/nimble_peripheral_utils/misc.c @@ -41,3 +41,22 @@ addr_str(const void *addr) return buf; } + +void +print_mbuf(const struct os_mbuf *om) +{ + int colon, i; + + colon = 0; + while (om != NULL) { + if (colon) { + MODLOG_DFLT(DEBUG, ":"); + } else { + colon = 1; + } + for (i = 0; i < om->om_len; i++) { + MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", om->om_data[i]); + } + om = SLIST_NEXT(om, om_next); + } +}