diff --git a/.gitlab/ci/docs.yml b/.gitlab/ci/docs.yml index 3ea791048af7..139ac5b32ea6 100644 --- a/.gitlab/ci/docs.yml +++ b/.gitlab/ci/docs.yml @@ -118,7 +118,7 @@ build_docs_html_full: paths: - docs/_build/*/*/*.txt - docs/_build/*/*/html/* - expire_in: 4 days + expire_in: 12 hrs variables: DOC_BUILDERS: "html" @@ -131,7 +131,7 @@ build_docs_html_partial: paths: - docs/_build/*/*/*.txt - docs/_build/*/*/html/* - expire_in: 4 days + expire_in: 12 hrs variables: DOC_BUILDERS: "html" parallel: diff --git a/components/app_trace/port/port_uart.c b/components/app_trace/port/port_uart.c index c4146d09d3e3..3761bc904643 100644 --- a/components/app_trace/port/port_uart.c +++ b/components/app_trace/port/port_uart.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -295,10 +295,9 @@ static esp_err_t esp_apptrace_uart_up_buffer_put(esp_apptrace_uart_data_t *hw_da static void esp_apptrace_uart_down_buffer_config(esp_apptrace_uart_data_t *hw_data, uint8_t *buf, uint32_t size) { - hw_data->down_buffer = (uint8_t *)malloc(size); - if (hw_data->down_buffer == NULL){ - assert(false && "Failed to allocate apptrace uart down buffer!"); - } + assert(buf != NULL && "Down buffer cannot be NULL"); + + hw_data->down_buffer = buf; hw_data->down_buffer_size = size; } diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index 4b6967782c44..0b63c884f5b0 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -519,7 +519,7 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest Cache_Read_Enable(0); #else #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_MMAP_VADDR, actual_mapped_len); + cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_READ_VADDR, actual_mapped_len); #endif #if !ESP_TEE_BUILD cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); diff --git a/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c b/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c index f0996e405933..12c7ce749231 100644 --- a/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c +++ b/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,12 +13,17 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/ecp.h" #include "rom/ecdsa.h" +#include "sdkconfig.h" #include "secure_boot_signature_priv.h" static const char *TAG = "secure_boot_v2_ecdsa"; +#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS +#define ECDSA_INTEGER_LEN 48 +#else #define ECDSA_INTEGER_LEN 32 +#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block) { @@ -48,6 +53,12 @@ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_bl key_size = 32; mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); break; +#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS + case ECDSA_CURVE_P384: + key_size = 48; + mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP384R1); + break; +#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */ default: ESP_LOGE(TAG, "Invalid curve ID"); return ESP_ERR_INVALID_ARG; diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 1f942a3a212c..a215bd4e8e54 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -47,6 +47,9 @@ set(ble_mesh_v11_include_dirs "esp_ble_mesh/v1.1/api/core/include" "esp_ble_mesh/v1.1/api/models/include" "esp_ble_mesh/v1.1/btc/include" + "esp_ble_mesh/v1.1/include" + "esp_ble_mesh/v1.1/dfu" + "esp_ble_mesh/v1.1/mbt" ) if(CONFIG_IDF_DOC_BUILD) @@ -571,7 +574,6 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/core/storage/settings.c" "esp_ble_mesh/core/access.c" "esp_ble_mesh/core/adv_common.c" - "esp_ble_mesh/core/ble_adv.c" "esp_ble_mesh/core/beacon.c" "esp_ble_mesh/core/cfg_cli.c" "esp_ble_mesh/core/cfg_srv.c" @@ -623,9 +625,13 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c" "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c" "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c" + "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c" + "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c" @@ -633,24 +639,35 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c" + "esp_ble_mesh/v1.1/mbt/blob_srv.c" + "esp_ble_mesh/v1.1/mbt/blob_cli.c" + "esp_ble_mesh/v1.1/dfu/dfu_cli.c" + "esp_ble_mesh/v1.1/dfu/dfu_srv.c" + "esp_ble_mesh/v1.1/dfu/dfu_slot.c" + "esp_ble_mesh/v1.1/dfu/dfu_metadata.c" + "esp_ble_mesh/v1.1/dfu/dfd_srv.c" + "esp_ble_mesh/v1.1/dfu/dfd_cli.c" "esp_ble_mesh/lib/ext.c") + if(CONFIG_BLE_MESH_SAR_ENHANCEMENT) list(APPEND srcs "esp_ble_mesh/core/transport.enh.c") else() list(APPEND srcs "esp_ble_mesh/core/transport.c") endif() else() - list(APPEND srcs - "esp_ble_mesh/core/transport.c") + list(APPEND srcs "esp_ble_mesh/core/transport.c") endif() + if(CONFIG_BLE_MESH_SUPPORT_MULTI_ADV) list(APPEND srcs "esp_ble_mesh/core/ext_adv.c") else() list(APPEND srcs "esp_ble_mesh/core/adv.c") endif() - endif() - + if(CONFIG_BLE_MESH_SUPPORT_BLE_ADV) + list(APPEND srcs "esp_ble_mesh/core/ble_adv.c") + endif() + endif() if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) list(APPEND srcs diff --git a/components/bt/common/btc/core/btc_alarm.c b/components/bt/common/btc/core/btc_alarm.c index 6c6177f7a351..67604332c13e 100644 --- a/components/bt/common/btc/core/btc_alarm.c +++ b/components/bt/common/btc/core/btc_alarm.c @@ -12,7 +12,7 @@ void btc_alarm_handler(btc_msg_t *msg) { btc_alarm_args_t *arg = (btc_alarm_args_t *)msg->arg; - BTC_TRACE_DEBUG("%s act %d\n", __FUNCTION__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); if (arg->cb) { arg->cb(arg->cb_data); diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 41c0b4368e72..9299015591a9 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -89,6 +89,7 @@ #include "btc_ble_mesh_rpr_model.h" #include "btc_ble_mesh_sar_model.h" #include "btc_ble_mesh_srpl_model.h" +#include "btc_ble_mesh_dfu_model.h" #endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #endif /* #if CONFIG_BLE_MESH */ @@ -262,6 +263,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { #if CONFIG_BLE_MESH_MBT_SRV [BTC_PID_MBT_SERVER] = {btc_ble_mesh_mbt_server_call_handler, btc_ble_mesh_mbt_server_cb_handler }, #endif /* CONFIG_BLE_MESH_MBT_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI + [BTC_PID_DFU_CLIENT] = {btc_ble_mesh_dfu_client_call_handler, btc_ble_mesh_dfu_client_cb_handler}, +#endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFD_CLI + [BTC_PID_DFD_CLIENT] = {btc_ble_mesh_dfd_client_call_handler, btc_ble_mesh_dfd_client_cb_handler}, +#endif /* CONFIG_BLE_MESH_DFD_CLI */ #if CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 [BTC_PID_BLE_MESH_BLE_COEX] = {btc_ble_mesh_ble_call_handler, btc_ble_mesh_ble_cb_handler }, #endif /* CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 */ diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index 04365582420b..5d1712018097 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -106,6 +106,12 @@ typedef enum { BTC_PID_TIME_SCENE_SERVER, BTC_PID_MBT_CLIENT, BTC_PID_MBT_SERVER, + BTC_PID_BLOB_CLIENT, + BTC_PID_BLOB_SERVER, + BTC_PID_DFU_CLIENT, + BTC_PID_DFU_SERVER, + BTC_PID_DFD_CLIENT, + BTC_PID_DFD_SERVER, BTC_PID_BLE_MESH_BLE_COEX, #endif /* CONFIG_BLE_MESH */ #if (BLE_FEAT_ISO_EN == TRUE) diff --git a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c index 744c0df83ad1..380da2edb586 100644 --- a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c +++ b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,6 +32,7 @@ #include "esp_bt_device.h" #include "esp_err.h" #include "esp_blufi.h" +#include #if (BLUFI_INCLUDED == TRUE) @@ -70,12 +71,155 @@ static esp_ble_adv_params_t blufi_adv_params = { .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; +#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE +static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req) +{ + char *auth_str = NULL; + switch(auth_req) { + case ESP_LE_AUTH_NO_BOND: + auth_str = "ESP_LE_AUTH_NO_BOND"; + break; + case ESP_LE_AUTH_BOND: + auth_str = "ESP_LE_AUTH_BOND"; + break; + case ESP_LE_AUTH_REQ_MITM: + auth_str = "ESP_LE_AUTH_REQ_MITM"; + break; + case ESP_LE_AUTH_REQ_BOND_MITM: + auth_str = "ESP_LE_AUTH_REQ_BOND_MITM"; + break; + case ESP_LE_AUTH_REQ_SC_ONLY: + auth_str = "ESP_LE_AUTH_REQ_SC_ONLY"; + break; + case ESP_LE_AUTH_REQ_SC_BOND: + auth_str = "ESP_LE_AUTH_REQ_SC_BOND"; + break; + case ESP_LE_AUTH_REQ_SC_MITM: + auth_str = "ESP_LE_AUTH_REQ_SC_MITM"; + break; + case ESP_LE_AUTH_REQ_SC_MITM_BOND: + auth_str = "ESP_LE_AUTH_REQ_SC_MITM_BOND"; + break; + default: + auth_str = "INVALID BLE AUTH REQ"; + break; + } + + return auth_str; +} + +static char *esp_key_type_to_str(esp_ble_key_type_t key_type) +{ + char *key_str = NULL; + switch(key_type) { + case ESP_LE_KEY_NONE: + key_str = "ESP_LE_KEY_NONE"; + break; + case ESP_LE_KEY_PENC: + key_str = "ESP_LE_KEY_PENC"; + break; + case ESP_LE_KEY_PID: + key_str = "ESP_LE_KEY_PID"; + break; + case ESP_LE_KEY_PCSRK: + key_str = "ESP_LE_KEY_PCSRK"; + break; + case ESP_LE_KEY_PLK: + key_str = "ESP_LE_KEY_PLK"; + break; + case ESP_LE_KEY_LLK: + key_str = "ESP_LE_KEY_LLK"; + break; + case ESP_LE_KEY_LENC: + key_str = "ESP_LE_KEY_LENC"; + break; + case ESP_LE_KEY_LID: + key_str = "ESP_LE_KEY_LID"; + break; + case ESP_LE_KEY_LCSRK: + key_str = "ESP_LE_KEY_LCSRK"; + break; + default: + key_str = "INVALID BLE KEY TYPE"; + break; + } + return key_str; +} +#endif + void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + BLUFI_TRACE_DEBUG("GAP_EVT, event %d", event); switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&blufi_adv_params); break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("Advertising start failed, status %x", param->adv_start_cmpl.status); + break; + } + BLUFI_TRACE_API("Advertising start successfully"); + break; +#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + BLUFI_TRACE_API("Passkey request"); + break; + case ESP_GAP_BLE_OOB_REQ_EVT: { + BLUFI_TRACE_API("OOB request"); + uint8_t tk[16] = {1}; //If you paired with OOB, both devices need to use the same tk + esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); + break; + } + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + BLUFI_TRACE_API("Local identity root"); + break; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + BLUFI_TRACE_API("Local encryption root"); + break; + case ESP_GAP_BLE_NC_REQ_EVT: + /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. + show the passkey number to the user to confirm it with the number displayed by peer device. */ + esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); + BLUFI_TRACE_WARNING("Numeric Comparison request, passkey %" PRIu32, param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should send the security response with negative(false) accept value*/ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer device. + BLUFI_TRACE_WARNING("Passkey notify, passkey %06" PRIu32, param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_KEY_EVT: + //shows the ble key info share with peer device to the user. + BLUFI_TRACE_API("Key exchanged, key_type %s", esp_key_type_to_str(param->ble_security.ble_key.key_type)); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: { + esp_bd_addr_t bd_addr; + memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t)); + BLUFI_TRACE_API("Authentication complete, addr_type %u, addr "ESP_BD_ADDR_STR"", + param->ble_security.auth_cmpl.addr_type, ESP_BD_ADDR_HEX(bd_addr)); + if(!param->ble_security.auth_cmpl.success) { + BLUFI_TRACE_WARNING("Pairing failed, reason 0x%x",param->ble_security.auth_cmpl.fail_reason); + } else { + BLUFI_TRACE_WARNING("Pairing successfully, auth_mode %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode)); + } + break; + } + case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: { + BLUFI_TRACE_DEBUG("Bond device remove, status %d, device "ESP_BD_ADDR_STR"", + param->remove_bond_dev_cmpl.status, ESP_BD_ADDR_HEX(param->remove_bond_dev_cmpl.bd_addr)); + break; + } + case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: + if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS){ + BLUFI_TRACE_WARNING("Local privacy config failed, status %x", param->local_privacy_cmpl.status); + } + break; +#endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE default: break; } @@ -251,10 +395,16 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) break; case BTA_GATTS_CREATE_EVT: blufi_env.handle_srvc = p_data->create.service_id; - + #if CONFIG_BT_BLUFI_BLE_SMP_ENABLE + BLUFI_TRACE_WARNING("BLE SMP support in BLUFI is ENABLED!"); + #endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE //add the first blufi characteristic --> write characteristic BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e, - (GATT_PERM_WRITE), + #if CONFIG_BT_BLUFI_BLE_SMP_ENABLE + GATT_PERM_WRITE_ENC_MITM, + #else + GATT_PERM_WRITE, + #endif (GATT_CHAR_PROP_BIT_WRITE), NULL, NULL); break; @@ -398,6 +548,16 @@ void esp_blufi_adv_stop(void) esp_ble_gap_stop_advertising(); } + +esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda) +{ + #ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE + return esp_ble_set_encryption(remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); + #else + return ESP_ERR_INVALID_STATE; + #endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE +} + void esp_blufi_send_encap(void *arg) { struct blufi_hdr *hdr = (struct blufi_hdr *)arg; diff --git a/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h b/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h index 8dc9a674ba8a..96d97591df96 100644 --- a/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h +++ b/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -90,6 +90,22 @@ void esp_blufi_adv_start_with_name(const char *name); void esp_blufi_send_encap(void *arg); +/* + * @brief Initiate BLE security request with the connected peer device. + * + * This function triggers the BLE Security Manager Protocol (SMP) procedure + * to establish a secure, encrypted connection with the specified remote device. + * It should be called after a BLE connection is established. + * + * @param[in] remote_bda Bluetooth device address of the connected peer. + * + * @return + * - ESP_OK: Security request initiated successfully + * - ESP_FAIL: Security request failed + * - ESP_ERR_INVALID_STATE: BluFi BLE SMP is not enabled + */ +esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda); + #ifdef CONFIG_BT_NIMBLE_ENABLED /** * @brief Handle gap event for BluFi. diff --git a/components/bt/common/include/bt_common.h b/components/bt/common/include/bt_common.h index d8fb107878ea..f687e3afe7a3 100644 --- a/components/bt/common/include/bt_common.h +++ b/components/bt/common/include/bt_common.h @@ -141,7 +141,9 @@ #define LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL #endif +#ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif #define BT_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_INITIAL_TRACE_LEVEL, LOG_LOCAL_LEVEL_MAPPING) >= BT_TRACE_LEVEL_##LEVEL) diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index c52de7cf2be1..c3d7df55e0ba 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -573,7 +573,7 @@ config BT_LE_LL_PEER_SCA config BT_LE_MAX_CONNECTIONS int "Maximum number of concurrent connections" depends on !BT_NIMBLE_ENABLED - range 1 35 + range 1 70 default 3 help Defines maximum number of concurrent BLE connections. For ESP32, user diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index 3f8f0a37d7d9..e6c19f0e4574 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -1636,11 +1636,13 @@ if BLE_MESH Enable support for Lighting server models. config BLE_MESH_MBT_CLI - bool "BLOB Transfer Client model" + bool "BLOB Transfer Client model(Deprecated)" depends on BLE_MESH_V11_SUPPORT default n help Enable support for BLOB Transfer Client model. + Warn: This version of the Mesh Binary Large Object Transfer Model will be deprecated, + and a new version will be released in the future. if BLE_MESH_MBT_CLI @@ -1655,11 +1657,259 @@ if BLE_MESH endif # BLE_MESH_MBT_CLI config BLE_MESH_MBT_SRV - bool "BLOB Transfer Server model" + bool "BLOB Transfer Server model(Deprecated)" depends on BLE_MESH_V11_SUPPORT default n help Enable support for BLOB Transfer Server model. + Warn: This version of the Mesh Binary Large Object Transfer Model will be deprecated, + and a new version will be released in the future. + + menu "Binary Larger Object Transfer model" + + config BLE_MESH_BLOB_SRV + bool "Support for BLOB Transfer Server model" + depends on BLE_MESH_V11_SUPPORT + help + Enable the Binary Large Object (BLOB) Transfer Server model. + + if BLE_MESH_BLOB_SRV + + config BLE_MESH_BLOB_SRV_PULL_REQ_COUNT + int "Number of chunks to request for each pull" + default 4 + range 1 16 + help + In Pull mode (Pull BLOB Transfer Mode), the BLOB Transfer Server + requests a fixed number of chunks from the Client. Use this option to + control the chunk count in the request. If the BLOB Transfer Server + is instantiated on a Low Power node, the pull request count will be + trimmed to not overflow the Friend queue. + + config BLE_MESH_BLOB_SIZE_MAX + int "Largest BLOB size in bytes" + default 524288 + range 1 3257617792 + help + The maximum object size a BLOB Transfer Server can receive. + + config BLE_MESH_BLOB_BLOCK_SIZE_MIN + int "Minimum block size" + default 4096 + range 64 1048576 # 2^6 - 2^20 + help + Minimum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + + config BLE_MESH_BLOB_BLOCK_SIZE_MAX + int "Maximum block size" + default 4096 + range BLE_MESH_BLOB_BLOCK_SIZE_MIN 1048576 + help + Maximum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + + config BLE_MESH_BLOB_REPORT_TIMEOUT + int "Partial Block Report interval in Pull mode" + default 10 + range 1 31 + help + The timer value that Pull BLOB Transfer Server uses to report missed chunks. + + config BLE_MESH_RX_BLOB_CHUNK_SIZE + depends on !BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + int "BLOB Server chunk size" + default 8 + range 8 377 + help + Set the chunk size for the BLOB Server. + The actual maximum chunk size depends on how many segments are + possible and will be clamped to the max possible if set above. + see also: BLE_MESH_RX_SEG_MAX, + and the maximum SDU a node can receive. + + endif # BLE_MESH_BLOB_SRV + + config BLE_MESH_BLOB_CLI + bool "Support for BLOB Transfer Client model" + depends on BLE_MESH_V11_SUPPORT + help + Enable the Binary Large Object (BLOB) Transfer Client model. + + if BLE_MESH_BLOB_CLI + + config BLE_MESH_BLOB_CLI_BLOCK_RETRIES + int "Number of retries per block" + default 5 + help + Controls the number of times the client will attempt to resend missing + chunks to the BLOB receivers for every block. + + config BLE_MESH_TX_BLOB_CHUNK_SIZE + depends on !BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + int "BLOB Client chunk size" + default 8 + range 1 377 + help + Set the chunk size for the BLOB Client. + The actual maximum chunk size depends on how many segments are + possible and will be clamped to the max possible if set above. + see also: BLE_MESH_TX_SEG_MAX, + and the maximum SDU a node can receive. + + config BLE_MESH_TX_BLOB_CHUNK_SEND_INTERVAL + int "BLOB Client chunk send interval" + default 0 + range 0 2147483647 + help + Set the interval in milliseconds in which chunks are sent during the BLOB transfer. + Note: Without a delay between each sent chunk, the network might become too busy with the + BLOB transfer for other communications to succeed. + Note: Timing restrictions, like the timeout base, should be considered or changed + accordingly when setting this interval. Otherwise, the interval might be too big for the + timeout settings and cause timeouts. + + endif # BLE_MESH_BLOB_CLI + + menu "BLOB models common configuration" + visible if BLE_MESH_BLOB_SRV || BLE_MESH_BLOB_CLI + + config BLE_MESH_BLOB_CHUNK_COUNT_MAX + int "Maximum chunk count per block" + default 256 + range 1 2992 + help + A BLOB transfer contains several blocks. Each block is made up of + several chunks. This option controls the maximum chunk count per + block. + + config BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + bool "Align chunk size to max segmented message size" + default y + + endmenu #BLOB models common configuration + + endmenu # Binary Larger Object Transfer model + + menu "Device Firmware Update model" + + config BLE_MESH_DFU_SRV + bool "Support for Firmware Update Server model" + depends on BLE_MESH_BLOB_SRV + help + Enable the Firmware Update Server model. + + config BLE_MESH_DFU_CLI + bool "Support for Firmware Update Client model" + depends on BLE_MESH_BLOB_CLI + help + Enable the Firmware Update Client model. + + menu "Firmware Update model configuration" + visible if BLE_MESH_DFU_SRV || BLE_MESH_DFU_CLI + + config BLE_MESH_DFU_FWID_MAXLEN + int "DFU FWID max length" + default 16 + range 0 106 + help + This value defines the maximum length of an image's firmware ID. + + config BLE_MESH_DFU_METADATA_MAXLEN + int "DFU metadata max length" + default 32 + range 18 255 if BLE_MESH_DFU_METADATA + range 0 255 + help + This value defines the maximum length of an image's metadata. + + config BLE_MESH_DFU_METADATA + bool "Support for the default metadata format" + help + This option adds a set of functions that can be used to encode and decode a firmware + metadata using the format defined in the Bluetooth mesh DFU subsystem. + + config BLE_MESH_DFU_URI_MAXLEN + int "DFU URI max length" + default 32 + range 0 255 + help + This value defines the maximum length of an image's URI, not including + a string terminator. + + endmenu #Firmware Update model configuration + + config BLE_MESH_DFU_SLOTS + bool "Firmware image slot manager" + default y if BLE_MESH_DFU_CLI + help + Enable the DFU image slot manager, for managing firmware distribution slots + for the Firmware Update Client model. + + if BLE_MESH_DFU_SLOTS + + config BLE_MESH_DFU_SLOT_CNT + int "Number of firmware image slots" + default 1 + range 1 32767 + help + This value defines the number of firmware slots the DFU image slot manager + can keep simultaneously. + + endif #BLE_MESH_DFU_SLOTS + + config BLE_MESH_DFD_CLI + bool "Support for Device Distribution Client model" + help + Enable the Device Distribution Client model + + config BLE_MESH_DFD_SRV + bool "Support for Firmware Distribution Server model" + depends on BLE_MESH_BLOB_SRV + depends on BLE_MESH_DFU_CLI + help + Enable the Firmware Distribution Server model. + + if BLE_MESH_DFD_SRV + + config BLE_MESH_DFD_SRV_SLOT_MAX_SIZE + int "Largest DFU image that can be stored" + default BLE_MESH_BLOB_SIZE_MAX + range 0 BLE_MESH_BLOB_SIZE_MAX + help + This value defines the largest DFU image a single slot can store. + + config BLE_MESH_DFD_SRV_SLOT_SPACE + int "Total DFU image storage space" + default BLE_MESH_DFD_SRV_SLOT_MAX_SIZE + range 0 4294967295 + help + This value defines the total storage space dedicated to storing DFU + images on the Firmware Distribution Server. + + config BLE_MESH_DFD_SRV_TARGETS_MAX + int "Maximum Target node count" + default 8 + range 1 65535 + help + This value defines the maximum number of Target nodes the Firmware + Distribution Server can target simultaneously. + + config BLE_MESH_DFD_SRV_OOB_UPLOAD + bool "Support for DFU image OOB upload" + help + This enables support for OOB upload of firmware images for + distribution. This makes several callbacks and use of the init + macro BLE_MESH_DFD_SRV_INIT_OOB mandatory. See the API documentation + for bt_mesh_dfd_srv_cb for details about the mandatory callbacks. + + endif #BLE_MESH_DFD_SRV + + endmenu # Device Firmware Update model endmenu #Support for BLE Mesh Client/Server models diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h index 83d7e627606b..cdada119b44d 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h @@ -97,6 +97,9 @@ typedef union { #if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BT_NIMBLE_ENABLED /** * @brief Event parameters of ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT + * @note The execution environment of this event is different + * from other BLE Mesh events, as it runs in the NimBLE Host's + * execution environment. */ struct ble_mesh_nimble_gap_event_evt_param { struct ble_gap_event event; /*!< GAP event parameters for NimBLE Host */ diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 7d4b0ed17088..01ade026682c 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -1982,9 +1982,14 @@ typedef union { #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -#define ESP_BLE_MESH_MODEL_ID_MBT_SRV 0x1400 -#define ESP_BLE_MESH_MODEL_ID_MBT_CLI 0x1401 - +#define ESP_BLE_MESH_MODEL_ID_MBT_SRV 0x14fe +#define ESP_BLE_MESH_MODEL_ID_MBT_CLI 0x14ff +#define ESP_BLE_MESH_MODEL_ID_BLOB_SRV 0x1400 +#define ESP_BLE_MESH_MODEL_ID_BLOB_CLI 0x1401 +#define ESP_BLE_MESH_MODEL_ID_DFU_SRV 0x1402 +#define ESP_BLE_MESH_MODEL_ID_DFU_CLI 0x1403 +#define ESP_BLE_MESH_MODEL_ID_DFD_SRV 0x1404 +#define ESP_BLE_MESH_MODEL_ID_DFD_CLI 0x1405 /** * esp_ble_mesh_opcode_config_client_get_t belongs to esp_ble_mesh_opcode_t, this typedef is only * used to locate the opcodes used by esp_ble_mesh_config_client_get_state. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c index 27699600293f..ac397aeb18da 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c @@ -14,6 +14,8 @@ #include "esp_ble_mesh_ble_api.h" #if (CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50) +static inline void btc_ble_mesh_ble_cb_to_app(esp_ble_mesh_ble_cb_event_t event, + esp_ble_mesh_ble_cb_param_t *param); static void btc_ble_mesh_ble_copy_req_data(btc_msg_t *msg, void *p_dst, void *p_src) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN @@ -99,7 +101,7 @@ void bt_mesh_ble_nimble_evt_to_btc(struct ble_gap_event *event, void *arg) memcpy(¶m.nimble_gap_evt.event, event, sizeof(struct ble_gap_event)); param.nimble_gap_evt.arg = arg; - btc_ble_mesh_ble_callback(¶m, ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT); + btc_ble_mesh_ble_cb_to_app(ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT, ¶m); } #endif /* CONFIG_BT_NIMBLE_ENABLED && CONFIG_BLE_MESH_USE_BLE_50 */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 72d1774d5e15..49ae1d5dda1a 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1410,6 +1410,31 @@ typedef bt_mesh_client_user_data_t bt_mesh_mbt_client_t; extern const struct bt_mesh_model_op bt_mesh_mbt_cli_op[]; extern const struct bt_mesh_model_cb bt_mesh_mbt_cli_cb; #endif /* CONFIG_BLE_MESH_MBT_CLI */ +#if CONFIG_BLE_MESH_BLOB_SRV +extern const struct bt_mesh_model_op _bt_mesh_blob_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb; +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ +#if CONFIG_BLE_MESH_BLOB_CLI +typedef bt_mesh_client_user_data_t bt_mesh_blob_client_t; +extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb; +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#if CONFIG_BLE_MESH_DFU_SRV +extern const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI +extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFD_SRV +extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +extern const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb; +#endif /* CONFIG_BLE_MESH_DFD_CLI */ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) { @@ -2205,9 +2230,9 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) case BLE_MESH_MODEL_ID_MBT_CLI: model->op = (esp_ble_mesh_model_op_t *)bt_mesh_mbt_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_mbt_cli_cb; - bt_mesh_mbt_client_t *cli = (bt_mesh_mbt_client_t *)model->user_data; - if (cli) { - cli->publish_status = btc_ble_mesh_mbt_client_publish_callback; + bt_mesh_mbt_client_t *mbt_cli = (bt_mesh_mbt_client_t *)model->user_data; + if (mbt_cli) { + mbt_cli->publish_status = btc_ble_mesh_mbt_client_publish_callback; } break; #endif /* CONFIG_BLE_MESH_MBT_CLI */ @@ -2220,6 +2245,61 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) } break; #endif /* CONFIG_BLE_MESH_MBT_SRV */ +#if CONFIG_BLE_MESH_BLOB_CLI + case BLE_MESH_MODEL_ID_BLOB_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_cli_cb; + bt_mesh_blob_client_t *blob_cli = (bt_mesh_blob_client_t *)model->user_data; + if (blob_cli) { + /* TBD: do we need publish callback for Blob Transfer Client model? */ + } + break; +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#if CONFIG_BLE_MESH_BLOB_SRV + case BLE_MESH_MODEL_ID_BLOB_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI + case BLE_MESH_MODEL_ID_DFU_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_cli_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFU_SRV + case BLE_MESH_MODEL_ID_DFU_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_SRV + case BLE_MESH_MODEL_ID_DFD_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI + case BLE_MESH_MODEL_ID_DFD_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_cli_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ default: goto set_vnd_op; } diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h index 73b00db41ff6..66507a1bb238 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h @@ -17,6 +17,45 @@ extern "C" { #endif +static inline void btc_ble_mesh_msg_ctx_copy(struct bt_mesh_msg_ctx *dst, + const struct bt_mesh_msg_ctx *src, + bool use_dev_key) +{ + if (dst == NULL || + src == NULL) { + return; + } + + dst->net_idx = src->net_idx; + dst->app_idx = use_dev_key ? BLE_MESH_KEY_DEV : src->app_idx; + dst->addr = src->addr; + dst->send_szmic = src->send_szmic; + dst->send_ttl = src->send_ttl; + dst->send_cred = src->send_cred; + dst->send_tag = src->send_tag; + if (src->enh.adv_cfg_used) { + dst->enh.adv_cfg_used = src->enh.adv_cfg_used; + dst->enh.adv_cfg.adv_cnt = src->enh.adv_cfg.adv_cnt; + dst->enh.adv_cfg.adv_itvl = src->enh.adv_cfg.adv_itvl; + dst->enh.adv_cfg.channel_map = src->enh.adv_cfg.channel_map; + } +#if CONFIG_BLE_MESH_EXT_ADV + if (src->enh.ext_adv_cfg_used) { + dst->enh.ext_adv_cfg_used = src->enh.ext_adv_cfg_used; + dst->enh.ext_adv_cfg.primary_phy = src->enh.ext_adv_cfg.primary_phy; + dst->enh.ext_adv_cfg.secondary_phy = src->enh.ext_adv_cfg.secondary_phy; + dst->enh.ext_adv_cfg.include_tx_power = src->enh.ext_adv_cfg.include_tx_power; + dst->enh.ext_adv_cfg.tx_power = src->enh.ext_adv_cfg.tx_power; + } +#if CONFIG_BLE_MESH_LONG_PACKET + if (src->enh.long_pkt_cfg_used) { + dst->enh.long_pkt_cfg_used = src->enh.long_pkt_cfg_used; + dst->enh.long_pkt_cfg = src->enh.long_pkt_cfg; + } +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +} + static inline void btc_ble_mesh_set_client_common_param(esp_ble_mesh_client_common_param_t *input, bt_mesh_client_common_param_t *output, bool use_dev_key) @@ -24,35 +63,8 @@ static inline void btc_ble_mesh_set_client_common_param(esp_ble_mesh_client_comm if (input && output) { output->opcode = input->opcode; output->model = (struct bt_mesh_model *)input->model; - output->ctx.net_idx = input->ctx.net_idx; - output->ctx.app_idx = use_dev_key ? BLE_MESH_KEY_DEV : input->ctx.app_idx; - output->ctx.addr = input->ctx.addr; - output->ctx.send_szmic = input->ctx.send_szmic; - output->ctx.send_ttl = input->ctx.send_ttl; - output->ctx.send_cred = input->ctx.send_cred; - output->ctx.send_tag = input->ctx.send_tag; output->msg_timeout = input->msg_timeout; - if (input->ctx.enh.adv_cfg_used) { - output->ctx.enh.adv_cfg_used = input->ctx.enh.adv_cfg_used; - output->ctx.enh.adv_cfg.adv_cnt = input->ctx.enh.adv_cfg.adv_cnt; - output->ctx.enh.adv_cfg.adv_itvl = input->ctx.enh.adv_cfg.adv_itvl; - output->ctx.enh.adv_cfg.channel_map = input->ctx.enh.adv_cfg.channel_map; - } -#if CONFIG_BLE_MESH_EXT_ADV - if (input->ctx.enh.ext_adv_cfg_used) { - output->ctx.enh.ext_adv_cfg_used = input->ctx.enh.ext_adv_cfg_used; - output->ctx.enh.ext_adv_cfg.primary_phy = input->ctx.enh.ext_adv_cfg.primary_phy; - output->ctx.enh.ext_adv_cfg.secondary_phy = input->ctx.enh.ext_adv_cfg.secondary_phy; - output->ctx.enh.ext_adv_cfg.include_tx_power = input->ctx.enh.ext_adv_cfg.include_tx_power; - output->ctx.enh.ext_adv_cfg.tx_power = input->ctx.enh.ext_adv_cfg.tx_power; - } -#if CONFIG_BLE_MESH_LONG_PACKET - if (input->ctx.enh.long_pkt_cfg_used) { - output->ctx.enh.long_pkt_cfg_used = input->ctx.enh.long_pkt_cfg_used; - output->ctx.enh.long_pkt_cfg = input->ctx.enh.long_pkt_cfg; - } -#endif -#endif + btc_ble_mesh_msg_ctx_copy(&output->ctx, (const struct bt_mesh_msg_ctx *)&input->ctx, use_dev_key); } } diff --git a/components/bt/esp_ble_mesh/common/include/mesh/kernel.h b/components/bt/esp_ble_mesh/common/include/mesh/kernel.h index 95624cf736f2..a24772a47d17 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/kernel.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/kernel.h @@ -37,7 +37,7 @@ extern "C" { #endif #endif -#define BLE_MESH_ADV_TASK_STACK_SIZE 3072 +#define BLE_MESH_ADV_TASK_STACK_SIZE (3072) #define BLE_MESH_ADV_TASK_NAME "mesh_adv_task" #define BLE_MESH_ADV_TASK_PRIO (configMAX_PRIORITIES - 5) diff --git a/components/bt/esp_ble_mesh/common/include/mesh/timer.h b/components/bt/esp_ble_mesh/common/include/mesh/timer.h index e1296aa82062..30b400aee460 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/timer.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/timer.h @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,8 @@ struct k_work; */ typedef void (*k_work_handler_t)(struct k_work *work); +typedef int32_t k_timeout_t; + struct k_work { k_work_handler_t handler; int index; @@ -141,6 +143,65 @@ struct k_work { */ #define K_FOREVER (-1) +/** + * @brief Define for delayable work type. + * + * This macro maps the Zephyr delayable work type `k_work_delayable` + * to the ESP-IDF type `k_delayed_work`. + */ +#define k_work_delayable k_delayed_work + +/** + * @brief Reschedule a delayable work item. + * + * This macro maps to `k_delayed_work_submit`, which cancels + * any existing pending submission of the work item and reschedules + * it with the new timeout delay. + * + * @param work Pointer to delayable work item. + * @param delay Timeout delay value. + * @return See implementation of `k_delayed_work_submit`. + */ +#define k_work_reschedule k_delayed_work_submit + +/** + * @brief Schedule a delayable work item. + * + * This macro maps to `k_delayed_work_submit`, + * which schedules a work item to be processed + * after the specified timeout delay. If the work + * is already pending, the new delay is applied. + * + * @param work Pointer to delayable work item. + * @param delay Timeout delay value. + * @return See implementation of `k_delayed_work_submit`. + */ +#define k_work_schedule k_delayed_work_submit + +/** + * @brief Cancel a delayable work item. + * + * This macro maps to `k_delayed_work_cancel`, + * which cancels a pending work submission + * associated with a delayable work item. + * + * @param work Pointer to delayable work item. + * @return See implementation of `k_delayed_work_cancel`. + */ +#define k_work_cancel_delayable k_delayed_work_cancel + +/** + * @brief Initialize a delayable work item. + * + * This macro maps to `k_delayed_work_init`, + * which initializes a delayable work item with + * the provided handler function. + * + * @param work Pointer to delayable work item. + * @param handler Work item handler function. + */ +#define k_work_init_delayable k_delayed_work_init + /** * @brief Get system uptime (32-bit version). * @@ -160,6 +221,27 @@ struct k_delayed_work { struct k_work work; }; +#define _K_DELAYABLE_WORK_INITIALIZER(work_handler) { \ + .work = { \ + .handler = work_handler, \ + }, \ +} + +/** + * @brief Convert a work item to its containing delayable work structure. + * + * This function uses container_of to derive the address of the containing + * k_work_delayable structure from the address of the embedded k_work structure. + * + * @param work Pointer to the embedded k_work structure within a k_work_delayable. + * @return Pointer to the containing k_work_delayable structure. + */ +static inline struct k_work_delayable * +k_work_delayable_from_work(struct k_work *work) +{ + return CONTAINER_OF(work, struct k_work_delayable, work); +} + /** * @brief Submit a delayed work item to the system workqueue. * @@ -209,6 +291,21 @@ int k_delayed_work_submit_periodic(struct k_delayed_work *work, int32_t period); */ int32_t k_delayed_work_remaining_get(struct k_delayed_work *work); +/** + * @brief Check if a delayable work item is pending execution. + * + * This function checks whether a delayable work item has been scheduled + * and is waiting to be processed. It returns true if the work item is in + * pending state (waiting for timeout expiration or being in work queue). + * + * @param dwork Pointer to delayable work item. + * @return true if work is pending, false otherwise. + */ +static inline bool k_work_delayable_is_pending(struct k_work_delayable *dwork) +{ + return k_delayed_work_remaining_get(dwork); +} + /** * @brief Submit a work item to the system workqueue. * @@ -267,10 +364,45 @@ int k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler); * @return Current uptime. */ int64_t k_uptime_get(void); +int64_t k_uptime_delta(int64_t *reftime); void bt_mesh_timer_init(void); void bt_mesh_timer_deinit(void); +/** + * @brief Initialize a statically-defined work item. + * + * This macro can be used to initialize a statically-defined workqueue work + * item, prior to its first use. For example, + * + * @code static K_WORK_DEFINE(, ); @endcode + * + * @param work Symbol name for work item object + * @param work_handler Function to invoke each time work item is processed. + */ +#define K_WORK_DEFINE(work, work_handler) \ + struct k_work work = _K_WORK_INITIALIZER(work_handler) + +/** + * @brief Initialize a statically-defined delayable work item. + * + * This macro can be used to initialize a statically-defined delayable + * work item, prior to its first use. For example, + * + * @code static K_WORK_DELAYABLE_DEFINE(, ); @endcode + * + * Note that if the runtime dependencies support initialization with + * k_work_init_delayable() using that will eliminate the initialized + * object in ROM that is produced by this macro and copied in at + * system startup. + * + * @param work Symbol name for delayable work item object + * @param work_handler Function to invoke each time work item is processed. + */ +#define K_WORK_DELAYABLE_DEFINE(work, work_handler) \ + struct k_delayed_work work \ + = _K_DELAYABLE_WORK_INITIALIZER(work_handler) + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/common/include/mesh/utils.h b/components/bt/esp_ble_mesh/common/include/mesh/utils.h index 967fed2e0c8c..4ef522ee3225 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/utils.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/utils.h @@ -15,6 +15,8 @@ #define _BLE_MESH_UTILS_H_ #include +#include +#include #include "esp_bit_defs.h" #include "mesh/types.h" #include "utils_loops.h" @@ -94,6 +96,81 @@ extern "C" { #define WB_DN(x) ROUND_DOWN(x, sizeof(void *)) #endif +/** + * @brief Whether @p ptr is an element of @p array + * + * This macro can be seen as a slightly stricter version of @ref PART_OF_ARRAY + * in that it also ensures that @p ptr is aligned to an array-element boundary + * of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr the pointer to check + * + * @return 1 if @p ptr is part of @p array, 0 otherwise + */ +#define IS_ARRAY_ELEMENT(array, ptr) \ + ((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \ + POINTER_TO_UINT(ptr) < POINTER_TO_UINT(&(array)[ARRAY_SIZE(array)]) && \ + (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) % sizeof((array)[0]) == 0) + +/** + * @brief Index of @p ptr within @p array + * + * With `CONFIG_ASSERT=y`, this macro will trigger a runtime assertion + * when @p ptr does not fall into the range of @p array or when @p ptr + * is not aligned to an array-element boundary of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr pointer to an element of @p array + * + * @return the array index of @p ptr within @p array, on success + */ +#define ARRAY_INDEX(array, ptr) \ + ({ \ + __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(array, ptr)); \ + (__typeof__((array)[0]) *)(ptr) - (array); \ + }) + + +/** + * @brief Divide and round up. + * + * Example: + * @code{.c} + * DIV_ROUND_UP(1, 2); // 1 + * DIV_ROUND_UP(3, 2); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded up. + */ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +/** + * @brief Divide and round to the nearest integer. + * + * Example: + * @code{.c} + * DIV_ROUND_CLOSEST(5, 2); // 3 + * DIV_ROUND_CLOSEST(5, -2); // -3 + * DIV_ROUND_CLOSEST(5, 3); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded to the nearest integer. + */ +#define DIV_ROUND_CLOSEST(n, d) \ + ((((n) < 0) ^ ((d) < 0)) ? ((n) - ((d) / 2)) / (d) : \ + ((n) + ((d) / 2)) / (d)) + #ifndef ceiling_fraction #define ceiling_fraction(numerator, divider) \ (((numerator) + ((divider) - 1)) / (divider)) @@ -125,6 +202,21 @@ extern "C" { #define BIT(n) (1UL << (n)) #endif +/** + * @brief Set or clear a bit depending on a boolean value + * + * The argument @p var is a variable whose value is written to as a + * side effect. + * + * @param var Variable to be altered + * @param bit Bit number + * @param set if 0, clears @p bit in @p var; any other value sets @p bit + */ +#ifndef WRITE_BIT +#define WRITE_BIT(var, bit, set) \ + ((var) = (set) ? ((var) | BIT(bit)) : ((var) & ~BIT(bit))) +#endif + #ifndef BIT_MASK #define BIT_MASK(n) (BIT(n) - 1) #endif @@ -219,6 +311,20 @@ const char *bt_hex(const void *buf, size_t len); void mem_rcopy(uint8_t *dst, uint8_t const *src, uint16_t len); +/** + * @brief Checks if a value is within range. + * + * @note @p val is evaluated twice. + * + * @param val Value to be checked. + * @param min Lower bound (inclusive). + * @param max Upper bound (inclusive). + * + * @retval true If value is within range + * @retval false If the value is not within range + */ +#define IN_RANGE(val, min, max) ((val) >= (min) && (val) <= (max)) + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/common/timer.c b/components/bt/esp_ble_mesh/common/timer.c index 0d65bd3a106e..248480e70bbd 100644 --- a/components/bt/esp_ble_mesh/common/timer.c +++ b/components/bt/esp_ble_mesh/common/timer.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2016 Intel Corporation * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,6 +43,28 @@ uint32_t k_uptime_get_32(void) return (uint32_t)(esp_timer_get_time() / 1000); } +/** + * @brief Get elapsed time. + * + * This routine computes the elapsed time between the current system uptime + * and an earlier reference time, in milliseconds. + * + * @param reftime Pointer to a reference time, which is updated to the current + * uptime upon return. + * + * @return Elapsed time. + */ +int64_t k_uptime_delta(int64_t *reftime) +{ + int64_t uptime, delta; + + uptime = k_uptime_get(); + delta = uptime - *reftime; + *reftime = uptime; + + return delta; +} + void bt_mesh_timer_init(void) { bm_alarm_hash_map = hash_map_new(BLE_MESH_ALARM_HASH_MAP_SIZE, diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 86d80139d00c..2f70e64eeae7 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -25,7 +25,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define BLE_MESH_SDU_MAX_LEN 384 @@ -37,7 +37,7 @@ extern const struct bt_mesh_comp *comp_0; static uint16_t dev_primary_addr; -static int model_send(struct bt_mesh_model *model, +static int model_send(const struct bt_mesh_model *model, struct bt_mesh_net_tx *tx, bool implicit_bind, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data); @@ -50,6 +50,8 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, { int i, j; + BT_DBG("ModelForeach"); + if (comp_0 == NULL) { BT_ERR("Invalid device composition"); return; @@ -58,15 +60,21 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; + BT_DBG("Element %u", i); + for (j = 0; j < elem->model_count; j++) { struct bt_mesh_model *model = &elem->models[j]; + BT_DBG("ID 0x%04x", model->id); + func(model, elem, false, i == 0, user_data); } for (j = 0; j < elem->vnd_model_count; j++) { struct bt_mesh_model *model = &elem->vnd_models[j]; + BT_DBG("ID 0x%04x CID 0x%04x", model->vnd.id, model->vnd.company); + func(model, elem, true, i == 0, user_data); } } @@ -76,6 +84,8 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) { int period = 0; + BT_DBG("ModelPubPeriodGet"); + if (!mod->pub) { BT_ERR("Model has no publication support"); return 0; @@ -103,6 +113,9 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) return 0; } + BT_DBG("Period %ld FastPeriod %u PeriodDiv %u", + period, mod->pub->fast_period, mod->pub->period_div); + if (mod->pub->fast_period) { return period >> mod->pub->period_div; } @@ -115,19 +128,22 @@ static int32_t next_period(struct bt_mesh_model *mod) struct bt_mesh_model_pub *pub = mod->pub; uint32_t elapsed = 0U, period = 0U; + BT_DBG("NextPeriod"); + if (!pub) { BT_ERR("Model has no publication support"); - return -ENOTSUP; + return 0; } period = bt_mesh_model_pub_period_get(mod); if (!period) { + BT_DBG("PeriodZero"); return 0; } elapsed = k_uptime_get_32() - pub->period_start; - BT_INFO("Publishing took %ums", elapsed); + BT_INFO("Elapsed %u Period %u", elapsed, period); if (elapsed >= period) { BT_WARN("Publication sending took longer than the period"); @@ -143,7 +159,7 @@ static void publish_sent(int err, void *user_data) struct bt_mesh_model *mod = user_data; int32_t delay = 0; - BT_DBG("err %d", err); + BT_DBG("PublishSent, Err %d", err); if (!mod->pub) { BT_ERR("Model has no publication support"); @@ -156,8 +172,9 @@ static void publish_sent(int err, void *user_data) delay = next_period(mod); } + BT_DBG("PubCount %u PubDelay %ld", mod->pub->count, delay); + if (delay) { - BT_INFO("Publishing next time in %dms", delay); k_delayed_work_submit(&mod->pub->timer, delay); } } @@ -167,6 +184,8 @@ static void publish_start(uint16_t duration, int err, void *user_data) struct bt_mesh_model *mod = user_data; struct bt_mesh_model_pub *pub = mod->pub; + BT_DBG("PublishStart, Err %d", err); + if (err) { BT_ERR("Failed to publish: err %d", err); return; @@ -196,6 +215,8 @@ static int publish_retransmit(struct bt_mesh_model *mod) }; int err = 0; + BT_DBG("PublishRetransmit"); + if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; @@ -224,9 +245,14 @@ static int publish_retransmit(struct bt_mesh_model *mod) ctx.send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + ctx.net_idx, ctx.app_idx, ctx.addr); + BT_DBG("TTL %u SendCred %u SendRel %u PubCount %u", + ctx.send_ttl, ctx.send_cred, pub->send_rel, pub->count); + #if CONFIG_BLE_MESH_DF_SRV bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { @@ -246,8 +272,11 @@ static int publish_retransmit(struct bt_mesh_model *mod) static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub) { + BT_DBG("PublishRetransmitEnd, Err %d", err); + /* Cancel all retransmits for this publish attempt */ pub->count = 0U; + /* Make sure the publish timer gets reset */ publish_sent(err, pub->mod); } @@ -261,7 +290,8 @@ static void mod_publish(struct k_work *work) int err = 0; period_ms = bt_mesh_model_pub_period_get(pub->mod); - BT_INFO("Publish period %u ms", period_ms); + + BT_INFO("ModPublish, Period %u", period_ms); if (pub->count) { err = publish_retransmit(pub->mod); @@ -289,6 +319,7 @@ static void mod_publish(struct k_work *work) if (pub->update && pub->update(pub->mod)) { /* Cancel this publish attempt. */ BT_ERR("Update failed, skipping publish (err %d)", err); + pub->period_start = k_uptime_get_32(); publish_retransmit_end(err, pub); return; @@ -300,8 +331,10 @@ static void mod_publish(struct k_work *work) } } -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) { + BT_DBG("ModelElem, ElemIdx %u", mod->elem_idx); + return &comp_0->elem[mod->elem_idx]; } @@ -309,6 +342,8 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ { struct bt_mesh_elem *elem = NULL; + BT_DBG("ModelGet, ElemIdx %u ModIdx %u Vnd %u", elem_idx, mod_idx, vnd); + if (!comp_0) { BT_ERR("comp_0 not initialized"); return NULL; @@ -344,6 +379,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int *err = user_data; int i; + BT_DBG("ModInit, Vnd %u Primary %u", vnd, primary); + if (!user_data) { BT_ERR("Invalid model init user data"); return; @@ -373,6 +410,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->model_idx = mod - elem->models; } + BT_DBG("ElemIdx %u ModelIdx %u", mod->elem_idx, mod->model_idx); + if (vnd) { return; } @@ -386,6 +425,8 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) { int err = 0; + BT_DBG("CompRegister, ElemCount %u", comp->elem_count); + /* There must be at least one element */ if (!comp->elem_count) { return -EINVAL; @@ -405,6 +446,8 @@ static void mod_deinit(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int *err = user_data; int i; + BT_DBG("ModDeinit, Vnd %u Primary %u", vnd, primary); + if (!user_data) { BT_ERR("Invalid model deinit user data"); return; @@ -443,6 +486,8 @@ int bt_mesh_comp_deregister(void) { int err = 0; + BT_DBG("CompDeregister"); + if (comp_0 == NULL) { return -EINVAL; } @@ -461,25 +506,29 @@ void bt_mesh_comp_provision(uint16_t addr) dev_primary_addr = addr; - BT_INFO("Primary address 0x%04x, element count %u", addr, comp_0->elem_count); + BT_INFO("CompProvision, PrimaryAddr 0x%04x ElemCount %u", addr, comp_0->elem_count); for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; elem->addr = addr++; - BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", + BT_DBG("ElemAddr 0x%04x ModCount %u VndModCount %u", elem->addr, elem->model_count, elem->vnd_model_count); } } void bt_mesh_comp_unprovision(void) { + BT_DBG("CompUnprovision"); + dev_primary_addr = BLE_MESH_ADDR_UNASSIGNED; } uint16_t bt_mesh_primary_addr(void) { + BT_DBG("PrimaryAddr 0x%04x", dev_primary_addr); + return dev_primary_addr; } @@ -487,12 +536,16 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, uint16_t addr) { int i; + BT_DBG("ModelFindGroup, Addr 0x%04x", addr); + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { if (mod->groups[i] == addr) { + BT_DBG("ModGroupFound"); return &mod->groups[i]; } } + BT_DBG("ModGroupNotFound"); return NULL; } @@ -503,6 +556,8 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, uint16_t *match = NULL; int i; + BT_DBG("ElemFindGroup, Addr 0x%04x", group_addr); + for (i = 0; i < elem->model_count; i++) { model = &elem->models[i]; @@ -528,6 +583,8 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) { uint16_t index = 0U; + BT_DBG("ElemFind, Addr 0x%04x", addr); + if (BLE_MESH_ADDR_IS_UNICAST(addr)) { index = (addr - comp_0->elem[0].addr); if (index < comp_0->elem_count) { @@ -548,15 +605,38 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) return NULL; } +bool bt_mesh_has_addr(uint16_t addr) +{ + uint16_t index; + + if (BLE_MESH_ADDR_IS_UNICAST(addr)) { + return bt_mesh_elem_find(addr) != NULL; + } + + for (index = 0; index < comp_0->elem_count; index++) { + struct bt_mesh_elem *elem = &comp_0->elem[index]; + + if (bt_mesh_elem_find_group(elem, addr)) { + return true; + } + } + + return false; +} + uint8_t bt_mesh_elem_count(void) { + BT_DBG("ElemCount %u", comp_0->elem_count); + return comp_0->elem_count; } -static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) +static bool model_has_key(const struct bt_mesh_model *mod, uint16_t key) { int i; + BT_DBG("ModelHasKey, AppIdx 0x%04x", key); + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { if (mod->keys[i] == key) { return true; @@ -570,6 +650,8 @@ static bool model_has_dst(struct bt_mesh_model *model, struct bt_mesh_subnet *sub, uint16_t dst) { + BT_DBG("ModelHasDst, Dst 0x%04x", dst); + if (BLE_MESH_ADDR_IS_UNICAST(dst)) { return (comp_0->elem[model->elem_idx].addr == dst); } @@ -588,6 +670,8 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, { int i; + BT_DBG("FindOp, ModelCount %u Opcode 0x%08lx", model_count, opcode); + for (i = 0; i < model_count; i++) { const struct bt_mesh_model_op *op; @@ -606,6 +690,8 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) { + BT_DBG("GetOpCode, PullBuf %u", pull_buf); + switch (buf->data[0] >> 6) { case 0x00: case 0x01: @@ -635,7 +721,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_bu if (pull_buf) { *opcode = net_buf_simple_pull_u8(buf) << 16; /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * little-endian in the mesh spec and using BLE_MESH_MODEL_OP_3 * will declare the opcode in this way. */ *opcode |= net_buf_simple_pull_le16(buf); @@ -651,6 +737,8 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_bu int bt_mesh_get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) { + BT_DBG("GetOpCode"); + if (buf == NULL || buf->len == 0 || opcode == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -661,6 +749,8 @@ int bt_mesh_get_opcode(struct net_buf_simple *buf, bool bt_mesh_fixed_group_match(uint16_t addr) { + BT_DBG("FixedGroupMatch, Addr 0x%04x", addr); + /* Check for fixed group addresses */ switch (addr) { case BLE_MESH_ADDR_ALL_NODES: @@ -682,12 +772,14 @@ bool bt_mesh_fixed_direct_match(struct bt_mesh_subnet *sub, uint16_t addr) * shall be processed by the primary element of all nodes that * have directed forwarding functionality enabled. */ + BT_DBG("FixedDirectMatch, Addr 0x%04x", addr); + #if CONFIG_BLE_MESH_DF_SRV if (addr == BLE_MESH_ADDR_DIRECTS && sub && sub->directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_ENABLED) { return true; } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return false; } @@ -700,16 +792,17 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) uint8_t count = 0U; int i; - BT_INFO("recv, app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, - rx->ctx.addr, rx->ctx.recv_dst); - BT_INFO("recv, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_INFO("ModelRecv"); + BT_INFO("AppIdx 0x%04x Src 0x%04x Dst 0x%04x", + rx->ctx.app_idx, rx->ctx.addr, rx->ctx.recv_dst); + BT_INFO("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (get_opcode(buf, &opcode, true) < 0) { BT_WARN("Unable to decode OpCode"); return; } - BT_DBG("OpCode 0x%08x", opcode); + BT_DBG("OpCode 0x%08lx RecvCred %u", opcode, rx->ctx.recv_cred); for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; @@ -734,10 +827,12 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (!model_has_key(model, rx->ctx.app_idx)) { + BT_DBG("ModelNotHasKey"); continue; } if (!model_has_dst(model, rx->sub, rx->ctx.recv_dst)) { + BT_DBG("ModelNotHasDst"); continue; } @@ -781,6 +876,8 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) { + BT_DBG("ModelMsgInit, OpCode 0x%08lx", opcode); + net_buf_simple_init(msg, 0); switch (BLE_MESH_MODEL_OP_LEN(opcode)) { @@ -793,7 +890,7 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) case 3: net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * little-endian in the mesh spec and using BLE_MESH_MODEL_OP_3 * will declare the opcode in this way. */ net_buf_simple_add_le16(msg, opcode & 0xffff); @@ -806,6 +903,8 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) static bool ready_to_send(uint16_t dst) { + BT_DBG("IsReadyToSend, Dst 0x%04x", dst); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { return true; } @@ -813,7 +912,7 @@ static bool ready_to_send(uint16_t dst) if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { if (bt_mesh_provisioner_check_msg_dst(dst) == false && bt_mesh_elem_find(dst) == false) { - BT_ERR("Failed to find DST 0x%04x", dst); + BT_ERR("Failed to find Dst 0x%04x", dst); return false; } return true; @@ -825,15 +924,19 @@ static bool ready_to_send(uint16_t dst) #if !CONFIG_BLE_MESH_V11_SUPPORT static bool use_friend_cred(uint16_t net_idx, uint16_t dst) { + BT_DBG("IsFrndCredUsed, NetIdx 0x%04x Dst 0x%04x", net_idx, dst); + /* Currently LPN only supports using NetKey in bt_mesh.sub[0] */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && net_idx == 0 && bt_mesh_lpn_match(dst)) { + BT_DBG("LPNMatch"); return true; } if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && bt_mesh_friend_match(net_idx, dst)) { + BT_DBG("FrndMatch"); return true; } @@ -848,6 +951,9 @@ bool bt_mesh_valid_security_cred(struct bt_mesh_net_tx *tx) * If not, later a better security credentials could be * chosen for the message. */ + BT_DBG("IsValidSecCred, NetIdx 0x%04x Tag 0x%02x Cred %u", + tx->ctx->net_idx, tx->ctx->send_tag, tx->ctx->send_cred); + if (!bt_mesh_tag_immutable_cred(tx->ctx->send_tag)) { return true; } @@ -876,22 +982,27 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) net_idx = tx->ctx->net_idx; addr = tx->ctx->addr; + BT_DBG("ChooseBetterSecCred"); + BT_DBG("NetIdx 0x%04x Dst 0x%04x Tag 0x%02x Cred %u", + net_idx, addr, send_tag, send_cred); + /* If the message is tagged with immutable-credentials, * then the security credentials shall not be changed. */ if (bt_mesh_tag_immutable_cred(send_tag)) { + BT_DBG("ImmutableCred"); return; } if (send_cred > BLE_MESH_FRIENDSHIP_CRED) { - BT_INFO("Use managed flooding security credentials"); + BT_INFO("UseFloodingSecCred"); tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; return; } if (send_cred == BLE_MESH_FRIENDSHIP_CRED) { if (!use_friend_cred(net_idx, addr)) { - BT_INFO("Use managed flooding security credentials"); + BT_INFO("UseFloodingSecCred"); tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; } else { @@ -916,14 +1027,13 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && BLE_MESH_ADDR_IS_UNICAST(addr) && bt_mesh_friend_match(net_idx, addr)) { - BT_INFO("Use friendship security credentials"); + BT_INFO("UseFrndSecCred"); tx->ctx->send_cred = BLE_MESH_FRIENDSHIP_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; return; } - /** - * Spec 3.7.3.1 + /* Spec 3.7.3.1 * The Low power node in friendship should use friendship security * material. * @@ -943,24 +1053,26 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) if (BLE_MESH_ADDR_IS_UNICAST(addr) && bt_mesh.lpn.frnd == addr && !bt_mesh_tag_immutable_cred(send_tag)) { + BT_INFO("UseFrndSecCred"); tx->ctx->send_cred = BLE_MESH_FRIENDSHIP_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; return; } -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ } #endif /* !CONFIG_BLE_MESH_V11_SUPPORT */ -static int model_send(struct bt_mesh_model *model, +static int model_send(const struct bt_mesh_model *model, struct bt_mesh_net_tx *tx, bool implicit_bind, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { int err = 0; - BT_INFO("send, app_idx 0x%04x src 0x%04x dst 0x%04x", - tx->ctx->app_idx, tx->src, tx->ctx->addr); - BT_INFO("send, len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_INFO("ModelSend"); + BT_INFO("AppIdx 0x%04x Src 0x%04x Dst 0x%04x TTL %u", + tx->ctx->app_idx, tx->src, tx->ctx->addr, tx->ctx->send_ttl); + BT_INFO("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); if (ready_to_send(tx->ctx->addr) == false) { BT_ERR("Not ready to send"); @@ -1013,7 +1125,7 @@ static int model_send(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_DF_SRV bt_mesh_is_directed_path_needed(tx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return err; } @@ -1025,9 +1137,11 @@ int bt_mesh_model_send_implicit(struct bt_mesh_model *model, { struct bt_mesh_subnet *sub = NULL; + BT_DBG("ModelSendImplicit"); + sub = bt_mesh_subnet_get(ctx->net_idx); if (!sub) { - BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + BT_ERR("NetIdx 0x%04x not found", ctx->net_idx); return -EADDRNOTAVAIL; } @@ -1041,16 +1155,18 @@ int bt_mesh_model_send_implicit(struct bt_mesh_model *model, return model_send(model, &tx, implicit_bind, msg, cb, cb_data); } -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { struct bt_mesh_subnet *sub = NULL; + BT_DBG("ModelSend, NetIdx 0x%04x", ctx->net_idx); + sub = bt_mesh_subnet_get(ctx->net_idx); if (!sub) { - BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + BT_ERR("NetIdx 0x%04x not found", ctx->net_idx); return -EADDRNOTAVAIL; } @@ -1077,6 +1193,8 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) }; int err = 0; + BT_DBG("ModelPublish"); + if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; @@ -1125,12 +1243,12 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ pub->count = BLE_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); - BT_INFO("Publish Retransmit Count %u Interval %ums", pub->count, - BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); + BT_INFO("PubCount %u PubInterval %u", + pub->count, BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { @@ -1154,6 +1272,8 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem, { int i; + BT_DBG("ModelFindVnd, ID 0x%04x CID 0x%04x", id, company); + for (i = 0; i < elem->vnd_model_count; i++) { if (elem->vnd_models[i].vnd.company == company && elem->vnd_models[i].vnd.id == id) { @@ -1168,6 +1288,8 @@ struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, uint16_t id) { int i; + BT_DBG("ModelFind, ID 0x%04x", id); + for (i = 0; i < elem->model_count; i++) { if (elem->models[i].id == id) { return &elem->models[i]; @@ -1179,6 +1301,8 @@ struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, uint16_t id) const struct bt_mesh_comp *bt_mesh_comp_get(void) { + BT_DBG("CompGet %p", comp_0); + return comp_0; } @@ -1196,6 +1320,8 @@ const uint8_t *bt_mesh_dev_key_get(uint16_t dst) key = bt_mesh_provisioner_dev_key_get(dst); } + BT_DBG("Dst 0x%04x DevKey %s", dst, key ? bt_hex(key, 16) : ""); + return key; } @@ -1207,20 +1333,22 @@ size_t bt_mesh_rx_netkey_size(void) if (bt_mesh_is_provisioned()) { size = ARRAY_SIZE(bt_mesh.sub); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { size = ARRAY_SIZE(bt_mesh.p_sub); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = ARRAY_SIZE(bt_mesh.sub); if (bt_mesh_is_provisioner_en()) { size += ARRAY_SIZE(bt_mesh.p_sub); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxNetKeySize %u", size); return size; } @@ -1233,13 +1361,13 @@ struct bt_mesh_subnet *bt_mesh_rx_netkey_get(size_t index) if (bt_mesh_is_provisioned()) { sub = &bt_mesh.sub[index]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { sub = bt_mesh.p_sub[index]; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index < ARRAY_SIZE(bt_mesh.sub)) { @@ -1247,7 +1375,10 @@ struct bt_mesh_subnet *bt_mesh_rx_netkey_get(size_t index) } else { sub = bt_mesh.p_sub[index - ARRAY_SIZE(bt_mesh.sub)]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxNetKeyGet, Index %u NetIdx 0x%04x", + index, sub ? sub->net_idx : BLE_MESH_KEY_ANY); return sub; } @@ -1271,7 +1402,7 @@ size_t bt_mesh_rx_devkey_size(void) if (bt_mesh_is_provisioner_en()) { size = 1; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = 1; @@ -1283,7 +1414,9 @@ size_t bt_mesh_rx_devkey_size(void) if (bt_mesh_is_provisioner_en()) { size += 1; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxDevKeySize %u", size); return size; } @@ -1300,13 +1433,13 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) key = bt_mesh.dev_key_ca; } } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { key = bt_mesh_provisioner_dev_key_get(src); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index == 0) { @@ -1324,11 +1457,13 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) */ key = bt_mesh.dev_key_ca; } else -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ { key = bt_mesh_provisioner_dev_key_get(src); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxDevKeyGet, Index %u Src 0x%04x", index, src); return key; } @@ -1341,20 +1476,22 @@ size_t bt_mesh_rx_appkey_size(void) if (bt_mesh_is_provisioned()) { size = ARRAY_SIZE(bt_mesh.app_keys); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { size = ARRAY_SIZE(bt_mesh.p_app_keys); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = ARRAY_SIZE(bt_mesh.app_keys); if (bt_mesh_is_provisioner_en()) { size += ARRAY_SIZE(bt_mesh.p_app_keys); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxAppKeySize %u", size); return size; } @@ -1367,13 +1504,13 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) if (bt_mesh_is_provisioned()) { key = &bt_mesh.app_keys[index]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { key = bt_mesh.p_app_keys[index]; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index < ARRAY_SIZE(bt_mesh.app_keys)) { @@ -1381,7 +1518,87 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) } else { key = bt_mesh.p_app_keys[index - ARRAY_SIZE(bt_mesh.app_keys)]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxAppKeyGet, Index %u AppIdx 0x%04x", + index, key ? key->app_idx : BLE_MESH_KEY_ANY); return key; } + +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) +{ + BT_DBG("AppKeyGet, AppIdx 0x%04x", app_idx); + + if (bt_mesh_is_provisioned()) { +#if CONFIG_BLE_MESH_NODE + if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { + for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.app_keys[i].app_idx == app_idx) { + BT_DBG("NodeAppKey"); + return &bt_mesh.app_keys[i]; + } + } + } else { + BT_DBG("FastProvAppKey"); + return bt_mesh_fast_prov_app_key_find(app_idx); + } +#endif /* CONFIG_BLE_MESH_NODE */ + } else if (bt_mesh_is_provisioner_en()) { +#if CONFIG_BLE_MESH_PROVISIONER + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + if (bt_mesh.p_app_keys[i] && + bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.p_app_keys[i]->app_idx == app_idx) { + BT_DBG("PvnrAppKey"); + return bt_mesh.p_app_keys[i]; + } + } +#endif /* CONFIG_BLE_MESH_PROVISIONER */ + } + + return NULL; +} + +int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, + const uint8_t **key, uint8_t *aid, uint16_t dst) +{ + struct bt_mesh_app_key *app_key = NULL; + + BT_DBG("UpperKeyGet, AppIdx 0x%04x Dst 0x%04x", app_idx, dst); + + if (app_idx == BLE_MESH_KEY_DEV) { + *key = bt_mesh_dev_key_get(dst); + if (!*key) { + BT_ERR("DevKeyNotFound 0x%04x", dst); + return -EINVAL; + } + + *aid = 0U; + return 0; + } + + if (!subnet) { + BT_ERR("InvalidSubnet"); + return -EINVAL; + } + + app_key = bt_mesh_app_key_get(app_idx); + if (!app_key) { + BT_ERR("AppKeyNotFound 0x%04x", app_idx); + return -ENOENT; + } + + if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { + BT_DBG("NewAppKey"); + *key = app_key->keys[1].val; + *aid = app_key->keys[1].id; + } else { + BT_DBG("OldAppKey"); + *key = app_key->keys[0].val; + *aid = app_key->keys[0].id; + } + + return 0; +} diff --git a/components/bt/esp_ble_mesh/core/access.h b/components/bt/esp_ble_mesh/core/access.h index 672a9a2c7bf3..669cff788c23 100644 --- a/components/bt/esp_ble_mesh/core/access.h +++ b/components/bt/esp_ble_mesh/core/access.h @@ -29,6 +29,8 @@ uint8_t bt_mesh_elem_count(void); /* Find local element based on unicast or group address */ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); +bool bt_mesh_has_addr(uint16_t addr); + uint16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, uint16_t addr); int bt_mesh_get_opcode(struct net_buf_simple *buf, diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index fa4249c1875e..9a12e8c12542 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -29,32 +29,11 @@ static struct bt_mesh_adv_queue *adv_queue; #if CONFIG_BLE_MESH_RELAY_ADV_BUF - -#define BLE_MESH_RELAY_QUEUE_SIZE CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT - static QueueSetHandle_t mesh_queue_set; -#define BLE_MESH_QUEUE_SET_SIZE (BLE_MESH_ADV_QUEUE_SIZE + BLE_MESH_RELAY_QUEUE_SIZE) - +#define BLE_MESH_QUEUE_SET_SIZE (bt_mesh_adv_buf_count_get() + bt_mesh_relay_adv_buf_count_get()) #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline int adv_send(struct net_buf *buf) +static int adv_send(struct net_buf *buf) { const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; void *cb_data = BLE_MESH_ADV(buf)->cb_data; @@ -64,8 +43,8 @@ static inline int adv_send(struct net_buf *buf) struct bt_mesh_adv_data ad = {0}; int err = 0; - BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("LegacyAdvSend, Type %u", BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV if (BLE_MESH_ADV(buf)->type != BLE_MESH_ADV_BLE) { @@ -133,10 +112,12 @@ static inline int adv_send(struct net_buf *buf) #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + struct bt_mesh_adv_data solic_ad[2] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x59, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), }; + #if CONFIG_BLE_MESH_USE_BLE_50 param.primary_phy = BLE_MESH_ADV_PHY_1M; param.secondary_phy = BLE_MESH_ADV_PHY_1M; @@ -145,9 +126,10 @@ static inline int adv_send(struct net_buf *buf) err = bt_le_adv_start(¶m, solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ { bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + #if CONFIG_BLE_MESH_USE_BLE_50 param.primary_phy = BLE_MESH_ADV_PHY_1M; param.secondary_phy = BLE_MESH_ADV_PHY_1M; @@ -168,8 +150,8 @@ static inline int adv_send(struct net_buf *buf) } BT_DBG("interval %dms, duration %dms, period %dms, count %d", - ADV_SCAN_INT(tx->param.interval), tx->param.duration, - tx->param.period, tx->param.count); + ADV_SCAN_INT(tx->param.interval), tx->param.duration, + tx->param.period, tx->param.count); data.adv_data_len = tx->buf->data[0]; if (data.adv_data_len) { @@ -192,6 +174,7 @@ static inline int adv_send(struct net_buf *buf) #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ net_buf_unref(buf); + adv_send_start(duration, err, cb, cb_data); if (err) { BT_ERR("Start advertising failed: err %d", err); @@ -201,17 +184,15 @@ static inline int adv_send(struct net_buf *buf) BT_DBG("Advertising started. Sleeping %u ms", duration); #if CONFIG_BLE_MESH_USE_BLE_50 - if (!ble_mesh_adv_task_wait(UINT32_MAX, K_FOREVER, NULL)) { + if (!bt_mesh_adv_task_wait(UINT32_MAX, K_FOREVER, NULL)) { BT_WARN("Advertising didn't finish on time"); bt_le_ext_adv_stop(CONFIG_BLE_MESH_ADV_INST_ID); } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ - ble_mesh_adv_task_wait(K_MSEC(duration)); -#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + bt_mesh_adv_task_wait(K_MSEC(duration)); -#if !CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_adv_stop(); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ adv_send_end(err, cb, cb_data); if (err) { @@ -223,36 +204,63 @@ static inline int adv_send(struct net_buf *buf) return 0; } +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +static QueueHandle_t relay_adv_handle_get(void) +{ + struct bt_mesh_adv_type_manager *adv_type = NULL; + + BT_DBG("RelayAdvHandleGet"); + + adv_type = bt_mesh_adv_types_mgmt_get(BLE_MESH_ADV_RELAY_DATA); + + if (adv_type->adv_q == NULL) { + BT_DBG("HandleNotFound"); + return NULL; + } + + return adv_type->adv_q->q.handle; +} +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + static void adv_thread(void *p) { #if CONFIG_BLE_MESH_RELAY_ADV_BUF + QueueHandle_t relay_adv_handle = NULL; QueueSetMemberHandle_t handle = NULL; - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; -#endif - bt_mesh_msg_t msg = {0}; +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ struct net_buf **buf = NULL; + bt_mesh_msg_t msg = {0}; + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ buf = (struct net_buf **)(&msg.arg); - BT_DBG("%s, starts", __func__); + BT_DBG("LegacyAdvThread"); while (1) { *buf = NULL; + #if !CONFIG_BLE_MESH_RELAY_ADV_BUF #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER xQueueReceive(adv_queue->q.handle, &msg, K_NO_WAIT); while (!(*buf)) { int32_t timeout = 0; + BT_DBG("Mesh Proxy Advertising start"); + timeout = bt_mesh_proxy_server_adv_start(); BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); + xQueueReceive(adv_queue->q.handle, &msg, K_WAIT(timeout)); + BT_DBG("Mesh Proxy Advertising stop"); bt_mesh_proxy_server_adv_stop(); } -#else +#else /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ xQueueReceive(adv_queue->q.handle, &msg, portMAX_DELAY); #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ @@ -268,12 +276,17 @@ static void adv_thread(void *p) } else { while (!(*buf)) { int32_t timeout = 0; + BT_DBG("Mesh Proxy Advertising start"); + timeout = bt_mesh_proxy_server_adv_start(); BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); + handle = xQueueSelectFromSet(mesh_queue_set, K_WAIT(timeout)); + BT_DBG("Mesh Proxy Advertising stop"); bt_mesh_proxy_server_adv_stop(); + if (handle) { if (uxQueueMessagesWaiting(adv_queue->q.handle)) { xQueueReceive(adv_queue->q.handle, &msg, K_NO_WAIT); @@ -283,7 +296,7 @@ static void adv_thread(void *p) } } } -#else +#else /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ handle = xQueueSelectFromSet(mesh_queue_set, portMAX_DELAY); if (handle) { if (uxQueueMessagesWaiting(adv_queue->q.handle)) { @@ -311,6 +324,7 @@ static void adv_thread(void *p) * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. */ BT_INFO("Ignore relay packet"); + net_buf_unref(*buf); } else { if (adv_send(*buf)) { @@ -323,33 +337,13 @@ static void adv_thread(void *p) net_buf_unref(*buf); } + BT_DBG("Yield"); + /* Give other threads a chance to run */ taskYIELD(); } } -void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - bt_mesh_msg_t msg = { - .relay = false, - }; - - BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, - bt_hex(buf->data, buf->len)); - - BLE_MESH_ADV(buf)->cb = cb; - BLE_MESH_ADV(buf)->cb_data = cb_data; - bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); - BLE_MESH_ADV(buf)->xmit = xmit; - - bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); - - msg.arg = (void *)net_buf_ref(buf); - bt_mesh_task_post(&msg, portMAX_DELAY, false); -} - void bt_mesh_adv_update(void) { bt_mesh_msg_t msg = { @@ -357,11 +351,14 @@ void bt_mesh_adv_update(void) .arg = NULL, }; + BT_DBG("LegacyAdvUpdate"); + bt_mesh_task_post(&msg, K_NO_WAIT, false); } void bt_mesh_adv_init(void) { + BT_DBG("LegacyAdvInit"); bt_mesh_adv_common_init(); adv_queue = bt_mesh_adv_queue_get(); @@ -369,20 +366,22 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + QueueHandle_t relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); -#if CONFIG_BLE_MESH_RELAY_ADV_BUF && !CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; mesh_queue_set = xQueueCreateSet(BLE_MESH_QUEUE_SET_SIZE); - __ASSERT(mesh_queue_set, "Failed to create queue set"); + assert(mesh_queue_set); + xQueueAddToSet(adv_queue->q.handle, mesh_queue_set); xQueueAddToSet(relay_adv_handle, mesh_queue_set); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ bt_mesh_adv_task_init(adv_thread); } @@ -390,15 +389,18 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_deinit(void) { + BT_DBG("LegacyAdvDeinit"); + /* Adv task must be deinit first */ bt_mesh_adv_task_deinit(); #if CONFIG_BLE_MESH_RELAY_ADV_BUF - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; + QueueHandle_t relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); xQueueRemoveFromSet(adv_queue->q.handle, mesh_queue_set); xQueueRemoveFromSet(relay_adv_handle, mesh_queue_set); + vQueueDelete(mesh_queue_set); mesh_queue_set = NULL; diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index 5770364a2e30..79f8ca2991b4 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -23,17 +23,16 @@ extern "C" { #endif -void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data); - void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); + void bt_mesh_adv_deinit(void); #ifdef __cplusplus } #endif + #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + #endif /* _ADV_H_ */ diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c index 96b4ac773aee..ff4e50ac1c8d 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.c +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -31,8 +31,7 @@ struct bt_mesh_adv_queue relay_adv_queue; #define BLE_MESH_RELAY_TIME_INTERVAL K_SECONDS(6) #define BLE_MESH_MAX_TIME_INTERVAL 0xFFFFFFFF - -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ static bt_mesh_mutex_t adv_buf_alloc_lock; #if CONFIG_BLE_MESH_EXT_ADV @@ -76,16 +75,8 @@ static inline void init_adv_with_defaults(struct bt_mesh_adv *adv, NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BLE_MESH_ADV_DATA_SIZE, NULL); -bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; - -struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_type type) -{ - memset(&frnd_adv_pool[idx].adv, 0, sizeof(struct bt_mesh_adv)); - init_adv_with_defaults(&frnd_adv_pool[idx].adv, type); - frnd_adv_pool[idx].app_idx = BLE_MESH_KEY_UNUSED; - return &frnd_adv_pool[idx].adv; -} -#endif +static bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; +#endif /* CONFIG_BLE_MESH_FRIEND */ struct bt_mesh_adv_task { TaskHandle_t handle; @@ -98,47 +89,51 @@ struct bt_mesh_adv_task { }; static struct bt_mesh_adv_task adv_task; + static struct bt_mesh_adv_type_manager adv_types[BLE_MESH_ADV_TYPES_NUM]; #if CONFIG_BLE_MESH_USE_BLE_50 static struct bt_mesh_adv_inst adv_insts[] = { - [BLE_MESH_ADV_INS] = { + [BLE_MESH_ADV_INST] = { .id = CONFIG_BLE_MESH_ADV_INST_ID, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV .busy = false, -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - [BLE_MESH_ADV_PROXY_INS] = { + [BLE_MESH_ADV_PROXY_INST] = { .id = CONFIG_BLE_MESH_PROXY_ADV_INST_ID, .busy = false, }, #endif #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - [BLE_MESH_RELAY_ADV_INS] = { + [BLE_MESH_RELAY_ADV_INST] = { .id = CONFIG_BLE_MESH_RELAY_ADV_INST_ID, .busy = false, }, -#endif +#endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - [BLE_MESH_BLE_ADV_INS] = { + [BLE_MESH_BLE_ADV_INST] = { .id = CONFIG_BLE_MESH_BLE_ADV_INST_ID, .busy = false, }, -#endif +#endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }; static struct bt_mesh_adv_inst *find_adv_inst_with_inst_id(uint8_t id) { + BT_DBG("FindAdvInstWithID, InstID %u", id); + for (int i = 0; i < ARRAY_SIZE(adv_insts); i++) { if (adv_insts[i].id == id) { return &adv_insts[i]; } } + BT_WARN("NotFoundAdvInst, InstID %u", id); return NULL; } @@ -147,47 +142,57 @@ struct bt_mesh_adv_inst *bt_mesh_get_adv_insts_set(void) return adv_insts; } -bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id) +bool bt_mesh_is_adv_inst_used(uint8_t inst_id) { - return (find_adv_inst_with_inst_id(adv_inst_id) != NULL); + BT_DBG("IsAdvInstUsed, InstID %u", inst_id); + + return (find_adv_inst_with_inst_id(inst_id) != NULL); } int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_DBG("AdvInstInit, InstType %u InstID %u", inst_type, inst_id); + + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("InvalidAdvInstType %u", inst_type); return -EINVAL; } - if (inst_id == BLE_MESH_ADV_INS_UNUSED) { - BT_ERR("Invalid instance id %d", inst_id); + if (inst_id == BLE_MESH_ADV_INST_UNUSED) { + BT_ERR("UnusedAdvInstID"); return -EINVAL; } adv_insts[inst_type].id = inst_id; + return 0; } int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_DBG("AdvInstDeinit, InstType %u", inst_type); + + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid adv inst type %d", inst_type); return -EINVAL; } + BT_DBG("InstID %u", adv_insts[inst_type].id); + bt_le_ext_adv_stop(adv_insts[inst_type].id); - adv_insts[inst_type].id = BLE_MESH_ADV_INS_UNUSED; + adv_insts[inst_type].id = BLE_MESH_ADV_INST_UNUSED; #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV adv_insts[inst_type].spt_mask = 0; -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + return 0; } - #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ -struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) +static struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("AdvAlloc, ID %d", id); init_adv_with_defaults(&adv_pool[id], type); return &adv_pool[id]; } @@ -238,8 +243,10 @@ struct bt_mesh_adv *ext_long_relay_adv_alloc(int id, enum bt_mesh_adv_type type) #endif /* CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ #endif /* CONFIG_BLE_MESH_LONG_PACKET */ -struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgnt_get(enum bt_mesh_adv_type adv_type) +struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgmt_get(enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvTypeMgmtGet, AdvType %u", adv_type); + return &adv_types[adv_type]; } @@ -251,6 +258,8 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, return; } + BT_DBG("AdvBufRefDebug, BufRef %u RefCmp %u", buf->ref, ref_cmp); + switch (flag) { case BLE_MESH_BUF_REF_EQUAL: if (buf->ref != ref_cmp) { @@ -268,11 +277,13 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, } #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV -void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_DBG("AdvInstTypeAdd, InstType %u AdvType %u", inst_type, adv_type); + + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -284,11 +295,13 @@ void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_typ adv_insts[inst_type].spt_mask |= BIT(adv_type); } -void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_rem(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_DBG("AdvInstTypeRem, InstType %u AdvType %u", inst_type, adv_type); + + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -300,11 +313,13 @@ void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type adv_insts[inst_type].spt_mask &= ~BIT(adv_type); } -void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_clear(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_DBG("AdvInstTypeClear, InstType %u AdvType %u", inst_type, adv_type); + + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -315,18 +330,19 @@ void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_t adv_insts[inst_type].spt_mask = 0; } -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, uint16_t queue_size, bt_mesh_adv_queue_send_cb_t cb) { + BT_DBG("AdvQueueInit, QueueSize %u", queue_size); + if (!adv_queue || !queue_size || !cb) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_queue_init(&adv_queue->q, queue_size, sizeof(bt_mesh_msg_t)); - adv_queue->send = cb; return 0; @@ -334,13 +350,14 @@ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, uint16_t queue_s int bt_mesh_adv_queue_deinit(struct bt_mesh_adv_queue *adv_queue) { + BT_DBG("AdvQueueDeinit"); + if (!adv_queue) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_queue_deinit(&adv_queue->q); - adv_queue->send = NULL; return 0; @@ -351,13 +368,15 @@ void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, struct net_buf_pool *buf_pool, bt_mesh_pool_allocator_t adv_alloc) { + BT_DBG("AdvTypeInit, AdvType %u", adv_type); + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { - BT_ERR("%s Invalid adv type %d",__func__, adv_type); + BT_ERR("%s, Invalid adv type %d", __func__, adv_type); return; } if (!adv_queue || !buf_pool || !adv_alloc) { - BT_ERR("Invalid parameters %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return; } @@ -368,8 +387,10 @@ void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvTypeDeinit, AdvType %u", adv_type); + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { - BT_ERR("%s Invalid adv type %d",__func__, adv_type); + BT_ERR("%s, Invalid adv type %d", __func__, adv_type); return; } @@ -379,19 +400,25 @@ void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) } #if CONFIG_BLE_MESH_USE_BLE_50 -int ble_mesh_adv_task_wakeup(uint32_t evt) +int bt_mesh_adv_task_wakeup(uint32_t evt) { + BT_DBG("AdvTypeWakeup, Evt 0x%08lx", evt); + xTaskNotify(adv_task.handle, evt, eSetBits); return 0; } -bool ble_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) +bool bt_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) { + BT_DBG("AdvTypeWait, WaitBits 0x%08lx Timeout %lu", wait_bits, timeout); + return (xTaskNotifyWait(wait_bits, UINT32_MAX, notify, K_WAIT(timeout)) == pdTRUE); } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ -bool ble_mesh_adv_task_wait(uint32_t timeout) +bool bt_mesh_adv_task_wait(uint32_t timeout) { + BT_DBG("AdvTypeWait, Timeout %lu", timeout); + vTaskDelay(K_WAIT(timeout)); return true; } @@ -405,45 +432,58 @@ uint16_t bt_mesh_pdu_duration(uint8_t xmit) adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_TRANSMIT_INT(xmit)); duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + BT_DBG("PDUDuration %u", duration); + return duration; } -struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, - int32_t timeout) +struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t timeout) { struct bt_mesh_adv *adv = NULL; struct net_buf *buf = NULL; - struct net_buf_pool *pool = adv_types[type].pool; + + BT_DBG("AdvCreateFromPool, Type %u", type); if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { BT_WARN("Refusing to allocate buffer while suspended"); return NULL; } - if (!pool || !adv_types[type].pool_allocator) { + if (type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("%s, Invalid adv type %u", __func__, type); + return NULL; + } + + if (adv_types[type].pool == NULL || adv_types[type].pool_allocator == NULL) { BT_ERR("Uninitialized adv type %d", type); return NULL; } bt_mesh_r_mutex_lock(&adv_buf_alloc_lock); - buf = net_buf_alloc(pool, timeout); + + buf = net_buf_alloc(adv_types[type].pool, timeout); if (!buf) { + BT_WARN("net buf alloc failed"); bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); - BT_WARN("Buf alloc failed"); return NULL; } - BT_DBG("pool %p, buf_count %d, uinit_count %d, ref %d", - buf->pool, pool->buf_count, pool->uninit_count, buf->ref); + BT_DBG("Pool %p BufCount %u UinitCount %u BufID %d Ref %u", + adv_types[type].pool, adv_types[type].pool->buf_count, + adv_types[type].pool->uninit_count, net_buf_id(buf), + buf->ref); adv = adv_types[type].pool_allocator(net_buf_id(buf), type); BLE_MESH_ADV(buf) = adv; bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); + return buf; } void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) { + BT_DBG("UnrefBufFromPool"); + if (pool == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -451,6 +491,9 @@ void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) for (int i = 0; i < pool->buf_count; i++) { struct net_buf *buf = &pool->__bufs[i]; + + BT_DBG("%u: Buf %p Ref %u", i, buf, buf->ref); + if (buf->ref > 1U) { buf->ref = 1U; } @@ -460,11 +503,15 @@ void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) void bt_mesh_unref_buf(bt_mesh_msg_t *msg) { - struct net_buf *buf = NULL; + struct net_buf *buf = msg->arg; + + BT_DBG("UnRefBuf %p", buf); + + if (buf) { + BT_DBG("Ref %u", buf->ref); - if (msg->arg) { - buf = (struct net_buf *)msg->arg; bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); + if (buf->ref > 1U) { buf->ref = 1U; } @@ -481,8 +528,10 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, .relay = false, /* useless flag in multi-instance mode */ }; - BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GenericAdvSend"); + BT_DBG("Src 0x%04x Dst 0x%04x Type 0x%02x", + src, dst, BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; @@ -499,16 +548,19 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, msg.src = src; msg.dst = dst; msg.timestamp = k_uptime_get_32(); + + BT_DBG("RelayAdvData, Timestamp %lu", msg.timestamp); } -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ - assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q && adv_types[BLE_MESH_ADV(buf)->type].adv_q->send); + assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q); + assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q->send); adv_types[BLE_MESH_ADV(buf)->type].adv_q->send(&msg, portMAX_DELAY, front); #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); -#endif + bt_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ } struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void) @@ -518,6 +570,8 @@ struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void) void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { + BT_DBG("TaskPost, Front %u", front); + if (adv_queue.q.handle == NULL) { BT_ERR("Invalid adv queue"); return; @@ -548,26 +602,25 @@ bool bt_mesh_ignore_relay_packet(uint32_t timestamp) interval = BLE_MESH_MAX_TIME_INTERVAL - (timestamp - now) + 1; } + BT_DBG("IgnoreRelayPacket"); + BT_DBG("Now %lu Timestamp %lu Interval %lu", now, timestamp, interval); + return ((interval >= BLE_MESH_RELAY_TIME_INTERVAL) ? true : false); } static struct bt_mesh_adv *relay_adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("RelayAdvAlloc, ID %d", id); memset(&relay_adv_pool[id], 0, sizeof(struct bt_mesh_adv)); init_adv_with_defaults(&relay_adv_pool[id], type); return &relay_adv_pool[id]; } -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout) -{ - return bt_mesh_adv_create_from_pool(type, timeout); -} - -static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) +static void bt_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { bt_mesh_msg_t old_msg = {0}; - ARG_UNUSED(front); + BT_DBG("RelayTaskPost, Front %u", front); if (relay_adv_queue.q.handle == NULL) { BT_ERR("Invalid relay queue"); @@ -583,14 +636,17 @@ static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool */ if (uxQueueMessagesWaiting(relay_adv_queue.q.handle)) { BT_INFO("Full queue, remove the oldest relay packet"); + /* Remove the oldest relay packet from queue */ if (xQueueReceive(relay_adv_queue.q.handle, &old_msg, K_NO_WAIT) != pdTRUE) { BT_ERR("Failed to remove item from relay queue"); bt_mesh_unref_buf(msg); return; } + /* Unref buf used for the oldest relay packet */ bt_mesh_unref_buf(&old_msg); + /* Send the latest relay packet to queue */ if (xQueueSend(relay_adv_queue.q.handle, msg, K_NO_WAIT) != pdTRUE) { BT_ERR("Failed to send item to relay queue"); @@ -605,28 +661,18 @@ static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool uint16_t bt_mesh_get_stored_relay_count(void) { - return (uint16_t)uxQueueMessagesWaiting(relay_adv_queue.q.handle); -} - -static ALWAYS_INLINE -uint16_t ble_mesh_relay_adv_buf_count_get(void) -{ - uint16_t relay_adv_count = 2 + CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT; + uint16_t count = (uint16_t)uxQueueMessagesWaiting(relay_adv_queue.q.handle); -#if CONFIG_BLE_MESH_EXT_ADV && CONFIG_BLE_MESH_RELAY - relay_adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; -#endif + BT_DBG("StoredRelayCount %u", count); -#if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_RELAY - relay_adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; -#endif - return relay_adv_count; + return count; } void bt_mesh_relay_adv_init(void) { - bt_mesh_adv_queue_init(&relay_adv_queue, ble_mesh_relay_adv_buf_count_get(), - ble_mesh_relay_task_post); + BT_DBG("RelayAdvInit"); + bt_mesh_adv_queue_init(&relay_adv_queue, bt_mesh_relay_adv_buf_count_get(), + bt_mesh_relay_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_RELAY_DATA, &relay_adv_queue, &relay_adv_buf_pool, &relay_adv_alloc); #if CONFIG_BLE_MESH_EXT_ADV @@ -634,69 +680,74 @@ void bt_mesh_relay_adv_init(void) &ext_adv_buf_pool, &ext_relay_adv_alloc); #if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, &relay_adv_queue, - &ext_long_relay_adv_buf_pool, ext_long_relay_adv_alloc); -#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + &ext_long_relay_adv_buf_pool, ext_long_relay_adv_alloc); +#endif /* CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - bt_mesh_adv_inst_init(BLE_MESH_RELAY_ADV_INS, + bt_mesh_adv_inst_init(BLE_MESH_RELAY_ADV_INST, CONFIG_BLE_MESH_RELAY_ADV_INST_ID); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ -#else +#else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } + #if CONFIG_BLE_MESH_DEINIT void bt_mesh_relay_adv_deinit(void) { + BT_DBG("RelayAdvDeinit"); + bt_mesh_adv_queue_deinit(&relay_adv_queue); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ - bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INS); -#else + bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INST); +#else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + bt_mesh_unref_buf_from_pool(&relay_adv_buf_pool); memset(relay_adv_pool, 0, sizeof(relay_adv_pool)); } @@ -704,25 +755,35 @@ void bt_mesh_relay_adv_deinit(void) #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_FRIEND -struct net_buf_pool *bt_mesh_frnd_adv_pool_get(void) +static struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_type type) { - return &friend_buf_pool; + BT_DBG("FrndAdvBufGet, Idx %d", idx); + + memset(&frnd_adv_pool[idx].adv, 0, sizeof(struct bt_mesh_adv)); + init_adv_with_defaults(&frnd_adv_pool[idx].adv, type); + frnd_adv_pool[idx].app_idx = BLE_MESH_KEY_UNUSED; + return &frnd_adv_pool[idx].adv; } void bt_mesh_frnd_adv_init(void) { + BT_DBG("FrndAdvInit"); + bt_mesh_adv_type_init(BLE_MESH_ADV_FRIEND, &adv_queue, &friend_buf_pool, bt_mesh_frnd_adv_buf_get); + #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_FRIEND); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ } void bt_mesh_frnd_adv_deinit(void) { + BT_DBG("FrndAdvDeinit"); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_FRIEND); #if CONFIG_BLE_MESH_FRIEND && CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_FRIEND); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_FRIEND */ bt_mesh_unref_buf_from_pool(&friend_buf_pool); @@ -730,72 +791,61 @@ void bt_mesh_frnd_adv_deinit(void) } #endif /* CONFIG_BLE_MESH_FRIEND */ -static ALWAYS_INLINE -uint16_t ble_mesh_adv_buf_count_get(void) -{ - uint16_t adv_count = 2 + CONFIG_BLE_MESH_ADV_BUF_COUNT; - -#if CONFIG_BLE_MESH_EXT_ADV - adv_count += CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT; -#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY - adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; -#endif -#endif - -#if CONFIG_BLE_MESH_LONG_PACKET - adv_count += CONFIG_BLE_MESH_LONG_PACKET_ADV_BUF_COUNT; -#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY - adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; -#endif -#endif - -#if (CONFIG_BLE_MESH_SUPPORT_BLE_ADV && \ - !(CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE)) - adv_count += CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT; -#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ - - return adv_count; -} - void bt_mesh_adv_task_init(void adv_thread(void *p)) { + BT_DBG("AdvTaskInit"); + if (!adv_thread) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return; } #if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ - (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ + (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) adv_task.task = heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); - __ASSERT(adv_task.task, "Failed to create adv thread task"); - adv_task.stack = heap_caps_calloc_prefer(1, BLE_MESH_ADV_TASK_STACK_SIZE * sizeof(StackType_t), 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); - __ASSERT(adv_task.stack, "Failed to create adv thread stack"); - adv_task.handle = xTaskCreateStaticPinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL, - BLE_MESH_ADV_TASK_PRIO, adv_task.stack, adv_task.task, BLE_MESH_ADV_TASK_CORE); - __ASSERT(adv_task.handle, "Failed to create static adv thread"); + assert(adv_task.task); + + adv_task.stack = heap_caps_calloc_prefer(1, BLE_MESH_ADV_TASK_STACK_SIZE * sizeof(StackType_t), + 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + assert(adv_task.stack); + + adv_task.handle = xTaskCreateStaticPinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, + BLE_MESH_ADV_TASK_STACK_SIZE, NULL, + BLE_MESH_ADV_TASK_PRIO, adv_task.stack, + adv_task.task, BLE_MESH_ADV_TASK_CORE); + assert(adv_task.handle); #else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ int ret = xTaskCreatePinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL, BLE_MESH_ADV_TASK_PRIO, &adv_task.handle, BLE_MESH_ADV_TASK_CORE); - __ASSERT(ret == pdTRUE, "Failed to create adv thread"); - (void)ret; +#if CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE + if (ret != pdTRUE) { + BT_ERR("xTaskCreatePinnedToCore failed, ret %d", ret); + return; + } +#else + assert(ret == pdTRUE); +#endif /* CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE */ #endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ } void bt_mesh_adv_common_init(void) { + BT_DBG("AdvCommonInit"); + bt_mesh_r_mutex_create(&adv_buf_alloc_lock); - bt_mesh_adv_queue_init(&adv_queue, ble_mesh_adv_buf_count_get(), bt_mesh_task_post); + bt_mesh_adv_queue_init(&adv_queue, bt_mesh_adv_buf_count_get(), bt_mesh_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_PROV, &adv_queue, &adv_buf_pool, adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_DATA, &adv_queue, &adv_buf_pool, adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_BEACON, &adv_queue, &adv_buf_pool, adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_URI, &adv_queue, &adv_buf_pool, adv_alloc); #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX bt_mesh_adv_type_init(BLE_MESH_ADV_PROXY_SOLIC, &adv_queue, &adv_buf_pool, adv_alloc); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ #if CONFIG_BLE_MESH_USE_BLE_50 - bt_mesh_adv_inst_init(BLE_MESH_ADV_INS, CONFIG_BLE_MESH_ADV_INST_ID); + bt_mesh_adv_inst_init(BLE_MESH_ADV_INST, CONFIG_BLE_MESH_ADV_INST_ID); #if CONFIG_BLE_MESH_EXT_ADV bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_PROV, &adv_queue, &ext_adv_buf_pool, ext_adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_DATA, &adv_queue, &ext_adv_buf_pool, ext_adv_alloc); @@ -813,29 +863,28 @@ void bt_mesh_adv_common_init(void) #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - /** - * Due to the limitation of the sequence number in the network layer, + /* Due to the limitation of the sequence number in the network layer, * it is not possible to use multiple advertising instances to process * data from the same message queue when sending mesh packets. * - * Therefore, shall to check whether there are - * duplicates in the queue buffer corresponding to each advertising instance. - */ - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_DATA); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_BEACON); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_URI); + * Therefore, shall to check whether there are duplicates in the queue + * buffer corresponding to each advertising instance. + */ + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BEACON); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_URI); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_DATA); #if CONFIG_BLE_MESH_RELAY && !CONFIG_BLE_MESH_RELAY_ADV_BUF - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #endif #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_DATA); #if CONFIG_BLE_MESH_RELAY && !CONFIG_BLE_MESH_RELAY_ADV_BUF - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ @@ -845,6 +894,8 @@ void bt_mesh_adv_common_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_task_deinit(void) { + BT_DBG("AdvTaskDeinit"); + vTaskDelete(adv_task.handle); adv_task.handle = NULL; @@ -860,6 +911,8 @@ void bt_mesh_adv_task_deinit(void) void bt_mesh_adv_common_deinit(void) { + BT_DBG("AdvCommonDeinit"); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_PROV); bt_mesh_adv_type_deinit(BLE_MESH_ADV_DATA); bt_mesh_adv_type_deinit(BLE_MESH_ADV_BEACON); @@ -885,12 +938,14 @@ void bt_mesh_adv_common_deinit(void) #endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_adv_queue_deinit(&adv_queue); + #if CONFIG_BLE_MESH_USE_BLE_50 - bt_mesh_adv_inst_deinit(BLE_MESH_ADV_INS); -#endif + bt_mesh_adv_inst_deinit(BLE_MESH_ADV_INST); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ bt_mesh_unref_buf_from_pool(&adv_buf_pool); memset(adv_pool, 0, sizeof(adv_pool)); + bt_mesh_r_mutex_free(&adv_buf_alloc_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/core/adv_common.h b/components/bt/esp_ble_mesh/core/adv_common.h index 23372d404cfc..54267ee5222d 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.h +++ b/components/bt/esp_ble_mesh/core/adv_common.h @@ -31,9 +31,9 @@ extern "C" { #endif /* Convert from ms to 0.625ms units */ -#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) /* Convert from 0.625ms units to interval(ms) */ -#define ADV_SCAN_INT(val) ((val) * 5 / 8) +#define ADV_SCAN_INT(val) ((val) * 5 / 8) /* Maximum advertising data payload for a single data type */ #define BLE_MESH_ADV_DATA_SIZE 29 @@ -46,7 +46,7 @@ extern "C" { #define BLE_MESH_MSG_NET_BUF(msg) ((struct net_buf *)(msg->arg)) -#define BLE_MESH_ADV_INS_UNUSED 0xFF +#define BLE_MESH_ADV_INST_UNUSED 0xFF struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; @@ -75,15 +75,13 @@ typedef struct { #endif #if CONFIG_BLE_MESH_FRIEND - #define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), bt_mesh_friend_adv_t, adv) typedef struct { struct bt_mesh_adv adv; uint16_t app_idx; } bt_mesh_friend_adv_t; - -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ enum { #if CONFIG_BLE_MESH_USE_BLE_50 @@ -103,12 +101,15 @@ enum { ADV_TASK_BLE_ADV_INST_EVT = BIT(CONFIG_BLE_MESH_BLE_ADV_INST_ID), #endif #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER ADV_TASK_PROXY_ADV_UPD_EVT = BIT(30), #endif #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + ADV_TASK_PKT_SEND_EVT = BIT(31), + ADV_TASK_EVT_MAX, }; @@ -124,11 +125,12 @@ typedef struct bt_mesh_msg { struct bt_mesh_adv_inst { uint8_t id; + #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bool busy; struct net_buf *sending_buf; - /* indicates that which adv_type is supported by this instance */ + /* Indicate which adv_type is supported by this instance */ uint32_t spt_mask; #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }; @@ -184,13 +186,13 @@ static const uint8_t adv_type[] = { #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_FRIEND - [BLE_MESH_ADV_FRIEND] = BLE_MESH_DATA_MESH_MESSAGE, + [BLE_MESH_ADV_FRIEND] = BLE_MESH_DATA_MESH_MESSAGE, #endif #if CONFIG_BLE_MESH_RELAY_ADV_BUF [BLE_MESH_ADV_RELAY_DATA] = BLE_MESH_DATA_MESH_MESSAGE, #endif - [BLE_MESH_ADV_BEACON] = BLE_MESH_DATA_MESH_BEACON, - [BLE_MESH_ADV_URI] = BLE_MESH_DATA_URI, + [BLE_MESH_ADV_BEACON] = BLE_MESH_DATA_MESH_BEACON, + [BLE_MESH_ADV_URI] = BLE_MESH_DATA_URI, }; typedef struct bt_mesh_adv *(*bt_mesh_pool_allocator_t)(int id, enum bt_mesh_adv_type type); @@ -212,10 +214,26 @@ static inline TickType_t K_WAIT(int32_t val) return (val == K_FOREVER) ? portMAX_DELAY : (val / portTICK_PERIOD_MS); } +static inline void adv_send_start(uint16_t duration, int err, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->start) { + cb->start(duration, err, cb_data); + } +} + +static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->end) { + cb->end(err, cb_data); + } +} + struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void); -struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, - int32_t timeout); +struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t timeout); static inline struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int32_t timeout) { @@ -225,14 +243,22 @@ static inline struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, uint8_t ref_cmp, bt_mesh_buf_ref_flag_t flag); -struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgnt_get(enum bt_mesh_adv_type adv_type); +struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgmt_get(enum bt_mesh_adv_type adv_type); void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, const struct bt_mesh_send_cb *cb, void *cb_data, uint16_t src, uint16_t dst, bool front); +static inline void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + bt_mesh_generic_adv_send(buf, xmit, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, false); +} + void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool); + void bt_mesh_unref_buf(bt_mesh_msg_t *msg); int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, @@ -242,35 +268,54 @@ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, int bt_mesh_adv_queue_deinit(struct bt_mesh_adv_queue *adv_queue); void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, - struct bt_mesh_adv_queue *adv_queue, - struct net_buf_pool *buf_pool, - bt_mesh_pool_allocator_t adv_alloc); + struct bt_mesh_adv_queue *adv_queue, + struct net_buf_pool *buf_pool, + bt_mesh_pool_allocator_t adv_alloc); void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type); void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); #if CONFIG_BLE_MESH_USE_BLE_50 -struct bt_mesh_adv_inst * bt_mesh_get_adv_insts_set(void); +struct bt_mesh_adv_inst *bt_mesh_get_adv_insts_set(void); + +bool bt_mesh_is_adv_inst_used(uint8_t inst_id); + int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id); + int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type); #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV -void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); +void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); -void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); +void bt_mesh_adv_inst_type_rem(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); -void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); -#endif +void bt_mesh_adv_inst_type_clear(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF +static ALWAYS_INLINE +uint16_t bt_mesh_relay_adv_buf_count_get(void) +{ + uint16_t relay_adv_count = 2 + CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT; + +#if CONFIG_BLE_MESH_EXT_ADV && CONFIG_BLE_MESH_RELAY + relay_adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; +#endif + +#if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_RELAY + relay_adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; +#endif + return relay_adv_count; +} + void bt_mesh_relay_adv_init(void); + bool bt_mesh_ignore_relay_packet(uint32_t timestamp); -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout); static inline void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, uint16_t src, uint16_t dst, @@ -288,31 +333,65 @@ void bt_mesh_relay_adv_deinit(void); #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_FRIEND -struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int id, enum bt_mesh_adv_type type); -struct net_buf_pool *bt_mesh_frnd_adv_pool_get(void); void bt_mesh_frnd_adv_init(void); + #if CONFIG_BLE_MESH_DEINIT void bt_mesh_frnd_adv_deinit(void); #endif /* CONFIG_BLE_MESH_DEINIT */ #endif /* CONFIG_BLE_MESH_FRIEND */ +static ALWAYS_INLINE +uint16_t bt_mesh_adv_buf_count_get(void) +{ + uint16_t adv_count = 2 + CONFIG_BLE_MESH_ADV_BUF_COUNT; + +#if CONFIG_BLE_MESH_EXT_ADV + adv_count += CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT; +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY + adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET + adv_count += CONFIG_BLE_MESH_LONG_PACKET_ADV_BUF_COUNT; +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY + adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + +#if (CONFIG_BLE_MESH_SUPPORT_BLE_ADV && \ + !(CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE)) + adv_count += CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT; +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + + return adv_count; +} + void bt_mesh_adv_task_init(void adv_thread(void *p)); + void bt_mesh_adv_common_init(void); #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_task_deinit(void); + void bt_mesh_adv_common_deinit(void); #endif #if CONFIG_BLE_MESH_USE_BLE_50 -bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id); -bool ble_mesh_adv_task_wait(uint32_t wait_bits, TickType_t timeout, uint32_t *notify); -int ble_mesh_adv_task_wakeup(uint32_t evt); -#else -bool ble_mesh_adv_task_wait(uint32_t timeout); -#endif +int bt_mesh_adv_task_wakeup(uint32_t evt); + +bool bt_mesh_adv_task_wait(uint32_t wait_bits, TickType_t timeout, uint32_t *notify); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ +bool bt_mesh_adv_task_wait(uint32_t timeout); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +static inline void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data, bool front) +{ + bt_mesh_generic_adv_send(buf, 0, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, front); +} + int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, const struct bt_mesh_ble_adv_data *data, uint8_t *index); diff --git a/components/bt/esp_ble_mesh/core/beacon.c b/components/bt/esp_ble_mesh/core/beacon.c index 97ec6ebd8231..32e31f10a97a 100644 --- a/components/bt/esp_ble_mesh/core/beacon.c +++ b/components/bt/esp_ble_mesh/core/beacon.c @@ -27,19 +27,19 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ -#if defined(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) +#if CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL #define UNPROV_BEACON_INTERVAL K_SECONDS(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) -#else +#else /* CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL */ #define UNPROV_BEACON_INTERVAL K_SECONDS(5) -#endif +#endif /* CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL */ #if CONFIG_BLE_MESH_BQB_TEST #define SECURE_BEACON_INTERVAL K_SECONDS(3) -#else +#else /* CONFIG_BLE_MESH_BQB_TEST */ #define SECURE_BEACON_INTERVAL K_SECONDS(10) -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ /* 3 transmissions, 20ms interval */ #define UNPROV_XMIT BLE_MESH_TRANSMIT(2, 20) @@ -58,6 +58,8 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) uint8_t *cache = NULL; int i = 0; + BT_DBG("CacheCheck, PrivateBeacon %u", private_beacon); + subnet_size = bt_mesh_rx_netkey_size(); for (i = 0; i < subnet_size; i++) { @@ -69,11 +71,12 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) #if CONFIG_BLE_MESH_PRIVATE_BEACON cache = private_beacon ? sub->mpb_cache : sub->snb_cache; -#else +#else /* CONFIG_BLE_MESH_PRIVATE_BEACON */ cache = sub->snb_cache; -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ if (!memcmp(cache, data, 21)) { + BT_DBG("BeaconSubFound, NetIdx 0x%04x", sub->net_idx); return sub; } } @@ -83,11 +86,13 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub, bool private_beacon) { + BT_DBG("CacheAdd, NetIdx 0x%04x PrivateBeacon %u", sub->net_idx, private_beacon); + #if CONFIG_BLE_MESH_PRIVATE_BEACON if (private_beacon) { memcpy(sub->mpb_cache, data, 21); } else -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ { memcpy(sub->snb_cache, data, 21); } @@ -98,10 +103,10 @@ static void secure_beacon_complete(int err, void *user_data) struct bt_mesh_subnet *sub = NULL; uint16_t net_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("err %d", err); - net_idx = (uint16_t)NET_IDX_GET(user_data); + BT_DBG("SecureBeaconComplete, NetIdx 0x%04x Err %d", net_idx, err); + /* For node, directly updating the "beacon_sent" timestamp is fine, * since the subnet is pre-allocated. * For Provisioner, before updating the "beacon_sent" timestamp, we @@ -112,6 +117,8 @@ static void secure_beacon_complete(int err, void *user_data) sub = bt_mesh_subnet_get(net_idx); if (sub) { sub->snb_sent = k_uptime_get_32(); + + BT_DBG("SnbSent %lu", sub->snb_sent); } } @@ -121,6 +128,8 @@ void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; + BT_DBG("SecureBeaconCreate"); + net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); if (sub->kr_flag) { @@ -139,10 +148,10 @@ void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, net_buf_simple_add_mem(buf, sub->auth, 8); - BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x flags 0x%02x", - sub->net_idx, bt_mesh.iv_index, flags); - BT_DBG("SNB: NetID %s Auth %s", bt_hex(keys->net_id, 8), - bt_hex(sub->auth, 8)); + BT_DBG("NetIdx 0x%04x IVIndex 0x%08x Flags 0x%02x", + sub->net_idx, bt_mesh.iv_index, flags); + BT_DBG("NetID %s Auth %s", bt_hex(keys->net_id, 8), + bt_hex(sub->auth, 8)); } static int secure_beacon_send(void) @@ -154,6 +163,8 @@ static int secure_beacon_send(void) size_t subnet_size = 0U; int i = 0; + BT_DBG("SecureBeaconSend"); + subnet_size = bt_mesh_rx_netkey_size(); for (i = 0; i < subnet_size; i++) { @@ -165,6 +176,8 @@ static int secure_beacon_send(void) continue; } + BT_DBG("Now %lu SnbSent %lu SnbLast %u", now, sub->snb_sent, sub->snb_last); + time_diff = now - sub->snb_sent; if (time_diff < K_SECONDS(600) && time_diff < BEACON_THRESHOLD(sub->snb_last)) { @@ -178,9 +191,10 @@ static int secure_beacon_send(void) */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT if (bt_mesh_proxy_client_beacon_send(sub, false)) { + BT_DBG("ProxyClientBeaconSend"); continue; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, K_NO_WAIT); if (!buf) { @@ -201,6 +215,7 @@ static int secure_beacon_send(void) * updating its "snb_sent" timestamp. */ bt_mesh_adv_send(buf, SNB_XMIT, &send_cb, NET_IDX_SET(sub->net_idx)); + net_buf_unref(buf); } @@ -214,6 +229,8 @@ static int unprovisioned_beacon_send(void) struct net_buf *buf = NULL; uint16_t oob_info = 0U; + BT_DBG("UnprovisionedBeaconSend"); + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; @@ -252,6 +269,8 @@ static int unprovisioned_beacon_send(void) len = strlen(bt_mesh_prov_get()->uri); + BT_DBG("URI %u: %s", len, bt_mesh_prov_get()->uri); + if (net_buf_tailroom(buf) < len) { BT_WARN("Too long URI to fit advertising data"); } else { @@ -277,6 +296,8 @@ void update_beacon_observation(bool private_beacon) size_t subnet_size = 0U; int i = 0; + BT_DBG("UpdateBeaconObservation, PrivateBeacon %u", private_beacon); + /* Observation period is 20 seconds, whereas the beacon timer * runs every 10 seconds. We process what's happened during * the window only after the second half. @@ -287,13 +308,15 @@ void update_beacon_observation(bool private_beacon) if (private_beacon) { mpb_first_half = !mpb_first_half; if (mpb_first_half) { + BT_DBG("MpbFirstHalf"); return; } } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { snb_first_half = !snb_first_half; if (snb_first_half) { + BT_DBG("SnbFirstHalf"); return; } } @@ -309,11 +332,15 @@ void update_beacon_observation(bool private_beacon) #if CONFIG_BLE_MESH_PRB_SRV if (private_beacon) { + BT_DBG("NetIdx 0x%04x MpbCur %u", sub->net_idx, sub->mpb_cur); + sub->mpb_last = sub->mpb_cur; sub->mpb_cur = 0U; } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { + BT_DBG("NetIdx 0x%04x SnbCur %u", sub->net_idx, sub->snb_cur); + sub->snb_last = sub->snb_cur; sub->snb_cur = 0U; } @@ -330,9 +357,12 @@ static bool ready_to_send(void) static void secure_beacon_send_timeout(struct k_work *work) { + BT_DBG("SecureBeaconSendTimeout"); + /* Don't send anything if we have an active provisioning link */ if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && IS_ENABLED(CONFIG_BLE_MESH_PROV) && bt_mesh_prov_active()) { + BT_DBG("ProvActive"); k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); return; } @@ -345,11 +375,14 @@ static void secure_beacon_send_timeout(struct k_work *work) /* Only resubmit if beaconing is still enabled */ if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED || bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { + BT_DBG("Resubmit, SecureBeacon %u", bt_mesh_secure_beacon_get()); + k_delayed_work_submit(&snb_timer, SECURE_BEACON_INTERVAL); } } else { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { unprovisioned_beacon_send(); + k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); } } @@ -365,6 +398,8 @@ static void secure_beacon_recv(struct net_buf_simple *buf) bool new_key = false; uint8_t flags = 0U; + BT_DBG("SecureBeaconRecv"); + if (buf->len != 21) { BT_ERR("Malformed secure beacon (len %u)", buf->len); return; @@ -384,7 +419,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) iv_index = net_buf_simple_pull_be32(buf); auth = buf->data; - BT_DBG("flags 0x%02x id %s iv_index 0x%08x", + BT_DBG("Flags 0x%02x NetID %s IVIndex 0x%08x", flags, bt_hex(net_id, 8), iv_index); sub = bt_mesh_subnet_find_with_snb(net_id, flags, iv_index, auth, &new_key); @@ -393,6 +428,9 @@ static void secure_beacon_recv(struct net_buf_simple *buf) return; } + BT_DBG("NetIdx 0x%04x KrPhase %u NewKey %u", + sub->net_idx, sub->kr_phase, new_key); + if (sub->kr_phase == BLE_MESH_KR_PHASE_2 && !new_key) { BT_WARN("Ignoring Phase 2 KR Update secured using old key"); return; @@ -417,8 +455,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) goto update_stats; } - BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x current iv_index 0x%08x", - sub->net_idx, iv_index, bt_mesh.iv_index); + BT_DBG("IVIndex 0x%08lx CurIVIndex 0x%08lx", iv_index, bt_mesh.iv_index); if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == @@ -452,6 +489,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) update_stats: if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED && sub->snb_cur < 0xff) { + BT_DBG("SnbCurInc %u", sub->snb_cur); sub->snb_cur++; } } @@ -460,7 +498,8 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) { uint8_t type = 0U; - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("BeaconRecv"); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1) { BT_ERR("Too short beacon"); @@ -470,7 +509,7 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) type = net_buf_simple_pull_u8(buf); switch (type) { case BEACON_TYPE_UNPROVISIONED: - BT_DBG("Unprovisioned device beacon received"); + BT_DBG("UnprovDevBeaconRecv, Rssi %d", rssi); if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && @@ -480,11 +519,16 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_is_provisioned()) { - const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + const bt_mesh_addr_t *addr = NULL; + + addr = bt_mesh_get_unprov_dev_addr(); + assert(addr); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ break; case BEACON_TYPE_SECURE: secure_beacon_recv(buf); @@ -493,7 +537,7 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) case BEACON_TYPE_PRIVATE: bt_mesh_private_beacon_recv(buf); break; -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ default: BT_DBG("Unknown beacon type 0x%02x", type); break; @@ -514,7 +558,7 @@ void bt_mesh_beacon_init(void) BT_ERR("Failed to create a mpb_timer"); return; } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } #if CONFIG_BLE_MESH_DEINIT @@ -532,24 +576,28 @@ void bt_mesh_beacon_deinit(void) void bt_mesh_beacon_ivu_initiator(bool enable) { + BT_DBG("BeaconIVUInitiator, IVUInitiator %u", enable); + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_INITIATOR, enable); if (enable) { k_delayed_work_submit(&snb_timer, K_NO_WAIT); + #if CONFIG_BLE_MESH_PRB_SRV if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_timer_submit(K_NO_WAIT); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } else { if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_DISABLED) { k_delayed_work_cancel(&snb_timer); } + #if CONFIG_BLE_MESH_PRB_SRV if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_DISABLED) { bt_mesh_private_beacon_timer_cancel(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } } @@ -558,8 +606,12 @@ void bt_mesh_secure_beacon_enable(void) size_t subnet_size = 0U; int i = 0; + BT_DBG("SecureBeaconEnable"); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && !bt_mesh_is_provisioned()) { + BT_DBG("NodeNotProvisioned"); + k_delayed_work_submit(&snb_timer, K_NO_WAIT); return; } @@ -584,6 +636,9 @@ void bt_mesh_secure_beacon_enable(void) void bt_mesh_secure_beacon_disable(void) { + BT_DBG("SecureBeaconDisable, IVUInitiator %u", + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { k_delayed_work_cancel(&snb_timer); } diff --git a/components/bt/esp_ble_mesh/core/ble_adv.c b/components/bt/esp_ble_mesh/core/ble_adv.c index 110e52e2204a..aaaa4b429060 100644 --- a/components/bt/esp_ble_mesh/core/ble_adv.c +++ b/components/bt/esp_ble_mesh/core/ble_adv.c @@ -14,14 +14,14 @@ #include "mesh/common.h" #include "mesh/buf.h" -#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV #if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE /* Use independent ble adv queue only if multi adv instance is used */ static struct bt_mesh_adv_queue ble_adv_queue; static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); #endif + static struct bt_mesh_adv_queue *p_ble_adv_queue; -#define BLE_MESH_BLE_ADV_QUEUE_SIZE (CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT + 1) + /* length + advertising data + length + scan response data */ NET_BUF_POOL_DEFINE(ble_adv_buf_pool, CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT, ((BLE_MESH_ADV_DATA_SIZE + 3) << 1), BLE_MESH_ADV_USER_DATA_SIZE, NULL); @@ -30,10 +30,11 @@ static struct bt_mesh_adv ble_adv_pool[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; static struct bt_mesh_ble_adv_tx ble_adv_tx[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; -#define SEND_BLE_ADV_INFINITE 0xFFFF +#define SEND_BLE_ADV_INFINITE 0xFFFF static struct bt_mesh_adv *ble_adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("BLEAdvAlloc, ID %d", id); memset(&ble_adv_pool[id], 0, sizeof(struct bt_mesh_adv)); ble_adv_pool[id].type = type; return &ble_adv_pool[id]; @@ -43,7 +44,7 @@ static struct bt_mesh_adv *ble_adv_alloc(int id, enum bt_mesh_adv_type type) /* A separate post function is required only when using a separate queue */ static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { - BT_DBG("%s", __func__); + BT_DBG("BLETaskPost, Front %u", front); if (p_ble_adv_queue->q.handle == NULL) { BT_ERR("Invalid adv queue"); @@ -64,20 +65,12 @@ static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool fro } #endif -static struct net_buf *bt_mesh_ble_adv_create(enum bt_mesh_adv_type type, int32_t timeout) -{ - return bt_mesh_adv_create_from_pool(type, timeout); -} - -inline void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data, bool front) -{ - bt_mesh_generic_adv_send(buf, 0, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, front); -} - static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) { + BT_DBG("BLEAdvTxReset, Unref %u", unref); + if (tx->buf == NULL) { + BT_DBG("NullTxBuf"); return; } @@ -85,7 +78,13 @@ static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) k_delayed_work_free(&tx->resend); } bt_mesh_atomic_set(tx->flags, 0); + memset(&tx->param, 0, sizeof(tx->param)); + + BT_DBG("Buf %p Ref %u Busy %u", + tx->buf, tx->buf->ref, + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf))); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0); if (unref) { net_buf_unref(tx->buf); @@ -97,7 +96,7 @@ static void ble_adv_send_start(uint16_t duration, int err, void *cb_data) { struct bt_mesh_ble_adv_tx *tx = cb_data; - BT_DBG("%s, duration %d, err %d", __func__, duration, err); + BT_DBG("BLEAdvSendStart, Duration %u Err %d", duration, err); /* If failed to send BLE adv packet, and param->count is not 0 * which means the timer has been initialized, here we need to @@ -112,13 +111,15 @@ static void ble_adv_send_end(int err, void *cb_data) { struct bt_mesh_ble_adv_tx *tx = cb_data; - BT_DBG("%s, err %d", __func__, err); + BT_DBG("BLEAdvSendEnd, Err %d", err); if (err) { ble_adv_tx_reset(tx, true); return; } + BT_DBG("Count %u Period %u", tx->param.count, tx->param.period); + if (tx->param.count) { if (tx->param.period) { k_delayed_work_submit(&tx->resend, tx->param.period); @@ -140,12 +141,18 @@ static void ble_adv_resend(struct k_work *work) struct bt_mesh_ble_adv_tx *tx = CONTAINER_OF(work, struct bt_mesh_ble_adv_tx, resend.work); bool front = false; + BT_DBG("BLEAdvResend"); + if (tx->buf == NULL) { /* The advertising has been cancelled */ + BT_INFO("%s, cancelled", __func__); return; } + BT_DBG("Priority %u Count %u Buf %p", tx->param.priority, tx->param.count, tx->buf); + front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; + bt_mesh_ble_adv_send(tx->buf, &ble_adv_send_cb, tx, front); if (tx->param.count == SEND_BLE_ADV_INFINITE) { @@ -165,6 +172,8 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, struct net_buf *buf = NULL; bool front = false; + BT_DBG("StartBLEAdv"); + if (param == NULL || index == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -211,12 +220,18 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, return -EINVAL; } - buf = bt_mesh_ble_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); if (!buf) { BT_ERR("No empty ble adv buffer"); return -ENOBUFS; } + BT_DBG("AdvType 0x%02x Interval 0x%04x AddrType 0x%02x/0x%02x", + param->adv_type, param->interval, param->own_addr_type, param->peer_addr_type); + BT_DBG("DataLen %u/%u Priority %u Count %u Duration %u", + (data ? data->adv_data_len : 0), (data ? data->scan_rsp_data_len : 0), + param->priority, param->count, param->duration); + /* Set advertising data and scan response data */ memset(buf->data, 0, buf->size); if (data) { @@ -237,6 +252,7 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; bt_mesh_ble_adv_send(buf, &ble_adv_send_cb, tx, front); + if (param->count) { if (k_delayed_work_init(&tx->resend, ble_adv_resend)) { /* If failed to create a timer, the BLE adv packet will be @@ -244,10 +260,12 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, * BLE adv packet can be sent, return 0 here. */ BT_WARN("Send BLE adv packet only once"); + tx->param.count = 0; net_buf_unref(buf); return 0; } + bt_mesh_atomic_set_bit(tx->flags, TIMER_INIT); } else { /* Send the BLE advertising packet only once */ @@ -262,6 +280,8 @@ int bt_mesh_stop_ble_advertising(uint8_t index) struct bt_mesh_ble_adv_tx *tx = NULL; bool unref = true; + BT_DBG("StopBLEAdv, Index %u", index); + if (index >= ARRAY_SIZE(ble_adv_tx)) { BT_ERR("Invalid adv index %d", index); return -EINVAL; @@ -274,6 +294,10 @@ int bt_mesh_stop_ble_advertising(uint8_t index) return 0; } + BT_DBG("Busy %u Ref %u", + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)), + tx->buf->ref); + /* busy 1, ref 1; busy 1, ref 2; * busy 0, ref 0; busy 0, ref 1; */ @@ -299,16 +323,17 @@ struct bt_mesh_adv_queue *bt_mesh_ble_adv_queue_get(void) void bt_mesh_ble_adv_init(void) { + BT_DBG("BLEAdvInit"); p_ble_adv_queue = bt_mesh_ble_adv_queue_get(); bt_mesh_adv_type_init(BLE_MESH_ADV_BLE, p_ble_adv_queue, &ble_adv_buf_pool, ble_adv_alloc); #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - bt_mesh_adv_inst_init(BLE_MESH_BLE_ADV_INS, CONFIG_BLE_MESH_BLE_ADV_INST_ID); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_BLE_ADV_INS, BLE_MESH_ADV_BLE); -#else + bt_mesh_adv_inst_init(BLE_MESH_BLE_ADV_INST, CONFIG_BLE_MESH_BLE_ADV_INST_ID); + bt_mesh_adv_inst_type_add(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); +#else /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_BLE); -#endif + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } @@ -316,10 +341,12 @@ void bt_mesh_ble_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_ble_adv_deinit(void) { + BT_DBG("BLEAdvDeinit"); + for (int i = 0; i < ARRAY_SIZE(ble_adv_tx); i++) { - struct bt_mesh_ble_adv_tx *tx = &ble_adv_tx[i]; - ble_adv_tx_reset(tx, false); + ble_adv_tx_reset(&ble_adv_tx[i], false); } + bt_mesh_unref_buf_from_pool(&ble_adv_buf_pool); memset(ble_adv_pool, 0, sizeof(ble_adv_pool)); @@ -329,16 +356,16 @@ void bt_mesh_ble_adv_deinit(void) bt_mesh_adv_queue_deinit(p_ble_adv_queue); #endif bt_mesh_adv_type_deinit(BLE_MESH_ADV_BLE); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - bt_mesh_adv_inst_deinit(BLE_MESH_BLE_ADV_INS); - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_BLE_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_deinit(BLE_MESH_BLE_ADV_INST); + bt_mesh_adv_inst_type_rem(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); #endif #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } #endif /* CONFIG_BLE_MESH_DEINIT */ -#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index fd42502fdaf6..e31d4186e70f 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -396,11 +396,11 @@ void ble_mesh_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, goto transfer_to_user; } #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(params->adv_term.adv_handle)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(params->adv_term.adv_handle)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ if (params->adv_term.status == 0x43 || /* Limit reached */ params->adv_term.status == 0x3C) { /* Advertising timeout */ - ble_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); + bt_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -423,7 +423,7 @@ void ble_mesh_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, * could lead to resource contention issues. */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); + bt_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -655,7 +655,7 @@ static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARC static struct { bool set; tBTA_DM_BLE_GAP_EXT_ADV_PARAMS param; -} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; +} last_param[BLE_MESH_ADV_INST_TYPES_NUM]; int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, @@ -1615,7 +1615,7 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) svc->attrs[i].handle = char_handle - 1; svc->attrs[i + 1].handle = char_handle; BT_DBG("Add characteristic, uuid 0x%04x, handle %d, perm %d, properties %d", - BLE_MESH_UUID_16(gatts_chrc->uuid)->val, char_handle, svc->attrs[i + 1].perm, gatts_chrc->properties); + BLE_MESH_UUID_16(gatts_chrc->uuid)->val, char_handle, svc->attrs[i + 1].perm, gatts_chrc->properties); break; } case BLE_MESH_UUID_GATT_CEP_VAL: @@ -1803,7 +1803,7 @@ uint16_t bt_mesh_gattc_get_service_uuid(struct bt_mesh_conn *conn) int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) { - tBTA_BLE_CONN_PARAMS conn_1m_param = {0}; + tBTA_BLE_CONN_PARAMS conn_1m_param = {0}; uint8_t zero[6] = {0}; int i; @@ -1872,9 +1872,10 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) conn_1m_param.max_ce_len = 0; BTA_GATTC_Enh_Open(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr.val, - bt_mesh_gattc_info[i].addr.type, true, BTA_GATT_TRANSPORT_LE, TRUE, BLE_ADDR_UNKNOWN_TYPE, - BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); -#else + bt_mesh_gattc_info[i].addr.type, true, + BTA_GATT_TRANSPORT_LE, TRUE, BLE_ADDR_UNKNOWN_TYPE, + BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ /* Min_interval: 15ms * Max_interval: 15ms * Slave_latency: 0x0 @@ -1886,9 +1887,10 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) conn_1m_param.supervision_timeout = 0x64; BTA_GATTC_Enh_Open(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr.val, - bt_mesh_gattc_info[i].addr.type, true, BTA_GATT_TRANSPORT_LE, FALSE, BLE_ADDR_UNKNOWN_TYPE, - BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); -#endif + bt_mesh_gattc_info[i].addr.type, true, + BTA_GATT_TRANSPORT_LE, FALSE, BLE_ADDR_UNKNOWN_TYPE, + BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ return 0; } diff --git a/components/bt/esp_ble_mesh/core/cfg_cli.c b/components/bt/esp_ble_mesh/core/cfg_cli.c index 3aedd3644b8a..211f80e9edfc 100644 --- a/components/bt/esp_ble_mesh/core/cfg_cli.c +++ b/components/bt/esp_ble_mesh/core/cfg_cli.c @@ -110,6 +110,8 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, struct net_buf_simple buf = {0}; uint8_t evt_type = 0xFF; + BT_DBG("CfgClientRecvStatus"); + if (!model || !ctx) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -125,6 +127,8 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, if (!node) { BT_DBG("Unexpected Config Status 0x%04x", ctx->recv_op); } else { + BT_DBG("OpCode 0x%08lx RecvOp 0x%08lx", node->opcode, ctx->recv_op); + switch (node->opcode) { case OP_BEACON_GET: case OP_COMP_DATA_GET: @@ -230,9 +234,10 @@ static void comp_data_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_comp_data_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("CompDataStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.page = net_buf_simple_pull_u8(buf); status.comp_data = bt_mesh_alloc_buf(buf->len); @@ -252,9 +257,10 @@ static void state_status_u8(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("StateStatusU8"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -265,6 +271,8 @@ static void beacon_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("BeaconStatus"); + state_status_u8(model, ctx, buf); } @@ -272,6 +280,8 @@ static void ttl_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("TTLStatus"); + state_status_u8(model, ctx, buf); } @@ -279,6 +289,8 @@ static void friend_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("FrndStatus"); + state_status_u8(model, ctx, buf); } @@ -286,6 +298,8 @@ static void gatt_proxy_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("GattProxyStatus"); + state_status_u8(model, ctx, buf); } @@ -295,9 +309,10 @@ static void relay_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_relay_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelayStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.relay = net_buf_simple_pull_u8(buf); status.retransmit = net_buf_simple_pull_u8(buf); @@ -311,9 +326,10 @@ static void net_key_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_netkey_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetKeyStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf) & 0xfff; @@ -327,9 +343,10 @@ static void app_key_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_appkey_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("AppKeyStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &status.net_idx, &status.app_idx); @@ -343,9 +360,10 @@ static void mod_app_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_app_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModAppStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -366,9 +384,10 @@ static void mod_pub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_pub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModPubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -395,9 +414,10 @@ static void mod_sub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_sub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModSubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -418,9 +438,10 @@ static void hb_sub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_hb_sub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HbSubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.src = net_buf_simple_pull_le16(buf); @@ -439,9 +460,10 @@ static void hb_pub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_hb_pub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HbPubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.dst = net_buf_simple_pull_le16(buf); @@ -458,9 +480,10 @@ static void node_reset_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeResetStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); cfg_client_recv_status(model, ctx, NULL, 0); } @@ -471,9 +494,10 @@ static void mod_sub_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_sub_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModSubList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -500,9 +524,10 @@ static void net_key_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_net_key_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetKeyList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.net_idx = bt_mesh_alloc_buf(buf->len); if (!list.net_idx) { @@ -520,9 +545,10 @@ static void app_key_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_app_key_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("AppKeyList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.net_idx = net_buf_simple_pull_le16(buf); @@ -542,9 +568,10 @@ static void node_id_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_node_id_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIDStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -559,9 +586,10 @@ static void mod_app_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_app_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModAppList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -588,9 +616,10 @@ static void kr_phase_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_key_refresh_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("KrPhaseStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -605,9 +634,10 @@ static void lpn_pollto_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_lpn_pollto_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("LPNPollToStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.lpn_addr = net_buf_simple_pull_le16(buf); status.timeout = net_buf_simple_pull_u8(buf); @@ -621,6 +651,8 @@ static void net_trans_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("NetTransStatus"); + state_status_u8(model, ctx, buf); } @@ -656,6 +688,9 @@ static int send_msg_with_none(bt_mesh_client_common_param_t *param, uint32_t op) { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 0); + BT_DBG("SendMsgWithNone"); + BT_DBG("Dst 0x%04x Op 0x%08lx", param->ctx.addr, op); + bt_mesh_model_msg_init(&msg, op); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -665,6 +700,9 @@ static int send_msg_with_u8(bt_mesh_client_common_param_t *param, uint32_t op, u { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 1); + BT_DBG("SendMsgWithU8"); + BT_DBG("Dst 0x%04x Op 0x%08lx Val 0x%02x", param->ctx.addr, op, val); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_u8(&msg, val); @@ -675,6 +713,9 @@ static int send_msg_with_le16(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 2); + BT_DBG("SendMsgWithLE16"); + BT_DBG("Dst 0x%04x Op 0x%08lx Val 0x%04x", param->ctx.addr, op, val); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, val); @@ -683,55 +724,76 @@ static int send_msg_with_le16(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_comp_data_get(bt_mesh_client_common_param_t *param, uint8_t page) { + BT_DBG("CompDataGet, Page %u", page); + return send_msg_with_u8(param, OP_COMP_DATA_GET, page); } int bt_mesh_cfg_beacon_get(bt_mesh_client_common_param_t *param) { + BT_DBG("BeaconGet"); + return send_msg_with_none(param, OP_BEACON_GET); } int bt_mesh_cfg_beacon_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("BeaconSet, Val 0x%02x", val); + if (val > 0x01) { BT_ERR("Invalid beacon state 0x%02x", val); return -EINVAL; } + return send_msg_with_u8(param, OP_BEACON_SET, val); } int bt_mesh_cfg_ttl_get(bt_mesh_client_common_param_t *param) { + BT_DBG("TTLGet"); + return send_msg_with_none(param, OP_DEFAULT_TTL_GET); } int bt_mesh_cfg_ttl_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("TTLSet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_DEFAULT_TTL_SET, val); } int bt_mesh_cfg_friend_get(bt_mesh_client_common_param_t *param) { + BT_DBG("FrndGet"); + return send_msg_with_none(param, OP_FRIEND_GET); } int bt_mesh_cfg_friend_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("FrndSet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_FRIEND_SET, val); } int bt_mesh_cfg_gatt_proxy_get(bt_mesh_client_common_param_t *param) { + BT_DBG("GattProxyGet"); + return send_msg_with_none(param, OP_GATT_PROXY_GET); } int bt_mesh_cfg_gatt_proxy_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("GattProxySet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_GATT_PROXY_SET, val); } int bt_mesh_cfg_relay_get(bt_mesh_client_common_param_t *param) { + BT_DBG("RelayGet"); + return send_msg_with_none(param, OP_RELAY_GET); } @@ -740,6 +802,8 @@ int bt_mesh_cfg_relay_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_SET, 2); + BT_DBG("RelaySet, Relay 0x%02x Retransmit 0x%02x", relay, retransmit); + bt_mesh_model_msg_init(&msg, OP_RELAY_SET); net_buf_simple_add_u8(&msg, relay); net_buf_simple_add_u8(&msg, retransmit); @@ -752,11 +816,15 @@ int bt_mesh_cfg_net_key_add(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_ADD, 18); + BT_DBG("NetKeyAdd"); + if (!net_key) { BT_ERR("Invalid NetKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x NetKey %s", net_idx, bt_hex(net_key, 16)); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_ADD); net_buf_simple_add_le16(&msg, net_idx); net_buf_simple_add_mem(&msg, net_key, 16); @@ -770,11 +838,16 @@ int bt_mesh_cfg_app_key_add(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_ADD, 19); + BT_DBG("AppKeyAdd"); + if (!app_key) { BT_ERR("Invalid AppKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x AppKey %s", + net_idx, app_idx, bt_hex(app_key, 16)); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_ADD); key_idx_pack(&msg, net_idx, app_idx); net_buf_simple_add_mem(&msg, app_key, 16); @@ -788,6 +861,10 @@ int bt_mesh_cfg_mod_app_bind(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_BIND, 8); + BT_DBG("ModAppBind"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, app_idx, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_APP_BIND); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, app_idx); @@ -805,6 +882,10 @@ static int mod_sub(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 8); + BT_DBG("ModSub"); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, sub_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, sub_addr); @@ -820,6 +901,8 @@ int bt_mesh_cfg_mod_sub_add(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubAdd"); + return mod_sub(param, OP_MOD_SUB_ADD, elem_addr, sub_addr, mod_id, cid); } @@ -827,6 +910,8 @@ int bt_mesh_cfg_mod_sub_del(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubDel"); + return mod_sub(param, OP_MOD_SUB_DEL, elem_addr, sub_addr, mod_id, cid); } @@ -834,6 +919,8 @@ int bt_mesh_cfg_mod_sub_overwrite(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubOverwrite"); + return mod_sub(param, OP_MOD_SUB_OVERWRITE, elem_addr, sub_addr, mod_id, cid); } @@ -843,13 +930,15 @@ static int mod_sub_va(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 22); + BT_DBG("ModSubVa"); + if (!label) { BT_ERR("Invalid label uuid"); return -EINVAL; } - BT_DBG("elem_addr 0x%04x label %s", elem_addr, bt_hex(label, 16)); - BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + BT_DBG("Label %s", bt_hex(label, 16)); bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, elem_addr); @@ -866,6 +955,8 @@ int bt_mesh_cfg_mod_sub_va_add(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaAdd"); + return mod_sub_va(param, OP_MOD_SUB_VA_ADD, elem_addr, label, mod_id, cid); } @@ -873,6 +964,8 @@ int bt_mesh_cfg_mod_sub_va_del(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaDel"); + return mod_sub_va(param, OP_MOD_SUB_VA_DEL, elem_addr, label, mod_id, cid); } @@ -880,6 +973,8 @@ int bt_mesh_cfg_mod_sub_va_overwrite(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaOverwrite"); + return mod_sub_va(param, OP_MOD_SUB_VA_OVERWRITE, elem_addr, label, mod_id, cid); } @@ -888,6 +983,9 @@ int bt_mesh_cfg_mod_pub_get(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_GET, 6); + BT_DBG("ModPubGet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_GET); net_buf_simple_add_le16(&msg, elem_addr); if (cid != BLE_MESH_CID_NVAL) { @@ -904,11 +1002,17 @@ int bt_mesh_cfg_mod_pub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_SET, 13); + BT_DBG("ModPubSet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (!pub) { BT_ERR("Invalid model pub set"); return -EINVAL; } + BT_DBG("Addr 0x%04x AppIdx 0x%04x TTL %u Period 0x%02x Transmit 0x%02x", + pub->addr, pub->app_idx, pub->ttl, pub->period, pub->transmit); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_SET); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, pub->addr); @@ -929,11 +1033,15 @@ int bt_mesh_cfg_hb_sub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_SET, 5); + BT_DBG("HbSubSet"); + if (!sub) { BT_ERR("Invalid heartbeat sub set"); return -EINVAL; } + BT_DBG("Src 0x%04x Dst 0x%04x Period 0x%02x", sub->src, sub->dst, sub->period); + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_SET); net_buf_simple_add_le16(&msg, sub->src); net_buf_simple_add_le16(&msg, sub->dst); @@ -944,6 +1052,8 @@ int bt_mesh_cfg_hb_sub_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_hb_sub_get(bt_mesh_client_common_param_t *param) { + BT_DBG("HbSubGet"); + return send_msg_with_none(param, OP_HEARTBEAT_SUB_GET); } @@ -952,11 +1062,16 @@ int bt_mesh_cfg_hb_pub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_SET, 9); + BT_DBG("HbPubSet"); + if (!pub) { BT_ERR("Invalid heartbeat pub set"); return -EINVAL; } + BT_DBG("Dst 0x%04x Count 0x%02x Period 0x%02x TTL %u Feat 0x%04x NetIdx 0x%04x", + pub->dst, pub->count, pub->period, pub->ttl, pub->feat, pub->net_idx); + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_SET); net_buf_simple_add_le16(&msg, pub->dst); net_buf_simple_add_u8(&msg, pub->count); @@ -970,11 +1085,15 @@ int bt_mesh_cfg_hb_pub_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_hb_pub_get(bt_mesh_client_common_param_t *param) { + BT_DBG("HbPubGet"); + return send_msg_with_none(param, OP_HEARTBEAT_PUB_GET); } int bt_mesh_cfg_node_reset(bt_mesh_client_common_param_t *param) { + BT_DBG("NodeReset"); + return send_msg_with_none(param, OP_NODE_RESET); } @@ -985,11 +1104,18 @@ int bt_mesh_cfg_mod_pub_va_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_VA_SET, 27); + BT_DBG("ModPubVaSet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (!label || !pub) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + BT_DBG("Label %s", bt_hex(label, 16)); + BT_DBG("AppIdx 0x%04x TTL %u Period 0x%02x Transmit 0x%02x", + pub->app_idx, pub->ttl, pub->period, pub->transmit); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_VA_SET); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_mem(&msg, label, 16); @@ -1010,6 +1136,9 @@ int bt_mesh_cfg_mod_sub_del_all(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_DEL_ALL, 6); + BT_DBG("ModSubDelAll"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_DEL_ALL); net_buf_simple_add_le16(&msg, elem_addr); if (cid != BLE_MESH_CID_NVAL) { @@ -1038,12 +1167,18 @@ static int mod_sub_get(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_mod_sub_get(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id) { + BT_DBG("ModSubGet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x", elem_addr, mod_id); + return mod_sub_get(param, OP_MOD_SUB_GET, elem_addr, mod_id, BLE_MESH_CID_NVAL); } int bt_mesh_cfg_mod_sub_get_vnd(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubGetVnd"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (cid == BLE_MESH_CID_NVAL) { BT_ERR("Invalid company id"); return -EINVAL; @@ -1056,11 +1191,15 @@ int bt_mesh_cfg_net_key_update(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_UPDATE, 18); + BT_DBG("NetKeyUpdate"); + if (!net_key) { BT_ERR("Invalid NetKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x NetKey %s", net_idx, bt_hex(net_key, 16)); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_UPDATE); net_buf_simple_add_le16(&msg, net_idx); net_buf_simple_add_mem(&msg, net_key, 16); @@ -1070,11 +1209,15 @@ int bt_mesh_cfg_net_key_update(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_net_key_delete(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("NetKeyDelete, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_NET_KEY_DEL, net_idx); } int bt_mesh_cfg_net_key_get(bt_mesh_client_common_param_t *param) { + BT_DBG("NetKeyGet"); + return send_msg_with_none(param, OP_NET_KEY_GET); } @@ -1084,11 +1227,16 @@ int bt_mesh_cfg_app_key_update(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_UPDATE, 19); + BT_DBG("AppKeyUpdate"); + if (!app_key) { BT_ERR("Invalid AppKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x AppKey %s", + net_idx, app_idx, bt_hex(app_key, 16)); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_UPDATE); key_idx_pack(&msg, net_idx, app_idx); net_buf_simple_add_mem(&msg, app_key, 16); @@ -1101,6 +1249,8 @@ int bt_mesh_cfg_app_key_delete(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_DEL, 3); + BT_DBG("AppKeyDelete, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_DEL); key_idx_pack(&msg, net_idx, app_idx); @@ -1109,11 +1259,15 @@ int bt_mesh_cfg_app_key_delete(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_app_key_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("AppKeyGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_APP_KEY_GET, net_idx); } int bt_mesh_cfg_node_identity_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("NodeIdentityGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_NODE_IDENTITY_GET, net_idx); } @@ -1122,6 +1276,8 @@ int bt_mesh_cfg_node_identity_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_IDENTITY_SET, 3); + BT_DBG("NodeIdentitySet, NetIdx 0x%04x Identity 0x%02x", net_idx, identity); + if (identity > 0x02) { BT_ERR("Invalid node identity 0x%02x", identity); return -EINVAL; @@ -1140,6 +1296,10 @@ int bt_mesh_cfg_mod_app_unbind(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_UNBIND, 8); + BT_DBG("ModAppUnbind"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, app_idx, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_APP_UNBIND); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, app_idx); @@ -1169,21 +1329,29 @@ static int mod_app_get(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_mod_app_get(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id) { + BT_DBG("ModAppGet, ElemAddr 0x%04x ModID 0x%04x", elem_addr, mod_id); + return mod_app_get(param, OP_SIG_MOD_APP_GET, elem_addr, mod_id, BLE_MESH_CID_NVAL); } int bt_mesh_cfg_mod_app_get_vnd(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModAppGetVnd"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (cid == BLE_MESH_CID_NVAL) { BT_ERR("Invalid company id"); return -EINVAL; } + return mod_app_get(param, OP_VND_MOD_APP_GET, elem_addr, mod_id, cid); } int bt_mesh_cfg_kr_phase_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("KrPhaseGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_KRP_GET, net_idx); } @@ -1192,6 +1360,8 @@ int bt_mesh_cfg_kr_phase_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_KRP_SET, 3); + BT_DBG("KrPhaseSet, NetIdx 0x%04x Transition 0x%02x", net_idx, transition); + if (transition > 0x03) { BT_ERR("Invalid kr phase transition 0x%02x", transition); return -EINVAL; @@ -1206,16 +1376,22 @@ int bt_mesh_cfg_kr_phase_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_lpn_timeout_get(bt_mesh_client_common_param_t *param, uint16_t lpn_addr) { + BT_DBG("LPNTimeoutGet, LPN 0x%04x", lpn_addr); + return send_msg_with_le16(param, OP_LPN_TIMEOUT_GET, lpn_addr); } int bt_mesh_cfg_net_transmit_get(bt_mesh_client_common_param_t *param) { + BT_DBG("NetTransmitGet"); + return send_msg_with_none(param, OP_NET_TRANSMIT_GET); } int bt_mesh_cfg_net_transmit_set(bt_mesh_client_common_param_t *param, uint8_t transmit) { + BT_DBG("NetTransmitSet, Transmit 0x%02x", transmit); + return send_msg_with_u8(param, OP_NET_TRANSMIT_SET, transmit); } @@ -1224,6 +1400,8 @@ static int cfg_cli_init(struct bt_mesh_model *model) config_internal_data_t *internal = NULL; bt_mesh_config_client_t *client = NULL; + BT_DBG("CfgCliInit"); + if (!model) { BT_ERR("Invalid Configuration Client model"); return -EINVAL; @@ -1271,6 +1449,8 @@ static int cfg_cli_deinit(struct bt_mesh_model *model) { bt_mesh_config_client_t *client = NULL; + BT_DBG("CfgCliDeinit"); + if (!model) { BT_ERR("Invalid Configuration Client model"); return -EINVAL; diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index fe605939a549..9be3e5198343 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -32,7 +32,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define DEFAULT_TTL 7 @@ -66,6 +66,9 @@ static uint8_t bt_mesh_comp_page_check(uint8_t page, bool largest) static inline uint16_t get_comp_elem_size(struct bt_mesh_elem *elem) { + BT_DBG("GetCompElemSize, ModelCount %u VndModelCount %u", + elem->model_count, elem->vnd_model_count); + return (4 + elem->model_count * 2 + elem->vnd_model_count * 4); } @@ -77,6 +80,8 @@ static uint16_t get_comp_data_size(const struct bt_mesh_comp *comp) size += get_comp_elem_size(&(comp->elem[i])); } + BT_DBG("GetCompDataSize, Size %u", size); + return size; } @@ -119,6 +124,7 @@ static void get_comp_data(struct net_buf_simple *buf, */ if (full_element && net_buf_simple_tailroom(buf) < get_comp_elem_size(elem)) { + BT_WARN("NoRoomForElementModelList"); return; } @@ -137,6 +143,8 @@ static void get_comp_data(struct net_buf_simple *buf, net_buf_simple_add_le16(buf, model->vnd.id); } } + + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); } static int fetch_comp_data(struct net_buf_simple *buf, @@ -155,7 +163,7 @@ static int fetch_comp_data(struct net_buf_simple *buf, if (net_buf_simple_tailroom(buf) < 10 || size - offset > net_buf_simple_tailroom(buf)) { BT_ERR("Too small buffer for comp data %d, %d, expected %d", - page, buf->size, size - offset); + page, buf->size, size - offset); return -EINVAL; } @@ -183,6 +191,9 @@ static int bt_mesh_get_comp_data(struct net_buf_simple *buf, uint8_t page, uint16_t offset, bool full_element) { + BT_DBG("FetchCompData, Page %u Offset %u FullElement %u", + page, offset, full_element); + if (page == 0) { return fetch_comp_data(buf, comp_0, page, offset, full_element); } @@ -199,9 +210,10 @@ static void comp_data_get(struct bt_mesh_model *model, struct net_buf_simple *sdu = NULL; uint8_t page = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("CompDataGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); /* TODO: * @@ -268,14 +280,17 @@ static void comp_data_get(struct bt_mesh_model *model, } static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, - struct net_buf_simple *buf, bool *vnd) + struct net_buf_simple *buf, + bool *vnd) { uint16_t company = 0U, id = 0U; + BT_DBG("GetModel, Len %u", buf->len); + if (buf->len < 4) { id = net_buf_simple_pull_le16(buf); - BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); + BT_DBG("ID 0x%04x ElemAddr 0x%04x", id, elem->addr); *vnd = false; @@ -285,42 +300,49 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, company = net_buf_simple_pull_le16(buf); id = net_buf_simple_pull_le16(buf); - BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, - elem->addr); + BT_DBG("CID 0x%04x ID 0x%04x Addr 0x%04x", company, id, elem->addr); *vnd = true; return bt_mesh_model_find_vnd(elem, company, id); } -static bool mod_pub_app_key_bound(struct bt_mesh_model *model, - uint16_t app_idx) +static bool mod_pub_app_key_bound(struct bt_mesh_model *model, uint16_t app_idx) { int i; + BT_DBG("ModPubAppKeyBound, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == app_idx) { return true; } } - BT_ERR("AppKey(0x%02x) not bound to this model", app_idx); + BT_ERR("AppKeyNotBound, AppIdx 0x%04x", app_idx); return false; } static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, - uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, - uint8_t retransmit, bool store) + uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, + uint8_t period, uint8_t retransmit, bool store) { + BT_DBG("_ModPubSet"); + BT_DBG("Addr 0x%04x AppIdx 0x%04x TTL %u Period 0x%02x Retransmit 0x%02x Store %u", + pub_addr, app_idx, ttl, period, retransmit, store); + if (!model->pub) { + BT_DBG("StatusNvalPubParam"); return STATUS_NVAL_PUB_PARAM; } if (!IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && cred_flag) { + BT_DBG("StatusFeatNotSupp"); return STATUS_FEAT_NOT_SUPP; } if (!model->pub->update && period) { + BT_DBG("StatusNvalPubParam"); return STATUS_NVAL_PUB_PARAM; } @@ -353,6 +375,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, */ if (!bt_mesh_app_key_get(app_idx) || !mod_pub_app_key_bound(model, app_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -367,7 +390,8 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, int32_t period_ms; period_ms = bt_mesh_model_pub_period_get(model); - BT_DBG("period %u ms", period_ms); + + BT_DBG("PubPeriod %ld", period_ms); if (period_ms) { k_delayed_work_submit(&model->pub->timer, period_ms); @@ -387,9 +411,10 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) { int i; - BT_DBG("model %p key_idx 0x%03x", model, key_idx); + BT_DBG("ModBind, KeyIdx 0x%04x", key_idx); if (!bt_mesh_app_key_get(key_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -412,6 +437,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) } } + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } @@ -419,9 +445,10 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st { int i; - BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); + BT_DBG("ModUnbind, KeyIdx 0x%04x Store %u", key_idx, store); if (!bt_mesh_app_key_get(key_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -449,6 +476,8 @@ struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx) { int i; + BT_DBG("AppKeyAlloc, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; @@ -457,31 +486,36 @@ struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx) } } + BT_ERR("AppKeyFull"); return NULL; } -static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val[16], - bool update) +static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, + const uint8_t val[16], bool update) { struct bt_mesh_app_keys *keys = NULL; struct bt_mesh_app_key *key = NULL; struct bt_mesh_subnet *sub = NULL; - BT_DBG("net_idx 0x%04x app_idx %04x update %u val %s", + BT_DBG("AppKeySet"); + BT_DBG("NetIdx 0x%04x AppIdx %04x Update %u Val %s", net_idx, app_idx, update, bt_hex(val, 16)); sub = bt_mesh_subnet_get(net_idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); return STATUS_INVALID_NETKEY; } key = bt_mesh_app_key_get(app_idx); if (update) { if (!key) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } if (key->net_idx != net_idx) { + BT_DBG("StatusInvalidBinding"); return STATUS_INVALID_BINDING; } @@ -493,11 +527,13 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val * the AppKey value is different. */ if (sub->kr_phase != BLE_MESH_KR_PHASE_1) { + BT_DBG("StatusCannotUpdate"); return STATUS_CANNOT_UPDATE; } if (key->updated) { if (memcmp(keys->val, val, 16)) { + BT_DBG("StatusCannotUpdate"); return STATUS_CANNOT_UPDATE; } @@ -513,14 +549,17 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val } if (key->net_idx == net_idx) { + BT_DBG("StatusIdxAlreadyStored"); return STATUS_IDX_ALREADY_STORED; } + BT_DBG("StatusInvalidNetKey"); return STATUS_INVALID_NETKEY; } key = bt_mesh_app_key_alloc(app_idx); if (!key) { + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } @@ -532,17 +571,15 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val key->updated = false; } + BT_DBG("StatusStorageFail"); return STATUS_STORAGE_FAIL; } - BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, keys->id); - key->net_idx = net_idx; key->app_idx = app_idx; memcpy(keys->val, val, 16); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); bt_mesh_store_app_key(key); } @@ -559,14 +596,13 @@ static void app_key_add(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppKeyAdd, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); status = app_key_set(key_net_idx, key_app_idx, buf->data, false); - BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_u8(&msg, status); key_idx_pack(&msg, key_net_idx, key_app_idx); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -594,14 +630,13 @@ static void app_key_update(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppKeyUpdate, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); status = app_key_set(key_net_idx, key_app_idx, buf->data, true); - BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_u8(&msg, status); key_idx_pack(&msg, key_net_idx, key_app_idx); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -628,6 +663,8 @@ static void _mod_unbind(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, { struct unbind_data *data = user_data; + BT_DBG("_ModUnbind, Vnd %u Primary %u", vnd, primary); + mod_unbind(mod, data->app_idx, data->store); } @@ -635,7 +672,7 @@ void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store) { struct unbind_data data = { .app_idx = key->app_idx, .store = store }; - BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); + BT_DBG("AppKeyDel, AppIdx 0x%04x Store %u", key->app_idx, store); bt_mesh_model_foreach(_mod_unbind, &data); @@ -658,9 +695,10 @@ static void app_key_del(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppkeyDel, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); if (!bt_mesh_subnet_get(key_net_idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; goto send_status; } @@ -675,11 +713,13 @@ static void app_key_del(struct bt_mesh_model *model, } if (key->net_idx != key_net_idx) { + BT_DBG("StatusInvalidBinding"); status = STATUS_INVALID_BINDING; goto send_status; } bt_mesh_app_key_del(key, true); + status = STATUS_SUCCESS; send_status: @@ -703,7 +743,7 @@ static void app_key_del(struct bt_mesh_model *model, } /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ -#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) +#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) static void app_key_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, @@ -714,17 +754,20 @@ static void app_key_get(struct bt_mesh_model *model, uint16_t get_idx = 0U, i = 0U, prev = 0U; uint8_t status = 0U; + BT_DBG("AppkeyGet"); + get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx); return; } - BT_DBG("idx 0x%04x", get_idx); + BT_DBG("GetIdx 0x%04x", get_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_LIST); if (!bt_mesh_subnet_get(get_idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; } else { status = STATUS_SUCCESS; @@ -738,6 +781,7 @@ static void app_key_get(struct bt_mesh_model *model, } prev = BLE_MESH_KEY_UNUSED; + for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; @@ -770,9 +814,10 @@ static void beacon_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_BEACON_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("BeaconGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_secure_beacon_get()); @@ -789,9 +834,10 @@ static void beacon_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_BEACON_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("BeaconSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -828,9 +874,10 @@ static void default_ttl_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_DEFAULT_TTL_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("DefaultTTLGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_DEFAULT_TTL_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_default_ttl_get()); @@ -847,9 +894,10 @@ static void default_ttl_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_DEFAULT_TTL_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("DefaultTTLSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -879,6 +927,8 @@ static void send_gatt_proxy_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_GATT_PROXY_STATUS, 1); + BT_DBG("SendGattProxyStatus"); + bt_mesh_model_msg_init(&msg, OP_GATT_PROXY_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_gatt_proxy_get()); @@ -891,9 +941,10 @@ static void gatt_proxy_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GattProxyGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); send_gatt_proxy_status(model, ctx); } @@ -904,9 +955,10 @@ static void gatt_proxy_set(struct bt_mesh_model *model, { struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GattProxySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid GATT Proxy value 0x%02x", buf->data[0]); @@ -923,7 +975,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, goto send_status; } - BT_DBG("GATT Proxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->data[0]); + BT_DBG("GattProxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->data[0]); if (cfg->gatt_proxy == buf->data[0]) { goto send_status; @@ -934,11 +986,11 @@ static void gatt_proxy_set(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_PRB_SRV /* If the value of the GATT Proxy state of the node is 0x01 (see Table 4.21), * then the value of the Private GATT Proxy state shall be Disable (0x00). - */ + */ if (buf->data[0] == BLE_MESH_GATT_PROXY_ENABLED) { bt_mesh_disable_private_gatt_proxy(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ #if CONFIG_BLE_MESH_DF_SRV /* If the value of the GATT Proxy state of the node is 0x00, @@ -946,7 +998,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, * directed proxy use directed default shall be 0x02. */ bt_mesh_disable_directed_proxy_state(ctx->net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_cfg(); @@ -966,9 +1018,10 @@ static void net_transmit_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_TRANSMIT_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetTransmitGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_net_transmit_get()); @@ -985,11 +1038,13 @@ static void net_transmit_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_TRANSMIT_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetTransmitSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("Transmit 0x%02x (count %u interval %ums)", buf->data[0], + BT_DBG("Transmit 0x%02x Count %u Interval %u", + buf->data[0], BLE_MESH_TRANSMIT_COUNT(buf->data[0]), BLE_MESH_TRANSMIT_INT(buf->data[0])); @@ -1017,9 +1072,10 @@ static void relay_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_STATUS, 2); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelayGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_RELAY_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_relay_get()); @@ -1037,9 +1093,10 @@ static void relay_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_STATUS, 2); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelaySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -1050,6 +1107,7 @@ static void relay_set(struct bt_mesh_model *model, change = false; } else { change = (cfg->relay != buf->data[0]); + cfg->relay = buf->data[0]; cfg->relay_retransmit = buf->data[1]; @@ -1058,9 +1116,8 @@ static void relay_set(struct bt_mesh_model *model, } } - BT_DBG("Relay 0x%02x (%s) xmit 0x%02x (count %u interval %u)", - cfg->relay, change ? "changed" : "not changed", - cfg->relay_retransmit, + BT_DBG("Relay 0x%02x Change %u Xmit 0x%02x Count %u Interval %u", + cfg->relay, change, cfg->relay_retransmit, BLE_MESH_TRANSMIT_COUNT(cfg->relay_retransmit), BLE_MESH_TRANSMIT_INT(cfg->relay_retransmit)); @@ -1089,6 +1146,10 @@ static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_STATUS, 14); + BT_DBG("SendModPubStatus"); + BT_DBG("ElemAddr 0x%04x PubAddr 0x%04x Vnd %u Status 0x%02x", + elem_addr, pub_addr, vnd, status); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_STATUS); net_buf_simple_add_u8(&msg, status); @@ -1129,6 +1190,8 @@ static void mod_pub_get(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModPubGet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1137,10 +1200,11 @@ static void mod_pub_get(struct bt_mesh_model *model, mod_id = buf->data; - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1149,11 +1213,13 @@ static void mod_pub_get(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!mod->pub) { + BT_DBG("StatusNvalPubParam"); status = STATUS_NVAL_PUB_PARAM; goto send_status; } @@ -1162,8 +1228,7 @@ static void mod_pub_get(struct bt_mesh_model *model, status = STATUS_SUCCESS; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } static void mod_pub_set(struct bt_mesh_model *model, @@ -1177,6 +1242,8 @@ static void mod_pub_set(struct bt_mesh_model *model, uint8_t *mod_id = NULL; bool vnd = false; + BT_DBG("ModPubSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1198,16 +1265,18 @@ static void mod_pub_set(struct bt_mesh_model *model, retransmit = net_buf_simple_pull_u8(buf); mod_id = buf->data; - BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u", + BT_DBG("ElemAddr 0x%04x PubAddr 0x%04x CredFlag %u", elem_addr, pub_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + BT_DBG("PubAppIdx 0x%04x PubTTL %u PubPeriod 0x%02x", pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BT_DBG("Retransmit 0x%02x Count %u Interval %u", + retransmit, BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), BLE_MESH_PUB_TRANSMIT_INT(retransmit)); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1216,6 +1285,7 @@ static void mod_pub_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -1224,8 +1294,7 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_period, retransmit, true); send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); if (status == STATUS_SUCCESS && mod->pub) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1245,6 +1314,8 @@ static void mod_pub_set(struct bt_mesh_model *model, struct label *get_label(uint16_t index) { + BT_DBG("GetLabel, Index %u", index); + if (index >= ARRAY_SIZE(labels)) { return NULL; } @@ -1255,7 +1326,10 @@ struct label *get_label(uint16_t index) #if CONFIG_BLE_MESH_LABEL_COUNT > 0 static inline void va_store(struct label *store) { + BT_DBG("VaStore"); + bt_mesh_atomic_set_bit(store->flags, BLE_MESH_VA_CHANGED); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_label(); } @@ -1267,6 +1341,8 @@ static struct label *va_find(const uint8_t *label_uuid, struct label *match = NULL; int i; + BT_DBG("VaFind"); + if (free_slot != NULL) { *free_slot = NULL; } @@ -1291,10 +1367,14 @@ uint8_t va_add(uint8_t *label_uuid, uint16_t *addr) { struct label *update = NULL, *free_slot = NULL; + BT_DBG("VaAdd"); + update = va_find(label_uuid, &free_slot); if (update) { update->ref++; + va_store(update); + if (addr) { *addr = update->addr; } @@ -1302,10 +1382,12 @@ uint8_t va_add(uint8_t *label_uuid, uint16_t *addr) } if (!free_slot) { + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } if (bt_mesh_virtual_addr(label_uuid, addr) < 0) { + BT_DBG("StatusUnspecified"); return STATUS_UNSPECIFIED; } @@ -1321,6 +1403,8 @@ uint8_t va_del(uint8_t *label_uuid, uint16_t *addr) { struct label *update = NULL; + BT_DBG("VaDel"); + update = va_find(label_uuid, NULL); if (update) { update->ref--; @@ -1337,6 +1421,7 @@ uint8_t va_del(uint8_t *label_uuid, uint16_t *addr) *addr = BLE_MESH_ADDR_UNASSIGNED; } + BT_DBG("StatusCannotRemove"); return STATUS_CANNOT_REMOVE; } @@ -1346,6 +1431,8 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) size_t clear_count = 0U; int i; + BT_DBG("ModSubListClear"); + /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { if (!BLE_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { @@ -1365,10 +1452,12 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) if (label_uuid) { va_del(label_uuid, NULL); } else { - BT_ERR("Label UUID not found"); + BT_ERR("LabelUUIDNotFound"); } } + BT_DBG("ClearCount %u", clear_count); + return clear_count; } @@ -1384,6 +1473,8 @@ static void mod_pub_va_set(struct bt_mesh_model *model, uint8_t *mod_id = NULL; bool vnd = false; + BT_DBG("ModPubVaSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1404,15 +1495,17 @@ static void mod_pub_va_set(struct bt_mesh_model *model, retransmit = net_buf_simple_pull_u8(buf); mod_id = buf->data; - BT_DBG("elem_addr 0x%04x cred_flag %u", elem_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + BT_DBG("ElemAddr 0x%04x CredFlag %u", elem_addr, cred_flag); + BT_DBG("PubAppIdx 0x%04x PubTTL %u PubPeriod 0x%02x", pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BT_DBG("Retransmit 0x%02x Count %u Interval %u", + retransmit, BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), BLE_MESH_PUB_TRANSMIT_INT(retransmit)); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); pub_addr = 0U; @@ -1422,6 +1515,7 @@ static void mod_pub_va_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); pub_addr = 0U; status = STATUS_INVALID_MODEL; goto send_status; @@ -1434,15 +1528,16 @@ static void mod_pub_va_set(struct bt_mesh_model *model, } send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } -#else +#else /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) { size_t clear_count = 0U; int i; + BT_DBG("ModSubListClear"); + /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { @@ -1451,6 +1546,8 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) } } + BT_DBG("ClearCount %u", clear_count); + return clear_count; } @@ -1458,12 +1555,14 @@ static void mod_pub_va_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + uint16_t elem_addr = 0U, pub_addr = 0U; uint8_t *mod_id = NULL, status = 0U; struct bt_mesh_model *mod = NULL; struct bt_mesh_elem *elem = NULL; - uint16_t elem_addr = 0U, pub_addr = 0U; bool vnd = false; + BT_DBG("ModPubVaSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1473,10 +1572,11 @@ static void mod_pub_va_set(struct bt_mesh_model *model, net_buf_simple_pull(buf, 16); mod_id = net_buf_simple_pull(buf, 4); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1485,33 +1585,37 @@ static void mod_pub_va_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!mod->pub) { + BT_DBG("StatusNvalPubParam"); status = STATUS_NVAL_PUB_PARAM; goto send_status; } pub_addr = mod->pub->addr; + + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } #endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static void send_mod_sub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, - uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, - bool vnd) + uint16_t elem_addr, uint16_t sub_addr, + uint8_t *mod_id, bool vnd) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_STATUS, 9); - BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status, - elem_addr, sub_addr); + BT_DBG("SendModSubStatus"); + BT_DBG("Status 0x%02x ElemAddr 0x%04x SubAddr 0x%04x Vnd %u", + status, elem_addr, sub_addr, vnd); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_STATUS); @@ -1542,6 +1646,8 @@ static void mod_sub_add(struct bt_mesh_model *model, bool vnd = false; int i; + BT_DBG("ModSubAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1550,12 +1656,13 @@ static void mod_sub_add(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x, sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1564,18 +1671,19 @@ static void mod_sub_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } if (bt_mesh_model_find_group(mod, sub_addr)) { /* Tried to add existing subscription */ - BT_DBG("found existing subscription"); status = STATUS_SUCCESS; goto send_status; } @@ -1592,6 +1700,7 @@ static void mod_sub_add(struct bt_mesh_model *model, } if (i == ARRAY_SIZE(mod->groups)) { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } else { status = STATUS_SUCCESS; @@ -1606,12 +1715,11 @@ static void mod_sub_add(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); #if CONFIG_BLE_MESH_DF_SRV bt_mesh_directed_forwarding_node_solicitation(mod, bt_mesh_subnet_get(ctx->net_idx)); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (status == STATUS_SUCCESS) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1636,6 +1744,8 @@ static void mod_sub_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1644,12 +1754,13 @@ static void mod_sub_del(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1658,11 +1769,13 @@ static void mod_sub_del(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } @@ -1686,8 +1799,7 @@ static void mod_sub_del(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); if (status == STATUS_SUCCESS) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1711,6 +1823,8 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1719,12 +1833,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1733,11 +1848,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } @@ -1760,13 +1877,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, bt_mesh_lpn_group_add(sub_addr); } } else { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_del_all(struct bt_mesh_model *model, @@ -1780,18 +1897,21 @@ static void mod_sub_del_all(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubDelAll"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); return; } - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1800,6 +1920,7 @@ static void mod_sub_del_all(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -1832,6 +1953,8 @@ static void mod_sub_get(struct bt_mesh_model *model, uint16_t addr = 0U, id = 0U; int i; + BT_DBG("ModSubGet"); + addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { BT_ERR("Prohibited element address 0x%04x", addr); @@ -1840,12 +1963,13 @@ static void mod_sub_get(struct bt_mesh_model *model, id = net_buf_simple_pull_le16(buf); - BT_DBG("addr 0x%04x id 0x%04x", addr, id); + BT_DBG("ElemAddr 0x%04x ID 0x%04x", addr, id); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST); elem = bt_mesh_elem_find(addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, id); @@ -1854,6 +1978,7 @@ static void mod_sub_get(struct bt_mesh_model *model, mod = bt_mesh_model_find(elem, id); if (!mod) { + BT_DBG("StatusInvalidModel"); net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, id); @@ -1888,6 +2013,8 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, uint16_t company = 0U, addr = 0U, id = 0U; int i; + BT_DBG("ModSubGetVnd"); + addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { BT_ERR("Prohibited element address 0x%04x", addr); @@ -1897,12 +2024,13 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, company = net_buf_simple_pull_le16(buf); id = net_buf_simple_pull_le16(buf); - BT_DBG("addr 0x%04x company 0x%04x id 0x%04x", addr, company, id); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x", addr, company, id); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST_VND); elem = bt_mesh_elem_find(addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, company); @@ -1912,6 +2040,7 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, mod = bt_mesh_model_find_vnd(elem, company, id); if (!mod) { + BT_DBG("StatusInvalidModel"); net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, company); @@ -1951,6 +2080,8 @@ static void mod_sub_va_add(struct bt_mesh_model *model, bool vnd = false; int i; + BT_DBG("ModSubVaAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1959,11 +2090,12 @@ static void mod_sub_va_add(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); sub_addr = BLE_MESH_ADDR_UNASSIGNED; @@ -1973,6 +2105,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); sub_addr = BLE_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; @@ -2001,6 +2134,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } if (i == ARRAY_SIZE(mod->groups)) { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } else { if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { @@ -2015,8 +2149,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_va_del(struct bt_mesh_model *model, @@ -2032,6 +2165,8 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2040,12 +2175,13 @@ static void mod_sub_va_del(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); sub_addr = BLE_MESH_ADDR_UNASSIGNED; @@ -2055,6 +2191,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); sub_addr = BLE_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; @@ -2079,12 +2216,12 @@ static void mod_sub_va_del(struct bt_mesh_model *model, status = STATUS_SUCCESS; } else { + BT_DBG("StatusCannotRemove"); status = STATUS_CANNOT_REMOVE; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_va_overwrite(struct bt_mesh_model *model, @@ -2099,6 +2236,8 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2107,12 +2246,13 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2121,6 +2261,7 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -2145,14 +2286,14 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, } } } else { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } -#else +#else /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static void mod_sub_va_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) @@ -2164,6 +2305,8 @@ static void mod_sub_va_add(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2176,6 +2319,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2184,10 +2328,12 @@ static void mod_sub_va_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2205,6 +2351,8 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2217,16 +2365,19 @@ static void mod_sub_va_del(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; goto send_status; } if (!get_model(elem, buf, &vnd)) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2244,6 +2395,8 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2256,16 +2409,19 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; goto send_status; } if (!get_model(elem, buf, &vnd)) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2280,6 +2436,8 @@ static void send_net_key_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_STATUS, 3); + BT_DBG("SendNetKeyStatus"); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_STATUS); net_buf_simple_add_u8(&msg, status); @@ -2298,13 +2456,15 @@ static void net_key_add(struct bt_mesh_model *model, uint16_t idx = 0U; int err = 0; + BT_DBG("NetKeyAdd"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { @@ -2318,8 +2478,8 @@ static void net_key_add(struct bt_mesh_model *model, } if (!sub) { - send_net_key_status(model, ctx, idx, - STATUS_INSUFF_RESOURCES); + BT_DBG("StatusInsuffResources"); + send_net_key_status(model, ctx, idx, STATUS_INSUFF_RESOURCES); return; } } @@ -2329,6 +2489,7 @@ static void net_key_add(struct bt_mesh_model *model, uint8_t status = 0U; if (memcmp(buf->data, sub->keys[0].net, 16)) { + BT_DBG("StatusIdxAlreadyStored"); status = STATUS_IDX_ALREADY_STORED; } else { status = STATUS_SUCCESS; @@ -2340,6 +2501,7 @@ static void net_key_add(struct bt_mesh_model *model, err = bt_mesh_net_keys_create(&sub->keys[0], buf->data); if (err) { + BT_DBG("StatusUnspecified"); send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); return; } @@ -2347,7 +2509,6 @@ static void net_key_add(struct bt_mesh_model *model, sub->net_idx = idx; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -2368,7 +2529,7 @@ static void net_key_add(struct bt_mesh_model *model, if (sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { bt_mesh_directed_proxy_server_directed_proxy_caps_send(sub, false); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY */ bt_mesh_adv_update(); } else { @@ -2381,7 +2542,7 @@ static void net_key_add(struct bt_mesh_model *model, if (bt_mesh_directed_forwarding_sub_init(sub)) { BT_ERR("Failed to init subnet for directed forward"); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ bt_mesh_cfg_server_state_change_t change = {0}; change.cfg_netkey_add.net_idx = sub->net_idx; @@ -2398,16 +2559,19 @@ static void net_key_update(struct bt_mesh_model *model, uint16_t idx = 0U; int err = 0; + BT_DBG("NetKeyUpdate"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_net_key_status(model, ctx, idx, STATUS_INVALID_NETKEY); return; } @@ -2432,6 +2596,7 @@ static void net_key_update(struct bt_mesh_model *model, /* fall through */ case BLE_MESH_KR_PHASE_2: case BLE_MESH_KR_PHASE_3: + BT_DBG("StatusCannotUpdate"); send_net_key_status(model, ctx, idx, STATUS_CANNOT_UPDATE); return; } @@ -2443,6 +2608,7 @@ static void net_key_update(struct bt_mesh_model *model, } if (err) { + BT_DBG("StatusUnspecified"); send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); return; } @@ -2450,7 +2616,6 @@ static void net_key_update(struct bt_mesh_model *model, sub->kr_phase = BLE_MESH_KR_PHASE_1; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -2467,6 +2632,8 @@ static void net_key_update(struct bt_mesh_model *model, static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) { + BT_DBG("HbPubDisable"); + cfg->hb_pub.dst = BLE_MESH_ADDR_UNASSIGNED; cfg->hb_pub.count = 0U; cfg->hb_pub.ttl = 0U; @@ -2483,13 +2650,15 @@ static void net_key_del(struct bt_mesh_model *model, uint16_t del_idx = 0U; uint8_t status = 0U; + BT_DBG("NetKeyDel"); + del_idx = net_buf_simple_pull_le16(buf); if (del_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx); return; } - BT_DBG("idx 0x%04x", del_idx); + BT_DBG("NetIdx 0x%04x", del_idx); sub = bt_mesh_subnet_get(del_idx); if (!sub) { @@ -2504,6 +2673,7 @@ static void net_key_del(struct bt_mesh_model *model, * The NetKey List must contain a minimum of one NetKey. */ if (ctx->net_idx == del_idx) { + BT_DBG("StatusCannotRemove"); status = STATUS_CANNOT_REMOVE; goto send_status; } @@ -2525,8 +2695,8 @@ static void net_key_del(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_SETTINGS bt_mesh_clear_directed_forwarding_table_data(del_idx); -#endif -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS */ +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY */ bt_mesh_subnet_del(sub, true); status = STATUS_SUCCESS; @@ -2540,11 +2710,11 @@ static void net_key_del(struct bt_mesh_model *model, * Index of the deleted NetKey are removed. */ bt_mesh_delete_netkey_in_bridge_table(del_idx); -#endif /* CONFIG_BLE_MESH_BRC_SRV */ +#endif /* CONFIG_BLE_MESH_BRC_SRV */ #if CONFIG_BLE_MESH_RPR_SRV bt_mesh_rpr_srv_netkey_del(del_idx); -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ send_status: send_net_key_status(model, ctx, del_idx, status); @@ -2565,6 +2735,8 @@ static void net_key_get(struct bt_mesh_model *model, IDX_LEN(CONFIG_BLE_MESH_SUBNET_COUNT)); uint16_t prev = 0U, i = 0U; + BT_DBG("NetKeyGet"); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_LIST); prev = BLE_MESH_KEY_UNUSED; @@ -2602,9 +2774,10 @@ static void node_identity_get(struct bt_mesh_model *model, uint8_t node_id = 0U; uint16_t idx = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIdentityGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2616,6 +2789,7 @@ static void node_identity_get(struct bt_mesh_model *model, sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); node_id = 0x00; } else { @@ -2640,9 +2814,10 @@ static void node_identity_set(struct bt_mesh_model *model, uint8_t node_id = 0U; uint16_t idx = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIdentitySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2660,6 +2835,7 @@ static void node_identity_set(struct bt_mesh_model *model, sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); net_buf_simple_add_le16(&msg, idx); net_buf_simple_add_u8(&msg, node_id); @@ -2672,7 +2848,8 @@ static void node_identity_set(struct bt_mesh_model *model, * Identity state shall be Disable (0x00). */ bt_mesh_proxy_private_identity_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + bt_mesh_proxy_server_identity_start(sub); } else { bt_mesh_proxy_server_identity_stop(sub); @@ -2697,6 +2874,10 @@ static void create_mod_app_status(struct net_buf_simple *msg, { bt_mesh_model_msg_init(msg, OP_MOD_APP_STATUS); + BT_DBG("CreateModAppStatus"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x Status 0x%02x Vnd %u", + elem_addr, app_idx, status, vnd); + net_buf_simple_add_u8(msg, status); net_buf_simple_add_le16(msg, elem_addr); net_buf_simple_add_le16(msg, app_idx); @@ -2719,6 +2900,8 @@ static void mod_app_bind(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModAppBind"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2730,6 +2913,7 @@ static void mod_app_bind(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2738,24 +2922,24 @@ static void mod_app_bind(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } /* Configuration Server only allows device key based access */ if (model == mod) { - BT_ERR("Client tried to bind AppKey to Configuration Model"); + BT_ERR("StatusCannotBind"); status = STATUS_CANNOT_BIND; goto send_status; } status = mod_bind(mod, key_app_idx); - BT_INFO("bind app key %#x on mode %#x", key_app_idx, mod->id); + BT_INFO("AppIdx 0x%04x ID 0x%04x", key_app_idx, mod->id); + send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, mod_id); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Model App Bind Status"); @@ -2783,6 +2967,8 @@ static void mod_app_unbind(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModAppUnbind"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2794,6 +2980,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2802,6 +2989,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -2809,9 +2997,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, status = mod_unbind(mod, key_app_idx, true); send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, mod_id); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Model App Unbind Status"); @@ -2828,23 +3014,22 @@ static void mod_app_unbind(struct bt_mesh_model *model, } } -#define KEY_LIST_LEN (CONFIG_BLE_MESH_MODEL_KEY_COUNT * 2) +#define KEY_LIST_LEN (CONFIG_BLE_MESH_MODEL_KEY_COUNT * 2) static void mod_app_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - NET_BUF_SIMPLE_DEFINE(msg, - MAX(BLE_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, - 9 + KEY_LIST_LEN), - BLE_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, - 9 + KEY_LIST_LEN))); + NET_BUF_SIMPLE_DEFINE(msg, MAX(BLE_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, 9 + KEY_LIST_LEN), + BLE_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); struct bt_mesh_model *mod = NULL; struct bt_mesh_elem *elem = NULL; uint8_t *mod_id = NULL, status = 0U; uint16_t elem_addr = 0U; bool vnd = false; + BT_DBG("ModAppGet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2853,10 +3038,11 @@ static void mod_app_get(struct bt_mesh_model *model, mod_id = buf->data; - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2865,6 +3051,7 @@ static void mod_app_get(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_list; } @@ -2908,15 +3095,15 @@ static void node_reset(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_RESET_STATUS, 0); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); - + BT_DBG("NodeReset"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS); - /* Send the response first since we won't have any keys left to - * send it later. + /* Send the response first since we won't have any keys + * left to send it later. */ if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Node Reset Status"); @@ -2933,6 +3120,8 @@ static void send_friend_status(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_FRIEND_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("SendFrndStatus"); + bt_mesh_model_msg_init(&msg, OP_FRIEND_STATUS); net_buf_simple_add_u8(&msg, cfg->frnd); @@ -2945,9 +3134,10 @@ static void friend_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("FrndGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); send_friend_status(model, ctx); } @@ -2958,9 +3148,10 @@ static void friend_set(struct bt_mesh_model *model, { struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("FrndSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid Friend value 0x%02x", buf->data[0]); @@ -2972,7 +3163,7 @@ static void friend_set(struct bt_mesh_model *model, goto send_status; } - BT_DBG("Friend 0x%02x -> 0x%02x", cfg->frnd, buf->data[0]); + BT_DBG("Frnd 0x%02x -> 0x%02x", cfg->frnd, buf->data[0]); if (cfg->frnd == buf->data[0]) { goto send_status; @@ -2993,7 +3184,7 @@ static void friend_set(struct bt_mesh_model *model, * then the value of the directed friend state shall be 0x00. */ bt_mesh_disable_directed_friend_state(ctx->net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_FRIEND */ } } @@ -3016,7 +3207,8 @@ static void lpn_timeout_get(struct bt_mesh_model *model, lpn_addr = net_buf_simple_pull_le16(buf); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x lpn_addr 0x%02x", + BT_DBG("LPNTimeoutGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x LPN 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr, lpn_addr); if (!BLE_MESH_ADDR_IS_UNICAST(lpn_addr)) { @@ -3054,6 +3246,8 @@ static void send_krp_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_KRP_STATUS, 4); + BT_DBG("SendKrpStatus"); + bt_mesh_model_msg_init(&msg, OP_KRP_STATUS); net_buf_simple_add_u8(&msg, status); @@ -3071,20 +3265,22 @@ static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet *sub = NULL; uint16_t idx = 0U; + BT_DBG("KrpGet"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); } else { - send_krp_status(model, ctx, idx, sub->kr_phase, - STATUS_SUCCESS); + send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS); } } @@ -3095,6 +3291,8 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t phase = 0U; uint16_t idx = 0U; + BT_DBG("KrpSet"); + idx = net_buf_simple_pull_le16(buf); phase = net_buf_simple_pull_u8(buf); @@ -3103,15 +3301,16 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return; } - BT_DBG("idx 0x%04x transition 0x%02x", idx, phase); + BT_DBG("NetIdx 0x%04x Phase 0x%02x", idx, phase); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); return; } - BT_DBG("%u -> %u", sub->kr_phase, phase); + BT_DBG("KrPhase %u -> %u", sub->kr_phase, phase); if (phase < BLE_MESH_KR_PHASE_2 || phase > BLE_MESH_KR_PHASE_3 || (sub->kr_phase == BLE_MESH_KR_NORMAL && @@ -3126,7 +3325,6 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, sub->kr_flag = 1; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing kr phase persistently"); bt_mesh_store_subnet(sub); } @@ -3157,6 +3355,8 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, static uint8_t hb_log(uint16_t val) { + BT_DBG("HbLog, Val 0x%04x", val); + switch (val) { case 0x0000: return 0x00; @@ -3169,6 +3369,8 @@ static uint8_t hb_log(uint16_t val) static uint8_t hb_pub_count_log(uint16_t val) { + BT_DBG("HbPubCountLog, Val 0x%04x", val); + switch (val) { case 0x0000: return 0x00; @@ -3183,6 +3385,8 @@ static uint8_t hb_pub_count_log(uint16_t val) static uint16_t hb_pwr2(uint8_t val, uint8_t sub) { + BT_DBG("HbPwr2, Val 0x%02x Sub 0x%02x", val, sub); + switch (val) { case 0x00: return 0x0000; @@ -3210,7 +3414,7 @@ static void hb_pub_send_status(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_STATUS, 10); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + BT_DBG("HbPubSendStatus, Src 0x%04x Status 0x%02x", ctx->addr, status); bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_STATUS); @@ -3239,7 +3443,7 @@ static void heartbeat_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatPubGet, Src 0x%04x", ctx->addr); hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); } @@ -3253,27 +3457,30 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, uint16_t dst = 0U, feat = 0U, idx = 0U; uint8_t status = 0U; - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatPubSet, Src 0x%04x", ctx->addr); dst = sys_le16_to_cpu(param->dst); /* All other address types but virtual are valid */ if (BLE_MESH_ADDR_IS_VIRTUAL(dst)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto failed; } if (param->count_log > 0x11 && param->count_log != 0xff) { + BT_DBG("StatusCannotSet"); status = STATUS_CANNOT_SET; goto failed; } if (param->period_log > 0x11) { + BT_DBG("StatusCannotSet"); status = STATUS_CANNOT_SET; goto failed; } if (param->ttl > BLE_MESH_TTL_MAX && param->ttl != BLE_MESH_TTL_DEFAULT) { - BT_ERR("Invalid TTL value 0x%02x", param->ttl); + BT_ERR("InvalidTTL %u", param->ttl); return; } @@ -3281,11 +3488,12 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, idx = sys_le16_to_cpu(param->net_idx); if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); + BT_ERR("InvalidNetIdx 0x%04x", idx); return; } if (!bt_mesh_subnet_get(idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; goto failed; } @@ -3302,7 +3510,7 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, cfg->hb_pub.count = hb_pwr2(param->count_log, 1); cfg->hb_pub.ttl = param->ttl; - BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000U); + BT_DBG("Period %u", hb_pwr2(param->period_log, 1) * 1000U); /* Note: Send heartbeat message here will cause wrong heartbeat status message */ #if 0 @@ -3343,14 +3551,15 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, } static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status) + struct bt_mesh_msg_ctx *ctx, + uint8_t status) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_STATUS, 9); struct bt_mesh_cfg_srv *cfg = model->user_data; uint16_t period = 0U; int64_t uptime = 0; - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + BT_DBG("HbSubSendStatus, Src 0x%04x Status 0x%02x", ctx->addr, status); uptime = k_uptime_get(); if (uptime > cfg->hb_sub.expiry) { @@ -3378,7 +3587,7 @@ static void heartbeat_sub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatSubGet, Src 0x%04x", ctx->addr); hb_sub_send_status(model, ctx, STATUS_SUCCESS); } @@ -3392,13 +3601,13 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, uint8_t sub_period = 0U; int32_t period_ms = 0; - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatSubSet, Src 0x%04x", ctx->addr); sub_src = net_buf_simple_pull_le16(buf); sub_dst = net_buf_simple_pull_le16(buf); sub_period = net_buf_simple_pull_u8(buf); - BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x", + BT_DBG("SubSrc 0x%04x SubDst 0x%04x SubPeriod 0x%02x", sub_src, sub_dst, sub_period); if (sub_src != BLE_MESH_ADDR_UNASSIGNED && @@ -3447,7 +3656,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, /* Let the transport layer know it needs to handle this address */ bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst); - BT_DBG("period_ms %u", period_ms); + BT_DBG("Period %ld", period_ms); if (period_ms) { cfg->hb_sub.expiry = k_uptime_get() + period_ms; @@ -3529,7 +3738,8 @@ static void hb_publish(struct k_work *work) struct bt_mesh_subnet *sub = NULL; uint16_t period_ms = 0U; - BT_DBG("hb_pub.count: %u", cfg->hb_pub.count); + BT_DBG("HbPublish, NetIdx 0x%04x Count %u", + cfg->hb_pub.net_idx, cfg->hb_pub.count); sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); if (!sub) { @@ -3557,15 +3767,20 @@ static void hb_publish(struct k_work *work) static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) { + BT_DBG("ConfIsValid"); + if (cfg->relay > 0x02) { + BT_ERR("InvalidRelay 0x%02x", cfg->relay); return false; } if (cfg->beacon > 0x01) { + BT_ERR("InvalidBeacon 0x%02x", cfg->beacon); return false; } if (cfg->default_ttl > BLE_MESH_TTL_MAX) { + BT_ERR("InvalidDefaultTTL 0x%02x", cfg->default_ttl); return false; } @@ -3591,6 +3806,8 @@ static int cfg_srv_init(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("CfgSrvInit"); + if (!bt_mesh_model_in_primary(model)) { BT_ERR("Configuration Server only allowed in primary element"); return -EINVAL; @@ -3602,7 +3819,6 @@ static int cfg_srv_init(struct bt_mesh_model *model) } if (!conf_is_valid(cfg)) { - BT_ERR("Invalid values in configuration"); return -EINVAL; } @@ -3637,6 +3853,8 @@ static int cfg_srv_deinit(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("CfgSrvDeinit"); + if (!bt_mesh_model_in_primary(model)) { BT_ERR("Configuration Server only allowed in primary element"); return -EINVAL; @@ -3682,6 +3900,9 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, clear_count = mod_sub_list_clear(mod); + BT_DBG("ModReset, ClearCount %lu Vnd %u Primary %u", + clear_count, vnd, primary); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && clear_count && store) { bt_mesh_store_mod_sub(mod); } @@ -3689,6 +3910,8 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, void bt_mesh_mod_sub_reset(bool store) { + BT_DBG("ModSubReset, Store %u", store); + bt_mesh_model_foreach(mod_reset, &store); } @@ -3697,6 +3920,8 @@ void bt_mesh_cfg_reset(bool store) struct bt_mesh_cfg_srv *cfg = conf; int i; + BT_DBG("CfgReset, Store %u", store); + if (!cfg) { return; } @@ -3725,7 +3950,11 @@ void bt_mesh_cfg_reset(bool store) uint8_t bt_mesh_net_transmit_get(void) { + BT_DBG("NetTransmitGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->net_transmit); + return conf->net_transmit; } @@ -3734,6 +3963,8 @@ uint8_t bt_mesh_net_transmit_get(void) void bt_mesh_relay_local_set(bool enable) { + BT_DBG("RelayLocalSet, Enable %u", enable); + if (conf && conf->relay != BLE_MESH_RELAY_NOT_SUPPORTED) { if (enable) { conf->relay = BLE_MESH_RELAY_ENABLED; @@ -3745,7 +3976,11 @@ void bt_mesh_relay_local_set(bool enable) uint8_t bt_mesh_relay_get(void) { + BT_DBG("RelayGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->relay); + return conf->relay; } @@ -3754,8 +3989,11 @@ uint8_t bt_mesh_relay_get(void) uint8_t bt_mesh_friend_get(void) { + BT_DBG("FrndGet"); + if (conf) { - BT_DBG("conf %p conf->frnd 0x%02x", conf, conf->frnd); + BT_DBG("Val 0x%02x", conf->frnd); + return conf->frnd; } @@ -3764,7 +4002,11 @@ uint8_t bt_mesh_friend_get(void) uint8_t bt_mesh_relay_retransmit_get(void) { + BT_DBG("RelayRetransmitGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->relay_retransmit); + return conf->relay_retransmit; } @@ -3773,7 +4015,11 @@ uint8_t bt_mesh_relay_retransmit_get(void) uint8_t bt_mesh_secure_beacon_get(void) { + BT_DBG("SecureBeaconGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->beacon); + return conf->beacon; } @@ -3782,7 +4028,11 @@ uint8_t bt_mesh_secure_beacon_get(void) uint8_t bt_mesh_gatt_proxy_get(void) { + BT_DBG("GattProxyGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->gatt_proxy); + return conf->gatt_proxy; } @@ -3791,7 +4041,11 @@ uint8_t bt_mesh_gatt_proxy_get(void) uint8_t bt_mesh_default_ttl_get(void) { + BT_DBG("DefaultTTLGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->default_ttl); + return conf->default_ttl; } @@ -3802,7 +4056,7 @@ uint8_t *bt_mesh_label_uuid_get(uint16_t addr) { int i; - BT_DBG("addr 0x%04x", addr); + BT_DBG("LabelUUIDGet, Addr 0x%04x", addr); for (i = 0; i < ARRAY_SIZE(labels); i++) { if (labels[i].addr == addr) { @@ -3819,6 +4073,8 @@ uint8_t *bt_mesh_label_uuid_get(uint16_t addr) struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) { + BT_DBG("HbPubGet"); + if (!conf) { return NULL; } @@ -3828,6 +4084,8 @@ struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) void bt_mesh_hb_pub_disable(void) { + BT_DBG("HbPubDisable"); + if (conf) { hb_pub_disable(conf); } @@ -3835,6 +4093,8 @@ void bt_mesh_hb_pub_disable(void) struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) { + BT_DBG("CfgGet, Conf %p", conf); + return conf; } @@ -3842,7 +4102,7 @@ void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store) { int i; - BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); + BT_DBG("SubnetDel, NetIdx 0x%04x Store %u", sub->net_idx, store); if (conf && conf->hb_pub.net_idx == sub->net_idx) { hb_pub_disable(conf); diff --git a/components/bt/esp_ble_mesh/core/crypto.c b/components/bt/esp_ble_mesh/core/crypto.c index 2577c65efba2..3adba0be1fc3 100644 --- a/components/bt/esp_ble_mesh/core/crypto.c +++ b/components/bt/esp_ble_mesh/core/crypto.c @@ -24,9 +24,9 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ -#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) +#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, @@ -369,10 +369,11 @@ static int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], size_t i = 0U, j = 0U; int err = 0; - BT_DBG("key %s", bt_hex(key, 16)); - BT_DBG("nonce %s", bt_hex(nonce, 13)); - BT_DBG("msg (len %u) %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("aad_len %u mic_size %u", aad_len, mic_size); + BT_DBG("CCMEncrypt"); + BT_DBG("Key %s", bt_hex(key, 16)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Len %u: %s", msg_len, bt_hex(msg, msg_len)); + BT_DBG("AADLen %u MicSize %u", aad_len, mic_size); /* Unsupported AAD size */ if (aad_len >= 0xff00) { @@ -580,7 +581,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, uint8_t tmp[16] = {0}; int err = 0, i; - BT_DBG("IVIndex %u, PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); + BT_DBG("IVIndex %lu PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); sys_put_be32(iv_index, &priv_rand[5]); memcpy(&priv_rand[9], &pdu[7], 7); @@ -589,6 +590,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, err = bt_mesh_encrypt_be(privacy_key, priv_rand, tmp); if (err) { + BT_ERR("NetObfuscateFailed (%d)", err); return err; } @@ -606,9 +608,9 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, uint8_t nonce[13] = {0}; int err = 0; - BT_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16), - mic_len); - BT_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("IVIndex %u EncKey %s MicLen %u proxy %u/%u", + iv_index, bt_hex(key, 16), mic_len, proxy, proxy_solic); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_PROXY if (proxy) { @@ -633,6 +635,8 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, NULL, 0, &buf->data[7], mic_len); if (!err) { net_buf_simple_add(buf, mic_len); + } else { + BT_ERR("NetEncryptFailed (%d)", err); } return err; @@ -643,10 +647,11 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13] = {0}; + int err; - BT_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), - mic_len); + BT_DBG("IVIndex %u EncKey %s MicLen %u proxy %u/%u", + iv_index, bt_hex(key, 16), mic_len, proxy, proxy_solic); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_PROXY if (proxy) { @@ -669,8 +674,13 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, buf->len -= mic_len; - return bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, - NULL, 0, &buf->data[7], mic_len); + err = bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, + NULL, 0, &buf->data[7], mic_len); + if (err) { + BT_ERR("NetDecrypt failed (%d)", err); + } + + return err; } static void create_app_nonce(uint8_t nonce[13], bool dev_key, uint8_t aszmic, @@ -698,14 +708,15 @@ int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, uint8_t nonce[13] = {0}; int err = 0; + BT_DBG("AppEncrypt"); BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst); - BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index); - BT_DBG("Clear: %s", bt_hex(buf->data, buf->len)); + BT_DBG("DevKey %u Src 0x%04x Dst 0x%04x", dev_key, src, dst); + BT_DBG("SeqNum 0x%08lx IVIndex 0x%08lx", seq_num, iv_index); + BT_DBG("Data %u %s", buf->len, bt_hex(buf->data, buf->len)); create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); err = bt_mesh_ccm_encrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, buf->data, APP_MIC_LEN(aszmic)); @@ -725,12 +736,12 @@ int bt_mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, uint8_t nonce[13] = {0}; int err = 0; - BT_DBG("EncData (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("EncData %u %s", buf->len, bt_hex(buf->data, buf->len)); create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, out->data, APP_MIC_LEN(aszmic)); diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c index ebc285177792..8b85076aedbe 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.c +++ b/components/bt/esp_ble_mesh/core/ext_adv.c @@ -28,28 +28,9 @@ #include "adv_common.h" #include "ble_adv.h" -static struct bt_mesh_adv_queue *adv_queue; - static struct bt_mesh_adv_inst *adv_insts; -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) +static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) { struct net_buf *buf = inst->sending_buf; const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; @@ -63,8 +44,8 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration uint8_t is_ext_adv = false; #endif - BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("ExtAdvSend, Type %u", BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); switch (BLE_MESH_ADV(buf)->type) { #if CONFIG_BLE_MESH_EXT_ADV @@ -84,13 +65,13 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration case BLE_MESH_ADV_DATA: #if CONFIG_BLE_MESH_FRIEND case BLE_MESH_ADV_FRIEND: -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF case BLE_MESH_ADV_RELAY_DATA: -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX case BLE_MESH_ADV_PROXY_SOLIC: -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ case BLE_MESH_ADV_BEACON: case BLE_MESH_ADV_URI: { #if CONFIG_BLE_MESH_EXT_ADV @@ -146,19 +127,24 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + struct bt_mesh_adv_data solic_ad[2] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x59, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), }; - err = bt_le_ext_adv_start(CONFIG_BLE_MESH_ADV_INST_ID, ¶m, solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); + + err = bt_le_ext_adv_start(CONFIG_BLE_MESH_ADV_INST_ID, ¶m, + solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ { bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + err = bt_le_ext_adv_start(inst->id, ¶m, &ad, 1, NULL, 0); } - } - break; + } + break; + #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV case BLE_MESH_ADV_BLE: struct bt_mesh_ble_adv_data data = {0}; @@ -171,8 +157,8 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration } BT_DBG("interval %dms, duration %dms, period %dms, count %d", - ADV_SCAN_INT(tx->param.interval), tx->param.duration, - tx->param.period, tx->param.count); + ADV_SCAN_INT(tx->param.interval), tx->param.duration, + tx->param.period, tx->param.count); data.adv_data_len = tx->buf->data[0]; if (data.adv_data_len) { @@ -188,9 +174,10 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration err = bt_mesh_ble_ext_adv_start(inst->id, &tx->param, &data); break; -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + default: - BT_ERR("Error Type"); + BT_ERR("InvalidAdvType %u", BLE_MESH_ADV(buf)->type); break; } @@ -201,54 +188,64 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration } *adv_duration = duration; + BT_DBG("Advertising started. %u ms", duration); return 0; } -static inline int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) +static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) { + BT_DBG("FindValidMsgFromQueue"); + while(uxQueueMessagesWaiting(msg_queue->handle)) { xQueueReceive(msg_queue->handle, msg, K_WAIT(K_FOREVER)); - /* In the previous adv task design, only - * the *buf of messages pushed to the queue - * by adv_update would be empty, but in the - * new design, there is a new processing method - * for adv_update's messages, - * so *buf here cannot be empty. */ + /* In the previous adv task design, only the *buf of messages pushed to the queue + * by adv_update would be empty, but in the new design, there is a new processing + * method for adv_update's messages, so *buf here cannot be empty. + */ assert(msg->arg); - /* If the message is canceled for advertising, - * then continue to retrieve the next message - * from that queue. */ + BT_DBG("Buf %p Relay %u Busy %u", + BLE_MESH_MSG_NET_BUF(msg), msg->relay, + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(BLE_MESH_MSG_NET_BUF(msg)))); + + /* If the message is cancelled for advertising, then continue to retrieve the next + * message from that queue. + */ if (!bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(BLE_MESH_MSG_NET_BUF(msg)), 1, 0)) { bt_mesh_adv_buf_ref_debug(__func__, BLE_MESH_MSG_NET_BUF(msg), 1U, BLE_MESH_BUF_REF_EQUAL); + /* Cancel the adv task's reference to this data packet. - * tips: The reference of buffer by adv_task occurs - * when the buffer is pushed into the queue. + * Tips: + * The reference of buffer by adv_task occurs when the buffer is pushed into + * the queue. */ net_buf_unref(BLE_MESH_MSG_NET_BUF(msg)); - /* Avoid reading the last message in the queue, which could lead - * to pointing to an invalid buffer due to the absence of other - * messages in the queue. */ + + /* Avoid reading the last message in the queue, which could lead to pointing + * to an invalid buffer due to the absence of other messages in the queue. + */ msg->arg = NULL; continue; } #if CONFIG_BLE_MESH_RELAY_ADV_BUF - /* If the relay message should be ignored, - * then continue to retrieve the next message - * from that queue. */ + /* If the relay message should be ignored, then continue to retrieve the next message + * from that queue. + */ if (msg->relay && bt_mesh_ignore_relay_packet(msg->timestamp)) { /* If the interval between "current time - msg.timestamp" is bigger than * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. */ BT_DBG("Ignore relay packet"); + net_buf_unref(BLE_MESH_MSG_NET_BUF(msg)); msg->arg = NULL; continue; } -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + break; } @@ -259,38 +256,43 @@ static inline int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_ return 0; } -static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_duration) +static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_duration) { - uint32_t evts = 0; - uint16_t duration = K_FOREVER; uint16_t cur_min_duration = K_FOREVER; enum bt_mesh_adv_type adv_type = 0; - struct bt_mesh_adv_inst *instance = NULL; bt_mesh_queue_t *msg_queue = NULL; + uint16_t duration = K_FOREVER; bt_mesh_msg_t msg = {0}; uint32_t spt_mask = 0; + uint32_t evts = 0; + + BT_DBG("ActivateIdleAdvInst"); #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - if (!adv_insts[BLE_MESH_ADV_PROXY_INS].busy) { + if (!adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { BT_DBG("Mesh Proxy Advertising start"); + duration = bt_mesh_proxy_server_adv_start(); if (duration < cur_min_duration) { cur_min_duration = duration; } - adv_insts[BLE_MESH_ADV_PROXY_INS].busy = true; - evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INS].id); + + adv_insts[BLE_MESH_ADV_PROXY_INST].busy = true; + evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INST].id); } #endif - for (int i = BLE_MESH_ADV_INS; i < BLE_MESH_ADV_INS_TYPES_NUM; i++) { - instance = &adv_insts[i]; + for (int i = BLE_MESH_ADV_INST; i < BLE_MESH_ADV_INST_TYPES_NUM; i++) { + struct bt_mesh_adv_inst *instance = &adv_insts[i]; + if (instance->busy #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER - || unlikely(instance->id == CONFIG_BLE_MESH_PROXY_ADV_INST_ID) + CONFIG_BLE_MESH_GATT_PROXY_SERVER + || unlikely(instance->id == CONFIG_BLE_MESH_PROXY_ADV_INST_ID) #endif - ) { + ) { + BT_DBG("AdvInstSkipped, InstID %u Busy %u", instance->id, instance->busy); continue; } @@ -300,30 +302,38 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ while(spt_mask) { adv_type = find_lsb_set(spt_mask) - 1; spt_mask &= ~BIT(adv_type); - msg_queue = &(bt_mesh_adv_types_mgnt_get(adv_type)->adv_q->q); + msg_queue = &(bt_mesh_adv_types_mgmt_get(adv_type)->adv_q->q); - /* When there is no new message in the queue, *buf (aka: msg.arg) - * will be empty. */ + /* If no new message in the queue, the *buf (aka: msg.arg) will be empty */ if (find_valid_msg_from_queue(msg_queue, &msg)) { - BT_DBG("no valid message for instance %d", instance->id); + BT_DBG("NoMsgForAdvInst, InstID %u", instance->id); continue; } instance->sending_buf = (struct net_buf *)msg.arg; + if (adv_send(instance, &duration)) { - BT_ERR("adv start failed"); + /* When this adv instance fails to broadcast, it could be due to some + * persistent issues, such as incorrect adv parameter settings, or it + * could be due to some temporary issues, such as memory allocation + * failure. + * + * Therefore, it is advisable to skip subsequent queue reads for this + * instance and attempt to broadcast subsequent data again next time, + * rather than disabling the adv instance. + */ + BT_ERR("AdvSendFailed, InstID %u AdvType %u SptMask %08lx Buf %p", + instance->id, adv_type, instance->spt_mask, instance->sending_buf); + net_buf_unref(instance->sending_buf); instance->sending_buf = NULL; - /* When this adv instance fails to broadcast, it could be - * due to some persistent issues, such as incorrect adv - * parameter settings, or it could be due to some temporary - * issues, such as memory allocation failure. Therefore, it - * is advisable to skip subsequent queue reads for this instance - * and attempt to broadcast subsequent data again next time, - * rather than disabling the adv instance. */ break; } + BT_DBG("Activate, InstID %u AdvType %u SptMask %08lx Buf %p Duration %u/%u", + instance->id, adv_type, instance->spt_mask, + instance->sending_buf, duration, cur_min_duration); + if (duration < cur_min_duration) { cur_min_duration = duration; } @@ -331,14 +341,17 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ instance->busy = true; evts |= ADV_TASK_ADV_INST_EVT(adv_insts[i].id); - /* Must be nullified to avoid affecting the next adv - * instance's judgment on whether the message queue - * is empty. */ + /* Must be nullified to avoid affecting the next adv instance's judgment + * on whether the message queue is empty. + */ msg.arg = NULL; break; } } + BT_DBG("ActivateEnd, Duration %u UpdateEvts %08lx Evts%08lx", + cur_min_duration, *update_evts, evts); + *min_duration = cur_min_duration; *update_evts |= evts; @@ -347,30 +360,36 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ static uint32_t received_adv_evts_handle(uint32_t recv_evts) { - uint32_t evt = 0; + BT_DBG("RecvAdvEvtsHandle, RecvEvts 0x%08lx", recv_evts); if (!recv_evts) { return 0; } - for (int i = 0; recv_evts && i < BLE_MESH_ADV_INS_TYPES_NUM; i++) { - evt = ADV_TASK_ADV_INST_EVT(adv_insts[i].id); + for (int i = 0; recv_evts && i < BLE_MESH_ADV_INST_TYPES_NUM; i++) { + uint32_t evt = ADV_TASK_ADV_INST_EVT(adv_insts[i].id); + if (recv_evts & evt) { recv_evts &= ~evt; + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ -CONFIG_BLE_MESH_GATT_PROXY_SERVER - if (unlikely(i == BLE_MESH_ADV_PROXY_INS)) { + CONFIG_BLE_MESH_GATT_PROXY_SERVER + if (unlikely(i == BLE_MESH_ADV_PROXY_INST)) { BT_DBG("Mesh Proxy Advertising auto stop"); + bt_mesh_proxy_server_adv_flag_set(false); } else #endif { - /* adv_send_end maybe*/ - adv_send_end(0, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb_data); + adv_send_end(0, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb, + BLE_MESH_ADV(adv_insts[i].sending_buf)->cb_data); + bt_mesh_adv_buf_ref_debug(__func__, adv_insts[i].sending_buf, 4U, BLE_MESH_BUF_REF_SMALL); + net_buf_unref(adv_insts[i].sending_buf); adv_insts[i].sending_buf = NULL; } + adv_insts[i].busy = false; } } @@ -384,30 +403,31 @@ static void adv_thread(void *p) uint32_t recv_evts = 0; uint32_t wait_evts = 0; - BT_DBG("%s, starts", __func__); + BT_DBG("ExtAdvThread"); while (1) { adv_duration = K_FOREVER; wait_evts |= ADV_TASK_PKT_SEND_EVT; - active_idle_adv_instance(&wait_evts, &adv_duration); + activate_idle_adv_instance(&wait_evts, &adv_duration); - ble_mesh_adv_task_wait(wait_evts, adv_duration, &recv_evts); + bt_mesh_adv_task_wait(wait_evts, adv_duration, &recv_evts); + + BT_DBG("WaitEvts %08lx RecvEvts %08lx", wait_evts, recv_evts); wait_evts &= ~recv_evts; #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER if (recv_evts & ADV_TASK_PROXY_ADV_UPD_EVT) { - adv_insts[BLE_MESH_ADV_PROXY_INS].busy = false; + adv_insts[BLE_MESH_ADV_PROXY_INST].busy = false; recv_evts &= ~ADV_TASK_PROXY_ADV_UPD_EVT; } #endif - /** - * `recv_evts == ADV_TASK_PKT_SEND_EVT` indicates that new packets - * have been placed into the queue, and the advertising instances started - * previous have not yet stopped. + /* The `recv_evts == ADV_TASK_PKT_SEND_EVT` indicates that new packets + * have been put into the queue, and the advertising instances started + * previously have not yet been stopped. */ if (recv_evts == ADV_TASK_PKT_SEND_EVT) { continue; @@ -420,37 +440,42 @@ static void adv_thread(void *p) recv_evts = received_adv_evts_handle(recv_evts); if (recv_evts) { - BT_ERR("Remain evts %08x to handle", recv_evts); + BT_ERR("RecvEvts %08lx", recv_evts); } } } void bt_mesh_adv_update(void) { + BT_DBG("ExtAdvUpdate"); + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER BT_DBG("Mesh Proxy Advertising stopped manually"); + bt_mesh_proxy_server_adv_stop(); - if (adv_insts[BLE_MESH_ADV_PROXY_INS].busy) { - ble_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); + + if (adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { + bt_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); } #endif } void bt_mesh_adv_init(void) { + BT_DBG("ExtAdvInit"); + bt_mesh_adv_common_init(); adv_insts = bt_mesh_get_adv_insts_set(); - adv_queue = bt_mesh_adv_queue_get(); #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ bt_mesh_adv_task_init(adv_thread); } @@ -458,6 +483,8 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_deinit(void) { + BT_DBG("ExtAdvDeinit"); + bt_mesh_adv_task_deinit(); bt_mesh_adv_common_deinit(); @@ -466,10 +493,10 @@ void bt_mesh_adv_deinit(void) #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/core/ext_adv.h b/components/bt/esp_ble_mesh/core/ext_adv.h index 3004db27cdfc..eaa9c4f81973 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.h +++ b/components/bt/esp_ble_mesh/core/ext_adv.h @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,16 +20,10 @@ extern "C" { #endif -static inline void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - bt_mesh_generic_adv_send(buf, xmit, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, false); -} - void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); + void bt_mesh_adv_deinit(void); #ifdef __cplusplus diff --git a/components/bt/esp_ble_mesh/core/fast_prov.c b/components/bt/esp_ble_mesh/core/fast_prov.c index 049a12bb438c..5d34db8a0919 100644 --- a/components/bt/esp_ble_mesh/core/fast_prov.c +++ b/components/bt/esp_ble_mesh/core/fast_prov.c @@ -27,12 +27,15 @@ const uint8_t *bt_mesh_fast_prov_dev_key_get(uint16_t dst) { const uint8_t *key = NULL; + BT_DBG("FastProvDevKeyGet, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { BT_ERR("Invalid unicast address 0x%04x", dst); return NULL; } if (bt_mesh_is_provisioner_en() == false) { + BT_DBG("NodeDevKey"); return bt_mesh.dev_key; } @@ -42,9 +45,11 @@ const uint8_t *bt_mesh_fast_prov_dev_key_get(uint16_t dst) */ key = bt_mesh_provisioner_dev_key_get(dst); if (key) { + BT_DBG("PvnrDevKey"); return key; } + BT_DBG("NodeDevKeyFinal"); return bt_mesh.dev_key; } @@ -53,9 +58,12 @@ struct bt_mesh_subnet *bt_mesh_fast_prov_subnet_get(uint16_t net_idx) struct bt_mesh_subnet *sub = NULL; int i; + BT_DBG("FastProvSubnetGet, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { sub = &bt_mesh.sub[i]; if (sub->net_idx == net_idx) { + BT_DBG("NodeSub"); return sub; } } @@ -63,10 +71,12 @@ struct bt_mesh_subnet *bt_mesh_fast_prov_subnet_get(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { sub = bt_mesh.p_sub[i]; if (sub && sub->net_idx == net_idx) { + BT_DBG("PvnrSub"); return sub; } } + BT_DBG("NoSub"); return NULL; } @@ -75,10 +85,13 @@ struct bt_mesh_app_key *bt_mesh_fast_prov_app_key_find(uint16_t app_idx) struct bt_mesh_app_key *key = NULL; int i; + BT_DBG("FastProvAppKeyFind, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { key = &bt_mesh.app_keys[i]; if (key->net_idx != BLE_MESH_KEY_UNUSED && key->app_idx == app_idx) { + BT_DBG("NodeAppKey"); return key; } } @@ -87,15 +100,19 @@ struct bt_mesh_app_key *bt_mesh_fast_prov_app_key_find(uint16_t app_idx) key = bt_mesh.p_app_keys[i]; if (key && key->net_idx != BLE_MESH_KEY_UNUSED && key->app_idx == app_idx) { + BT_DBG("PvnrAppKey"); return key; } } + BT_DBG("NoAppKey"); return NULL; } uint8_t bt_mesh_set_fast_prov_net_idx(uint16_t net_idx) { + BT_DBG("SetFastProvNetIdx, NetIdx 0x%04x", net_idx); + /* Set net_idx for fast provisioning */ bt_mesh_provisioner_set_fast_prov_net_idx(net_idx); @@ -116,6 +133,8 @@ uint8_t bt_mesh_fast_prov_net_key_add(const uint8_t net_key[16]) net_idx = bt_mesh_provisioner_get_fast_prov_net_idx(); bt_mesh.p_net_idx_next = net_idx; + BT_DBG("FastProvNetKeyAdd, NetIdx 0x%04x", net_idx); + err = bt_mesh_provisioner_local_net_key_add(net_key, &net_idx); if (err) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); @@ -130,12 +149,16 @@ const uint8_t *bt_mesh_fast_prov_net_key_get(uint16_t net_idx) { struct bt_mesh_subnet *sub = NULL; + BT_DBG("FastProvNetKeyGet, NetIdx 0x%04x", net_idx); + sub = bt_mesh_fast_prov_subnet_get(net_idx); if (!sub) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); return NULL; } + BT_DBG("KrFlag %u", sub->kr_flag); + return (sub->kr_flag ? sub->keys[1].net : sub->keys[0].net); } @@ -143,17 +166,23 @@ const uint8_t *bt_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx) { struct bt_mesh_app_key *key = NULL; + BT_DBG("GetFastProvAppKey, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + key = bt_mesh_fast_prov_app_key_find(app_idx); if (!key) { BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); return NULL; } + BT_DBG("KeyUpdated %u", key->updated); + return (key->updated ? key->keys[1].val : key->keys[0].val); } uint8_t bt_mesh_set_fast_prov_action(uint8_t action) { + BT_DBG("SetFastProvAction, Action %u", action); + if (!action || action > ACTION_EXIT) { return 0x01; } @@ -168,9 +197,11 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_disable(); } + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_enable(); } + bt_mesh_provisioner_set_primary_elem_addr(bt_mesh_primary_addr()); bt_mesh_provisioner_set_prov_bearer(BLE_MESH_PROV_ADV, false); bt_mesh_provisioner_fast_prov_enable(true); @@ -179,11 +210,15 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_disable(); } + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_enable(); } + bt_mesh_atomic_and(bt_mesh.flags, ~(BIT(BLE_MESH_PROVISIONER) | BIT(BLE_MESH_VALID_PROV))); + bt_mesh_provisioner_fast_prov_enable(false); + if (action == ACTION_EXIT) { bt_mesh_provisioner_remove_node(NULL); } @@ -191,4 +226,5 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) return 0x0; } + #endif /* CONFIG_BLE_MESH_FAST_PROV */ diff --git a/components/bt/esp_ble_mesh/core/foundation.h b/components/bt/esp_ble_mesh/core/foundation.h index 4f3aa79ad11a..66f8c5ea2b8c 100644 --- a/components/bt/esp_ble_mesh/core/foundation.h +++ b/components/bt/esp_ble_mesh/core/foundation.h @@ -287,6 +287,7 @@ uint8_t bt_mesh_default_ttl_get(void); void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store); struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx); + void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store); static inline void key_idx_pack(struct net_buf_simple *buf, diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index 99e41cd099de..46060d3b0f24 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -69,6 +69,9 @@ static struct bt_mesh_subnet *friend_subnet_get(uint16_t net_idx) static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) { + BT_INFO("IsLPNUnicast, LPN 0x%04x NumElem %u Addr 0x%04x", + frnd->lpn, frnd->num_elem, addr); + if (frnd->lpn == BLE_MESH_ADDR_UNASSIGNED) { return false; } @@ -81,11 +84,16 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, { int i; - BT_DBG("net_idx 0x%04x lpn_addr 0x%04x", net_idx, lpn_addr); + BT_DBG("FrndFind"); + BT_DBG("NetIdx 0x%04x LPN 0x%04x Valid %u Established %u", + net_idx, lpn_addr, valid, established); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: LPN 0x%04x NetIdx 0x%04x Valid %u Established %u", + i, frnd->lpn, frnd->net_idx, frnd->valid, frnd->established); + if (valid && !frnd->valid) { continue; } @@ -108,11 +116,15 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, static void purge_buffers(sys_slist_t *list) { + BT_DBG("PurgeBuffers"); + while (!sys_slist_is_empty(list)) { struct net_buf *buf = NULL; buf = (void *)sys_slist_get_not_empty(list); + BT_DBG("Buf %p Ref %u", buf, buf->ref); + buf->frags = NULL; buf->flags &= ~NET_BUF_FRAGS; @@ -127,18 +139,21 @@ static void purge_buffers(sys_slist_t *list) */ static int32_t recv_delay(struct bt_mesh_friend *frnd) { + BT_DBG("RecvDelay, LPN 0x%04x RecvWin %u RecvDelay %u", + frnd->lpn, CONFIG_BLE_MESH_FRIEND_RECV_WIN, frnd->recv_delay); + #if CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 return (int32_t)frnd->recv_delay + (CONFIG_BLE_MESH_FRIEND_RECV_WIN / 5); -#else +#else /* CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 */ return frnd->recv_delay; -#endif +#endif /* CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 */ } static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) { int i; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("FrndClear, LPN 0x%04x Reason 0x%02x", frnd->lpn, reason); k_delayed_work_cancel(&frnd->timer); @@ -160,9 +175,13 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) friend_cred_del(frnd->net_idx, frnd->lpn); if (frnd->last) { + BT_DBG("FrndLast, Buf %p Ref %u PendingBuf %u", + frnd->last, frnd->last->ref, frnd->pending_buf); + /* Cancel the sending if necessary */ if (frnd->pending_buf) { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(frnd->last), 0); } else { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL); @@ -177,6 +196,8 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { struct bt_mesh_friend_seg *seg = &frnd->seg[i]; + BT_DBG("%u: SegCount %u", i, seg->seg_count); + purge_buffers(&seg->queue); seg->seg_count = 0U; } @@ -194,11 +215,13 @@ void bt_mesh_friend_clear_net_idx(uint16_t net_idx) { int i; - BT_DBG("net_idx 0x%04x", net_idx); + BT_DBG("FrndClearNetIdx, NetIdx 0x%04x", net_idx); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: LPN 0x%04x NetIdx 0x%04x", i, frnd->lpn, frnd->net_idx); + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { continue; } @@ -213,11 +236,13 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) { int i; - BT_DBG("net_idx 0x%04x", net_idx); + BT_DBG("FrndSecUpdate, NetIdx 0x%04x", net_idx); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: NetIdx 0x%04x", i, frnd->net_idx); + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { continue; } @@ -257,19 +282,21 @@ int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) }; struct bt_mesh_ctl_friend_clear_confirm cfm = {0}; + BT_DBG("FrndClear, NetIdx 0x%04x", rx->sub->net_idx); + if (buf->len < sizeof(*msg)) { - BT_WARN("Too short Friend Clear (len %d)", buf->len); + BT_WARN("Too short FriendClear (len %d)", buf->len); return -EINVAL; } lpn_addr = sys_be16_to_cpu(msg->lpn_addr); lpn_counter = sys_be16_to_cpu(msg->lpn_counter); - BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter); + BT_DBG("LPN 0x%04x Counter %u", lpn_addr, lpn_counter); frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", lpn_addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", lpn_addr); return 0; } @@ -305,6 +332,8 @@ static bool friend_sub_exist(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("IsFrndSubExist, Addr 0x%04x", addr); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { return true; @@ -318,6 +347,8 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("FrndSubAdd, Addr 0x%04x", addr); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == BLE_MESH_ADDR_UNASSIGNED) { frnd->sub_list[i] = addr; @@ -332,6 +363,8 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("FrndSubRem, Addr 0x%04x", addr); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { frnd->sub_list[i] = BLE_MESH_ADDR_UNASSIGNED; @@ -346,7 +379,9 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, { struct net_buf *buf = NULL; - buf = bt_mesh_adv_create_from_pool(BLE_MESH_ADV_FRIEND, K_NO_WAIT); + BT_DBG("CreatFrndPDU"); + + buf = bt_mesh_adv_create(BLE_MESH_ADV_FRIEND, K_NO_WAIT); if (!buf) { return NULL; } @@ -385,6 +420,10 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, uint16_t app_idx = FRIEND_ADV(buf)->app_idx; int err = 0; + BT_DBG("UnsegAppSduUnpack"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x RecvDst 0x%04x", + frnd->net_idx, app_idx, meta->net.ctx.recv_dst); + meta->subnet = friend_subnet_get(frnd->net_idx); if (!meta->subnet) { BT_ERR("Invalid subnet for unseg app sdu"); @@ -393,6 +432,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, meta->is_dev_key = (app_idx == BLE_MESH_KEY_DEV); bt_mesh_net_header_parse(&buf->b, &meta->net); + err = bt_mesh_upper_key_get(meta->subnet, app_idx, &meta->key, &meta->aid, meta->net.ctx.addr); if (err) { @@ -423,6 +463,8 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; + BT_DBG("UnsegAppSduDecrypt, SduLen %u", sdu.len); + return bt_mesh_app_decrypt(meta->key, meta->is_dev_key, 0, &sdu, &sdu, meta->ad, meta->net.ctx.addr, meta->net.ctx.recv_dst, meta->net.seq, @@ -439,6 +481,8 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; + BT_DBG("UnsegAppSduEncrypt, SduLen %u", sdu.len); + return bt_mesh_app_encrypt(meta->key, meta->is_dev_key, 0, &sdu, meta->ad, meta->net.ctx.addr, meta->net.ctx.recv_dst, bt_mesh.seq, @@ -451,6 +495,10 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta meta = {0}; int err = 0; + BT_DBG("UnsegAppSduPrepare"); + BT_DBG("LPN 0x%04x AppIdx 0x%04x Buf %p", + frnd->lpn, FRIEND_ADV(buf)->app_idx, buf); + if (FRIEND_ADV(buf)->app_idx == BLE_MESH_KEY_UNUSED) { return 0; } @@ -464,6 +512,7 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, * unchanged. */ if (meta.net.seq == bt_mesh.seq) { + BT_DBG("Seq 0x%06x", bt_mesh.seq); return 0; } @@ -491,8 +540,11 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, uint8_t nid = 0U; int err = 0; + BT_DBG("EncryptFrndPDU, LPN 0x%04x NetIdx 0x%04x Cred %u", + frnd->lpn, frnd->net_idx, master_cred); + if (!sub) { - BT_ERR("Invalid subnet to encrypt friend pdu"); + BT_ERR("NoSubToEncryptFrndPDU"); return -EINVAL; } @@ -502,7 +554,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, nid = sub->keys[sub->kr_flag].nid; } else { if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) { - BT_ERR("friend_cred_get failed"); + BT_ERR("FrndCredNotFound"); return -ENOENT; } } @@ -515,6 +567,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, if (FRIEND_ADV(buf)->app_idx != BLE_MESH_KEY_UNUSED) { err = unseg_app_sdu_prepare(frnd, buf); if (err) { + BT_DBG("UnsegAppSduPrepareFailed, Err %d", err); return err; } } @@ -529,15 +582,15 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi)); } + BT_DBG("Src 0x%04x NID 0x%02x IVIndex 0x%08lx", src, nid, iv_index); + buf->data[0] = (nid | (iv_index & 1) << 7); if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false, false)) { - BT_ERR("Encrypting failed"); return -EINVAL; } if (bt_mesh_net_obfuscate(buf->data, iv_index, priv)) { - BT_ERR("Obfuscating failed"); return -EINVAL; } @@ -550,7 +603,7 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd, { struct friend_pdu_info info = {0}; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("EncodeFrndCTL"); net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0)); @@ -564,21 +617,25 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd, info.iv_index = BLE_MESH_NET_IVI_TX; + BT_DBG("CTLOp 0x%02x IVIndex 0x%08lx", ctl_op, info.iv_index); + return create_friend_pdu(frnd, &info, sdu); } static struct net_buf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) { + struct bt_mesh_subnet *sub = friend_subnet_get(frnd->net_idx); struct bt_mesh_ctl_friend_update *upd = NULL; NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*upd)); - struct bt_mesh_subnet *sub = friend_subnet_get(frnd->net_idx); + + BT_DBG("EncodeUpdate, NetIdx 0x%04x", frnd->net_idx); if (!sub) { BT_ERR("Friend subnet 0x%04x not found", frnd->net_idx); return NULL; } - BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); + BT_DBG("LPN 0x%04x MD %u", frnd->lpn, md); net_buf_simple_reserve(&sdu, 1); @@ -596,7 +653,7 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*cfm)); struct net_buf *buf = NULL; - BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact); + BT_DBG("EnqueueSubCFM, LPN 0x%04x Xact 0x%02x", frnd->lpn, xact); net_buf_simple_reserve(&sdu, 1); @@ -614,7 +671,7 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) } if (frnd->last) { - BT_DBG("Discarding last PDU"); + BT_DBG("DiscardFrndLast, Buf %p Ref %u", frnd->last, frnd->last->ref); net_buf_unref(frnd->last); } @@ -624,9 +681,12 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) static void friend_recv_delay(struct bt_mesh_friend *frnd) { + int32_t delay = recv_delay(frnd); + + BT_INFO("FrndRecvDelay, Delay %ld", delay); + frnd->pending_req = 1U; - k_delayed_work_submit(&frnd->timer, recv_delay(frnd)); - BT_INFO("Waiting RecvDelay of %d ms", recv_delay(frnd)); + k_delayed_work_submit(&frnd->timer, delay); } int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, @@ -635,6 +695,8 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint8_t xact = 0U; + BT_DBG("FrndSubAdd"); + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { BT_WARN("Too short Friend Subscription Add (len %d)", buf->len); return -EINVAL; @@ -642,7 +704,7 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -666,6 +728,7 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, } if (friend_sub_exist(frnd, addr)) { + BT_DBG("FrndSubExist, Addr 0x%04x", addr); continue; } @@ -676,9 +739,9 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, #if CONFIG_BLE_MESH_DF_SRV return bt_mesh_directed_friend_solicitation(frnd, rx->sub); -#else +#else /* CONFIG_BLE_MESH_DF_SRV */ return 0; -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, @@ -687,6 +750,8 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint8_t xact = 0U; + BT_DBG("FrndSubRem"); + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { BT_WARN("Too short Friend Subscription Remove (len %d)", buf->len); return -EINVAL; @@ -694,7 +759,7 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -713,7 +778,7 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, if (!BLE_MESH_ADDR_IS_GROUP(addr) && !BLE_MESH_ADDR_IS_VIRTUAL(addr) && !BLE_MESH_ADDR_IS_FIXED_GROUP(addr)) { - BT_WARN("Invalid friend sub addr 0x%04x to remove", addr); + BT_WARN("InvalidFrndSub, Addr 0x%04x", addr); continue; } @@ -727,6 +792,8 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, static void enqueue_buf(struct bt_mesh_friend *frnd, struct net_buf *buf) { + BT_DBG("EnqueueBuf, Buf %p QueueSize %u", buf, frnd->queue_size); + net_buf_slist_put(&frnd->queue, buf); frnd->queue_size++; } @@ -735,6 +802,8 @@ static void enqueue_update(struct bt_mesh_friend *frnd, uint8_t md) { struct net_buf *buf = NULL; + BT_DBG("EnqueueUpdate, LPN 0x%04x MD %u", frnd->lpn, md); + buf = encode_update(frnd, md); if (!buf) { BT_ERR("Unable to encode Friend Update"); @@ -749,6 +818,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) struct bt_mesh_ctl_friend_poll *msg = (void *)buf->data; struct bt_mesh_friend *frnd = NULL; + BT_DBG("FrndPoll"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Poll (len %d)", buf->len); return -EINVAL; @@ -756,7 +827,7 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -770,12 +841,13 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) return 0; } - BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn); + BT_DBG("MsgFSN %u FrndFSN %u", (msg->fsn & 1), frnd->fsn); friend_recv_delay(frnd); if (!frnd->established) { - BT_INFO("Friendship established with 0x%04x", frnd->lpn); + BT_INFO("Friendship established with LPN 0x%04x", frnd->lpn); + frnd->established = 1U; if (friend_cb) { friend_cb(true, frnd->lpn, 0); @@ -783,7 +855,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (msg->fsn == frnd->fsn && frnd->last) { - BT_DBG("Re-sending last PDU"); + BT_DBG("ResendFrndLast"); + frnd->send_last = 1U; } else { if (frnd->last) { @@ -794,8 +867,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) frnd->fsn = msg->fsn; if (sys_slist_is_empty(&frnd->queue)) { + BT_DBG("EnqueueFrndUpdate"); enqueue_update(frnd, 0); - BT_DBG("Enqueued Friend Update to empty queue"); } } @@ -806,6 +879,8 @@ static struct bt_mesh_friend *find_clear(uint16_t prev_friend) { int i; + BT_DBG("FindClear, PrevFrnd 0x%04x", prev_friend); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -821,6 +896,8 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; + BT_DBG("FrndClearSent, RepeatSec %u Err %d", frnd->clear.repeat_sec, err); + k_delayed_work_submit(&frnd->clear.timer, K_SECONDS(frnd->clear.repeat_sec)); frnd->clear.repeat_sec *= 2U; @@ -852,6 +929,8 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter), }; + BT_DBG("SendFrndClear, Addr 0x%04x", frnd->clear.frnd); + if (!tx.sub) { BT_ERR("Invalid subnet for Friend Clear"); return; @@ -863,13 +942,15 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) static void clear_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - clear.timer.work); + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, clear.timer.work); uint32_t duration = 0U; - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - duration = k_uptime_get_32() - frnd->clear.start; + + BT_DBG("ClearTimeout"); + BT_DBG("LPN 0x%04x Frnd 0x%04x Duration %lu PollTo %ld", + frnd->lpn, frnd->clear.frnd, duration, frnd->poll_to); + if (duration > 2 * frnd->poll_to) { BT_DBG("Clear Procedure timer expired"); frnd->clear.frnd = BLE_MESH_ADDR_UNASSIGNED; @@ -881,11 +962,13 @@ static void clear_timeout(struct k_work *work) static void clear_procedure_start(struct bt_mesh_friend *frnd) { - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - frnd->clear.start = k_uptime_get_32(); frnd->clear.repeat_sec = 1U; + BT_DBG("ClearProcedureStart"); + BT_DBG("LPN 0x%04x Frnd 0x%04x ClearStart %lu", + frnd->lpn, frnd->clear.frnd, frnd->clear.start); + send_friend_clear(frnd); } @@ -896,6 +979,8 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint16_t lpn_addr = 0U, lpn_counter = 0U; + BT_DBG("FrndClearCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Clear Confirm (len %d)", buf->len); return -EINVAL; @@ -933,6 +1018,9 @@ static void enqueue_offer(struct bt_mesh_friend *frnd, int8_t rssi) NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*off)); struct net_buf *buf = NULL; + BT_DBG("EnqueueOffset"); + BT_DBG("LPN 0x%04x Counter %u Rssi %d", frnd->lpn, frnd->counter, rssi); + net_buf_simple_reserve(&sdu, 1); off = net_buf_simple_add(&sdu, sizeof(*off)); @@ -977,7 +1065,7 @@ static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t cri static const uint8_t fact[] = { 10, 15, 20, 25 }; int32_t delay = 0; - BT_INFO("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d", + BT_INFO("RecvWinFactor %u RecvWin %u RssiFactor %u Rssi %d", fact[RECV_WIN_FACT(crit)], RECV_WIN, fact[RSSI_FACT(crit)], rssi); @@ -986,7 +1074,7 @@ static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t cri delay -= (int32_t)fact[RSSI_FACT(crit)] * rssi; delay /= 10; - BT_DBG("Local Delay calculated as %d ms", delay); + BT_DBG("OfferDelay %d", delay); if (delay < 100) { return K_MSEC(100); @@ -1002,13 +1090,15 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) uint32_t poll_to = 0U; int i; + BT_DBG("FrndReq"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Request (len %d)", buf->len); return -EINVAL; } if (msg->recv_delay <= 0x09) { - BT_WARN("Prohibited ReceiveDelay (0x%02x)", msg->recv_delay); + BT_WARN("Prohibited RecvDelay (0x%02x)", msg->recv_delay); return -EINVAL; } @@ -1035,7 +1125,7 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) { - BT_WARN("We have a too small Friend Queue size (%u < %u)", + BT_WARN("Too small Friend Queue size (%u < %u)", CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, MIN_QUEUE_SIZE(msg->criteria)); return 0; @@ -1070,11 +1160,10 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter); frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr); - BT_INFO("LPN 0x%04x rssi %d recv_delay %u poll_to %ums", - frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, frnd->poll_to); + BT_INFO("LPN 0x%04x Rssi %d RecvDelay %u PollTo %u", + frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, frnd->poll_to); - /** - * Spec says: + /* Spec says: * After a friendship has been established, if the PreviousAddress field * of the Friend Request message contains a valid unicast address that is * not the Friend node’s own unicast address, then the Friend node shall @@ -1086,11 +1175,9 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } k_delayed_work_submit(&frnd->timer, - offer_delay(frnd, rx->ctx.recv_rssi, - msg->criteria)); + offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria)); - friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, - frnd->counter); + friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, frnd->counter); enqueue_offer(frnd, rx->ctx.recv_rssi); @@ -1104,6 +1191,8 @@ static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_ze uint16_t buf_seq_zero = 0U; uint16_t buf_src = 0U; + BT_DBG("IsSeg, Buf %p", buf); + if (!buf) { return false; } @@ -1125,6 +1214,9 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd, struct bt_mesh_friend_seg *unassigned = NULL; int i; + BT_DBG("GetSeg, Src 0x%04x SeqZero 0x%04x SegCount %u", + src, seq_zero, seg_count); + for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { struct bt_mesh_friend_seg *seg = &frnd->seg[i]; @@ -1150,15 +1242,18 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf) { struct bt_mesh_friend_seg *seg = NULL; + uint16_t seq_zero = 0; - BT_DBG("type %u", type); + BT_DBG("EnqueueFrndPDU, Type %u", type); if (type == BLE_MESH_FRIEND_PDU_SINGLE) { enqueue_buf(frnd, buf); return; } - uint16_t seq_zero = (((buf->data[10] << 8 | buf->data[11]) >> 2) & TRANS_SEQ_ZERO_MASK); + seq_zero = (((buf->data[10] << 8 | buf->data[11]) >> 2) & TRANS_SEQ_ZERO_MASK); + + BT_DBG("Src 0x%04x SegCount %u SegZero 0x%04x", src, seg_count, seq_zero); seg = get_seg(frnd, src, seq_zero, seg_count); if (!seg) { @@ -1184,7 +1279,7 @@ static void buf_send_start(uint16_t duration, int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - BT_DBG("err %d", err); + BT_DBG("BufSendStart, Err %d", err); frnd->pending_buf = 0U; @@ -1199,7 +1294,7 @@ static void buf_send_end(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - BT_DBG("err %d", err); + BT_DBG("BufSendEnd, Err %d", err); if (frnd->pending_req) { BT_WARN("Another request before previous completed sending"); @@ -1207,47 +1302,48 @@ static void buf_send_end(int err, void *user_data) } if (frnd->established) { + BT_DBG("WaitForNextPoll %u", frnd->poll_to); + k_delayed_work_submit(&frnd->timer, frnd->poll_to); - BT_DBG("Waiting %u ms for next poll", frnd->poll_to); } else { /* Friend offer timeout is 1 second */ + BT_DBG("WaitForFirstPoll"); + k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); - BT_DBG("Waiting for first poll"); } } static void friend_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - timer.work); + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, timer.work); static const struct bt_mesh_send_cb buf_sent_cb = { .start = buf_send_start, .end = buf_send_end, }; + BT_DBG("FrndTimeout"); + if (frnd->pending_buf != 0U) { BT_ERR("Previous buffer not yet sent!"); return; } - BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, - frnd->send_last, frnd->last); + BT_DBG("LPN 0x%04x SendLast %u FrndLast %p", frnd->lpn, frnd->send_last, frnd->last); if (frnd->send_last && frnd->last) { - BT_DBG("Sending frnd->last %p", frnd->last); frnd->send_last = 0U; goto send_last; } if (frnd->established && !frnd->pending_req) { - BT_WARN("Friendship lost with 0x%04x", frnd->lpn); + BT_WARN("FriendshipLost, LPN 0x%04x", frnd->lpn); friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_POLL_TIMEOUT); return; } frnd->last = (void *)sys_slist_get(&frnd->queue); if (!frnd->last) { - BT_WARN("Friendship not established with 0x%04x", frnd->lpn); + BT_WARN("FriendshipNotEstablished, LPN 0x%04x", frnd->lpn); friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_ESTABLISH_FAIL); return; } @@ -1260,8 +1356,9 @@ static void friend_timeout(struct k_work *work) frnd->last->flags &= ~NET_BUF_FRAGS; frnd->last->frags = NULL; - BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", - frnd->last, frnd->lpn); + BT_DBG("SendBufFromFrndQueue, Last %p QueueSize %u LPN 0x%04x", + frnd->last, frnd->queue_size, frnd->lpn); + frnd->queue_size--; send_last: @@ -1279,6 +1376,8 @@ int bt_mesh_friend_init(void) { int i; + BT_DBG("FrndInit"); + if (friend_init == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1312,6 +1411,8 @@ int bt_mesh_friend_deinit(void) { int i; + BT_DBG("FrndDeinit"); + if (friend_init == false) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1341,6 +1442,8 @@ static bool is_segack(struct net_buf *buf, const uint64_t *seqauth, uint16_t src struct net_buf_simple_state state = {0}; bool found = false; + BT_DBG("IsSegAck, Len %u", buf->len); + if (buf->len != 16) { return false; } @@ -1350,23 +1453,27 @@ static bool is_segack(struct net_buf *buf, const uint64_t *seqauth, uint16_t src net_buf_skip(buf, 1); /* skip IVI, NID */ if (!(net_buf_pull_u8(buf) >> 7)) { + BT_DBG("Not SegAck"); goto end; } net_buf_pull(buf, 3); /* skip SEQNUM */ if (src != net_buf_pull_be16(buf)) { + BT_DBG("SrcNotSegAck"); goto end; } net_buf_skip(buf, 2); /* skip dst */ - if (TRANS_CTL_OP((uint8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) { + if (TRANS_CTL_OP((uint8_t *)net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) { + BT_DBG("OpNotSegAck"); goto end; } - found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == - (*seqauth & TRANS_SEQ_ZERO_MASK); + found = (((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == + (*seqauth & TRANS_SEQ_ZERO_MASK)); + end: net_buf_simple_restore(&buf->b, &state); return found; @@ -1377,17 +1484,18 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, { sys_snode_t *cur = NULL, *prev = NULL; - BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src); + BT_DBG("FrndPurgeOldAck, SeqAuth %llx Src 0x%04x", *seq_auth, src); for (cur = sys_slist_peek_head(&frnd->queue); - cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) { + cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) { struct net_buf *buf = (void *)cur; if (is_segack(buf, seq_auth, src)) { - BT_DBG("Removing old ack from Friend Queue"); + BT_DBG("RemoveOldAckFromFrndQueue, QueueSize %u", frnd->queue_size); sys_slist_remove(&frnd->queue, prev, cur); frnd->queue_size--; + /* Make sure old slist entry state doesn't remain */ buf->frags = NULL; @@ -1406,6 +1514,9 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, struct friend_pdu_info info = {0}; struct net_buf *buf = NULL; + BT_DBG("FrndLPNEnqueueRx, LPN 0x%04x QueueSize %u Type 0x%02x", + frnd->lpn, frnd->queue_size, type); + /* Because of network loopback, tx packets will also be passed into * this rx function. These packets have already been added to the * queue, and should be ignored. @@ -1414,8 +1525,6 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, return; } - BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn, frnd->queue_size); - if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr); } @@ -1443,7 +1552,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - BT_DBG("Queued message for LPN 0x%04x, queue_size %u", + BT_DBG("QueuedMsg, LPN 0x%04x QueueSize %u", frnd->lpn, frnd->queue_size); } @@ -1456,7 +1565,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, struct friend_pdu_info info = {0}; struct net_buf *buf = NULL; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("FrndLPNEnqueueTx, LPN 0x%04x Type 0x%02x", frnd->lpn, type); if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { friend_purge_old_ack(frnd, seq_auth, tx->src); @@ -1488,7 +1597,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - BT_DBG("Queued message for LPN 0x%04x", frnd->lpn); + BT_DBG("QueuedMsg, LPN 0x%04x", frnd->lpn); } static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, @@ -1496,6 +1605,10 @@ static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, { int i; + BT_DBG("IsFrndLPNMatch"); + BT_DBG("LPN 0x%04x NetIdx 0x%04x/0x%04x Addr 0x%04x Established %u", + frnd->lpn, net_idx, frnd->net_idx, addr, frnd->established); + if (!frnd->established) { return false; } @@ -1521,12 +1634,13 @@ bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr) { int i; + BT_DBG("FrndMatch, NetIdx 0x%04x Addr 0x%04x", net_idx, addr); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; if (friend_lpn_matches(frnd, net_idx, addr)) { - BT_DBG("LPN 0x%04x matched address 0x%04x", - frnd->lpn, addr); + BT_DBG("LPNMatch, LPN 0x%04x Addr 0x%04x", frnd->lpn, addr); return true; } } @@ -1540,6 +1654,8 @@ bool bt_mesh_friend_unicast_match(uint16_t net_idx, uint16_t addr, uint8_t *sele { int i; + BT_DBG("FrndUnicastMatch, NetIdx 0x%04x addr 0x%04x", net_idx, addr); + if (!BLE_MESH_ADDR_IS_UNICAST(addr) || selem == NULL) { BT_ERR("%s, Invalid parameter", __func__); return false; @@ -1565,6 +1681,10 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, uint32_t total = 0U; int i; + BT_DBG("IsFrndQueueHasSpace"); + BT_DBG("LPN 0x%04x SegCount %u QueueSize %u Addr 0x%04x", + frnd->lpn, seg_count, CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, addr); + if (seg_count > CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE) { return false; } @@ -1573,8 +1693,8 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, struct bt_mesh_friend_seg *seg = &frnd->seg[i]; if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) { - /* If there's a segment queue for this message then the - * space verification has already happened. + /* If there's a segment queue for this message then the space + * verification has already happened. */ return true; } @@ -1582,6 +1702,8 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, total += seg->seg_count; } + BT_DBG("TotalCount %u", total); + /* If currently pending segments combined with this segmented message * are more than the Friend Queue Size, then there's no space. This * is because we don't have a mechanism of aborting already pending @@ -1596,6 +1718,10 @@ bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst bool someone_has_space = false, friend_match = false; int i; + BT_DBG("FrndQueueHasSpace"); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x SegCount %u", + net_idx, src, dst, seg_count); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1614,6 +1740,7 @@ bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst * transport layer can continue its work. */ if (!friend_match) { + BT_DBG("NoMatchLPN"); return true; } @@ -1631,6 +1758,9 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add bool pending_segments = false; uint8_t avail_space = 0U; + BT_DBG("FrndQueuePrepareSpace"); + BT_DBG("LPN 0x%04x Addr 0x%04x SegCount %u", frnd->lpn, addr, seg_count); + if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) { return false; } @@ -1646,6 +1776,9 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add return false; } + BT_DBG("PendingSeg %u AvailSpace %u QueueSize %u", + pending_segments, avail_space, frnd->queue_size); + frnd->queue_size--; avail_space++; @@ -1668,15 +1801,19 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, { int i; + BT_DBG("FrndEnqueueRx"); + BT_DBG("FrndMatch %u RecvTTL %u NetIf %u FrndGet %u", + rx->friend_match, rx->ctx.recv_ttl, rx->net_if, + bt_mesh_friend_get()); + if (!rx->friend_match || (rx->ctx.recv_ttl <= 1U && rx->net_if != BLE_MESH_NET_IF_LOCAL) || bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return; } - BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x", - rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr, - rx->ctx.recv_dst); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x", + rx->sub->net_idx, rx->ctx.addr, rx->ctx.recv_dst); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1691,8 +1828,7 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, continue; } - friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count, - sbuf); + friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count, sbuf); } } @@ -1704,14 +1840,15 @@ bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, bool matched = false; int i; + BT_DBG("FrndEnqueueTx"); + BT_DBG("NetIdx 0x%04x Dst 0x%04x Src 0x%04x FrndState %u", + tx->sub->net_idx, tx->ctx->addr, tx->src, bt_mesh_friend_get()); + if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) || bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return matched; } - BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx, - tx->ctx->addr, tx->src); - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1738,6 +1875,9 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, { int i; + BT_DBG("FrndClearComplete"); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x", sub->net_idx, src, dst); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; int j; @@ -1766,6 +1906,8 @@ void bt_mesh_friend_remove_lpn(uint16_t lpn_addr) { struct bt_mesh_friend *frnd = NULL; + BT_DBG("FrndRemoveLPN, Addr 0x%04x", lpn_addr); + frnd = bt_mesh_friend_find(BLE_MESH_KEY_ANY, lpn_addr, false, false); if (frnd) { friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_DISABLE); diff --git a/components/bt/esp_ble_mesh/core/health_cli.c b/components/bt/esp_ble_mesh/core/health_cli.c index 1e03d93513c4..c458710db125 100644 --- a/components/bt/esp_ble_mesh/core/health_cli.c +++ b/components/bt/esp_ble_mesh/core/health_cli.c @@ -68,6 +68,8 @@ static void health_client_recv_status(struct bt_mesh_model *model, struct net_buf_simple buf = {0}; uint8_t evt_type = 0xFF; + BT_DBG("HealthClientRecvStatus"); + if (!model || !ctx || !status || !len) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -83,6 +85,8 @@ static void health_client_recv_status(struct bt_mesh_model *model, if (!node) { BT_DBG("Unexpected Health Status 0x%04x", ctx->recv_op); } else { + BT_DBG("OpCode 0x%08lx RecvOp 0x%08lx", node->opcode, ctx->recv_op); + switch (node->opcode) { case OP_HEALTH_FAULT_GET: case OP_HEALTH_PERIOD_GET: @@ -131,9 +135,10 @@ static void health_fault_status(struct bt_mesh_model *model, { struct bt_mesh_health_fault_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthFaultStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -154,9 +159,10 @@ static void health_current_status(struct bt_mesh_model *model, { struct bt_mesh_health_current_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthCurrentStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -177,9 +183,10 @@ static void health_period_status(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthPeriodStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -192,9 +199,10 @@ static void health_attention_status(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthAttentionStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -213,6 +221,8 @@ int bt_mesh_health_attention_get(bt_mesh_client_common_param_t *param) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_GET, 0); + BT_DBG("HealthAttentionGet"); + bt_mesh_model_msg_init(&msg, OP_ATTENTION_GET); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -223,6 +233,8 @@ int bt_mesh_health_attention_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_SET, 1); + BT_DBG("HealthAttentionSet, Attention 0x%02x NeedAck %u", attention, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_ATTENTION_SET : OP_ATTENTION_SET_UNREL); net_buf_simple_add_u8(&msg, attention); @@ -233,6 +245,8 @@ int bt_mesh_health_period_get(bt_mesh_client_common_param_t *param) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_GET, 0); + BT_DBG("HealthPeriodGet"); + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_GET); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -243,6 +257,8 @@ int bt_mesh_health_period_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_SET, 1); + BT_DBG("HealthPeriodSet, Divisor 0x%02x NeedAck %u", divisor, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_PERIOD_SET : OP_HEALTH_PERIOD_SET_UNREL); net_buf_simple_add_u8(&msg, divisor); @@ -254,6 +270,8 @@ int bt_mesh_health_fault_test(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_TEST, 3); + BT_DBG("HealthFaultTest, CID 0x%04x TestID 0x%04x NeedAck %u", cid, test_id, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_FAULT_TEST : OP_HEALTH_FAULT_TEST_UNREL); net_buf_simple_add_u8(&msg, test_id); net_buf_simple_add_le16(&msg, cid); @@ -266,6 +284,8 @@ int bt_mesh_health_fault_clear(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_CLEAR, 2); + BT_DBG("HealthFaultClear, CID 0x%04x NeedAck %u", cid, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_FAULT_CLEAR : OP_HEALTH_FAULT_CLEAR_UNREL); net_buf_simple_add_le16(&msg, cid); @@ -276,6 +296,8 @@ int bt_mesh_health_fault_get(bt_mesh_client_common_param_t *param, uint16_t cid) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_GET, 2); + BT_DBG("HealthFaultGet, CID 0x%04x", cid); + bt_mesh_model_msg_init(&msg, OP_HEALTH_FAULT_GET); net_buf_simple_add_le16(&msg, cid); @@ -287,6 +309,8 @@ static int health_cli_init(struct bt_mesh_model *model) health_internal_data_t *internal = NULL; bt_mesh_health_client_t *client = NULL; + BT_DBG("HealthCliInit"); + if (!model) { BT_ERR("Invalid Health Client model"); return -EINVAL; @@ -328,6 +352,8 @@ static int health_cli_deinit(struct bt_mesh_model *model) { bt_mesh_health_client_t *client = NULL; + BT_DBG("HealthCliDeinit"); + if (!model) { BT_ERR("Invalid Health Client model"); return -EINVAL; diff --git a/components/bt/esp_ble_mesh/core/health_srv.c b/components/bt/esp_ble_mesh/core/health_srv.c index a27e4547b211..f7db34babb3f 100644 --- a/components/bt/esp_ble_mesh/core/health_srv.c +++ b/components/bt/esp_ble_mesh/core/health_srv.c @@ -26,8 +26,7 @@ /* Health Server context of the primary element */ struct bt_mesh_health_srv *health_srv; -/** - * When an Element receives a Health Fault Get, or a Health Fault Test, or +/* When an Element receives a Health Fault Get, or a Health Fault Test, or * a Health Fault Test Unacknowledged, or a Health Fault Clear, or a Health * Fault Clear Unacknowledged message that is not successfully processed * (i.e. the Company ID field that does not identify any Health Fault state @@ -48,6 +47,8 @@ static uint8_t health_get_curr_fault_count(struct bt_mesh_model *model) } } + BT_DBG("HealthGetCurrFaultCount, Count %u", count); + return count; } @@ -61,6 +62,8 @@ static void health_get_fault_value(struct bt_mesh_model *model, array_size = current ? ARRAY_SIZE(srv->test.curr_faults) : ARRAY_SIZE(srv->test.reg_faults); + BT_DBG("HealthGetFaultValue, Current %u Size %lu", current, array_size); + for (i = 0U; i < array_size; i++) { if (net_buf_simple_tailroom(msg) == 0) { return; @@ -70,6 +73,8 @@ static void health_get_fault_value(struct bt_mesh_model *model, if (fault != HEALTH_NO_FAULT) { net_buf_simple_add_u8(msg, fault); } + + BT_DBG("%u: Fault 0x%02x", i, fault); } } @@ -78,12 +83,16 @@ static bool health_is_test_id_exist(struct bt_mesh_model *model, uint8_t test_id struct bt_mesh_health_srv *srv = model->user_data; int i; + BT_DBG("HealthIsTestIDExist, TestID 0x%02x", test_id); + for (i = 0; i < srv->test.id_count; i++) { if (srv->test.test_ids[i] == test_id) { + BT_DBG("TestIDExist"); return true; } } + BT_DBG("TestIDNotExist"); return false; } @@ -94,19 +103,23 @@ static int health_send_fault_status(struct bt_mesh_model *model, struct net_buf_simple *msg = NULL; int err = 0; + BT_DBG("HealthSendFaultStatus"); + msg = bt_mesh_alloc_buf(4 + ARRAY_SIZE(srv->test.reg_faults) + 4); if (!msg) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; } + BT_DBG("TestID 0x%02x CID 0x%04x", + srv->test.prev_test_id, srv->test.company_id); + bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS); net_buf_simple_add_u8(msg, srv->test.prev_test_id); net_buf_simple_add_le16(msg, srv->test.company_id); if (ctx->recv_op != OP_HEALTH_FAULT_CLEAR) { - /** - * For Health Fault Clear, the FaultArray field in Health Fault Status - * shall be empty. + /* For Health Fault Clear, the FaultArray field + * in Health Fault Status shall be empty. */ health_get_fault_value(model, msg, false); } @@ -127,6 +140,8 @@ static void health_fault_get(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id = 0U; + BT_DBG("HealthFaultGet"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -138,7 +153,7 @@ static void health_fault_get(struct bt_mesh_model *model, return; } - BT_DBG("company_id 0x%04x", company_id); + BT_DBG("CID 0x%04x", company_id); health_send_fault_status(model, ctx); } @@ -150,6 +165,8 @@ static void health_fault_clear(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id = 0U; + BT_DBG("HealthFaultClear"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -161,7 +178,7 @@ static void health_fault_clear(struct bt_mesh_model *model, return; } - BT_DBG("company_id 0x%04x", company_id); + BT_DBG("CID 0x%04x", company_id); memset(srv->test.reg_faults, HEALTH_NO_FAULT, ARRAY_SIZE(srv->test.reg_faults)); @@ -182,6 +199,8 @@ static void health_fault_test(struct bt_mesh_model *model, uint16_t company_id = 0U; uint8_t test_id = 0U; + BT_DBG("HealthFaultTest"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -199,7 +218,7 @@ static void health_fault_test(struct bt_mesh_model *model, return; } - BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); + BT_DBG("TestID 0x%02x CID 0x%04x", test_id, company_id); srv->test.prev_test_id = test_id; @@ -219,13 +238,16 @@ static void send_attention_status(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint8_t time = 0U; + BT_DBG("SendAttentionStatus"); + if (!srv) { BT_ERR("No Health Server context provided"); return; } time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; - BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + + BT_DBG("Time %u", time); bt_mesh_model_msg_init(&msg, OP_ATTENTION_STATUS); net_buf_simple_add_u8(&msg, time); @@ -239,6 +261,8 @@ static void attention_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("AttentionGet"); + send_attention_status(model, ctx); } @@ -250,7 +274,7 @@ static void health_set_attention(struct bt_mesh_model *model, time = net_buf_simple_pull_u8(buf); - BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + BT_DBG("HealthSetAttention, Time %u", time); bt_mesh_attention(model, time); } @@ -259,6 +283,8 @@ static void attention_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("AttentionSet"); + health_set_attention(model, ctx, buf); if (ctx->recv_op == OP_ATTENTION_SET) { @@ -271,6 +297,8 @@ static void send_health_period_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_STATUS, 1); + BT_DBG("SendHealthPeriodStatus"); + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_STATUS); net_buf_simple_add_u8(&msg, model->pub->period_div); @@ -283,6 +311,8 @@ static void health_period_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("HealthPeriodGet"); + send_health_period_status(model, ctx); } @@ -292,13 +322,15 @@ static void health_set_period(struct bt_mesh_model *model, { uint8_t period = 0U; + BT_DBG("HealthSetPeriod"); + period = net_buf_simple_pull_u8(buf); if (period > 15) { BT_WARN("Prohibited period value %u", period); return; } - BT_DBG("period %u", period); + BT_DBG("Period %u", period); model->pub->period_div = period; } @@ -307,6 +339,8 @@ static void health_period_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("HealthPeriodSet"); + health_set_period(model, ctx, buf); if (ctx->recv_op == OP_HEALTH_PERIOD_SET) { @@ -334,6 +368,8 @@ static size_t health_get_current(struct bt_mesh_model *model, { struct bt_mesh_health_srv *srv = model->user_data; + BT_DBG("HealthGetCurrent"); + if (!srv) { BT_ERR("No Health Server context provided"); return 0; @@ -344,6 +380,9 @@ static size_t health_get_current(struct bt_mesh_model *model, return 0; } + BT_DBG("TestID 0x%02x CID 0x%04x", + srv->test.prev_test_id, srv->test.company_id); + bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); net_buf_simple_add_u8(msg, srv->test.prev_test_id); net_buf_simple_add_le16(msg, srv->test.company_id); @@ -357,6 +396,8 @@ static int health_pub_update(struct bt_mesh_model *model) struct bt_mesh_model_pub *pub = model->pub; size_t count = 0U; + BT_DBG("HealthPubUpdate"); + if (!pub || !pub->msg) { BT_ERR("Invalid health publication context"); return -EINVAL; @@ -369,6 +410,8 @@ static int health_pub_update(struct bt_mesh_model *model) pub->fast_period = 0U; } + BT_DBG("Count %lu", count); + return 0; } @@ -376,6 +419,8 @@ int bt_mesh_fault_update(struct bt_mesh_elem *elem) { struct bt_mesh_model *model = NULL; + BT_DBG("FaultUpdate"); + model = bt_mesh_model_find(elem, BLE_MESH_MODEL_ID_HEALTH_SRV); if (!model) { BT_ERR("Health Server not exists"); @@ -409,6 +454,8 @@ static void attention_off(struct k_work *work) return; } + BT_DBG("AttentionOff"); + if (srv->cb.attn_off) { srv->cb.attn_off(srv->model); } @@ -423,6 +470,8 @@ static int health_srv_init(struct bt_mesh_model *model) * supported by any secondary elements. */ + BT_DBG("HealthSrvInit"); + if (!srv) { BT_ERR("No Health Server context provided"); return -EINVAL; @@ -433,6 +482,8 @@ static int health_srv_init(struct bt_mesh_model *model) return -EINVAL; } + BT_DBG("TestIDCount %u", srv->test.id_count); + if (!model->pub) { BT_ERR("Health Server has no publication support"); return -EINVAL; @@ -460,6 +511,8 @@ static int health_srv_deinit(struct bt_mesh_model *model) { struct bt_mesh_health_srv *srv = model->user_data; + BT_DBG("HealthSrvDeinit"); + if (!srv) { BT_ERR("No Health Server context provided"); return -EINVAL; @@ -499,6 +552,8 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) { struct bt_mesh_health_srv *srv = NULL; + BT_DBG("Attention, Time %u", time); + if (!model) { srv = health_srv; if (!srv) { diff --git a/components/bt/esp_ble_mesh/core/heartbeat.c b/components/bt/esp_ble_mesh/core/heartbeat.c index 4ff63a13abe0..4324da322342 100644 --- a/components/bt/esp_ble_mesh/core/heartbeat.c +++ b/components/bt/esp_ble_mesh/core/heartbeat.c @@ -21,11 +21,15 @@ static uint16_t hb_sub_dst = BLE_MESH_ADDR_UNASSIGNED; void bt_mesh_set_hb_sub_dst(uint16_t addr) { + BT_DBG("SetHbSubDst 0x%04x", addr); + hb_sub_dst = addr; } uint16_t bt_mesh_get_hb_sub_dst(void) { + BT_DBG("GetHbSubDst 0x%04x", hb_sub_dst); + return hb_sub_dst; } @@ -33,6 +37,9 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + BT_DBG("HeartbeatRecv"); + BT_DBG("Src 0x%04x Dst 0x%04x Hops %u Feat 0x%04x", src, dst, hops, feat); + if (cfg == NULL) { BT_WARN("No configuration server context available"); return; @@ -55,9 +62,8 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f cfg->hb_sub.count++; } - BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src, - dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, - cfg->hb_sub.count); + BT_DBG("MinHops %u MaxHops %u Count %u", + cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, cfg->hb_sub.count); if (cfg->hb_sub.func) { cfg->hb_sub.func(hops, feat); @@ -67,7 +73,6 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f void bt_mesh_heartbeat_send(void) { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); - uint16_t feat = 0U; struct __attribute__((packed)) { uint8_t init_ttl; uint16_t feat; @@ -85,6 +90,9 @@ void bt_mesh_heartbeat_send(void) .src = bt_mesh_model_elem(cfg->model)->addr, .xmit = bt_mesh_net_transmit_get(), }; + uint16_t feat = 0U; + + BT_DBG("HeartbeatSend, Dst 0x%04x", cfg->hb_pub.dst); /* Do nothing if heartbeat publication is not enabled */ if (cfg->hb_pub.dst == BLE_MESH_ADDR_UNASSIGNED) { @@ -111,7 +119,7 @@ void bt_mesh_heartbeat_send(void) hb.feat = sys_cpu_to_be16(feat); - BT_INFO("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat); + BT_INFO("InitTTL %u Feat 0x%04x", cfg->hb_pub.ttl, feat); bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), NULL, NULL); @@ -149,6 +157,8 @@ int bt_mesh_pvnr_register_hb_recv_cb(bt_mesh_pvnr_hb_recv_cb_t cb) int bt_mesh_pvnr_set_hb_recv_filter_type(uint8_t type) { + BT_DBG("PvnrSetHbRecvFilterType"); + if (type > HEARTBEAT_FILTER_REJECTLIST) { BT_ERR("Invalid heartbeat filter type 0x%02x", type); return -EINVAL; @@ -158,6 +168,8 @@ int bt_mesh_pvnr_set_hb_recv_filter_type(uint8_t type) * clear the existing filter entries. */ if (hb_rx.type != type) { + BT_DBG("OldType %u NewType %u", hb_rx.type, type); + memset(&hb_rx, 0, offsetof(struct heartbeat_recv, cb)); hb_rx.type = type; } @@ -169,6 +181,8 @@ static int hb_filter_alloc(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterAlloc, Src 0x%04x Dst 0x%04x", src, dst); + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; @@ -180,7 +194,7 @@ static int hb_filter_alloc(uint16_t src, uint16_t dst) } } - BT_ERR("Heartbeat filter is full!"); + BT_ERR("HbFilterFull"); return -ENOMEM; } @@ -188,6 +202,8 @@ static int hb_filter_add(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterAdd, Src 0x%04x Dst 0x%04x", src, dst); + if (!(BLE_MESH_ADDR_IS_UNICAST(src) && (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)))) { BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); @@ -199,7 +215,7 @@ static int hb_filter_add(uint16_t src, uint16_t dst) struct heartbeat_filter *filter = &hb_rx.filter[i]; if (filter->src == src && filter->dst == dst) { - BT_WARN("Filter already exists, src 0x%04x dst 0x%04x", filter->src, filter->dst); + BT_DBG("FilterIndex %u", i); return 0; } } @@ -211,6 +227,8 @@ static int hb_filter_remove(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterRemove, Src 0x%04x Dst 0x%04x", src, dst); + if (!(BLE_MESH_ADDR_IS_UNICAST(src) && (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)))) { BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); @@ -221,6 +239,7 @@ static int hb_filter_remove(uint16_t src, uint16_t dst) struct heartbeat_filter *filter = &hb_rx.filter[i]; if (filter->src == src && filter->dst == dst) { + BT_DBG("FilterIndex %u", i); memset(filter, 0, sizeof(struct heartbeat_filter)); } } @@ -236,7 +255,7 @@ int bt_mesh_pvnr_set_hb_recv_filter_info(uint8_t op, uint16_t src, uint16_t dst) case HEARTBEAT_FILTER_REMOVE: return hb_filter_remove(src, dst); default: - BT_ERR("Invalid heartbeat filter opcode 0x%02x", op); + BT_ERR("Invalid HbFilterOpCode 0x%02x", op); return -EINVAL; } } @@ -248,6 +267,7 @@ static bool filter_with_rejectlist(uint16_t hb_src, uint16_t hb_dst) for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; if (hb_src == filter->src && hb_dst == filter->dst) { + BT_DBG("InRejectList, Src 0x%04x Dst 0x%04x", hb_src, hb_dst); return true; } } @@ -262,6 +282,7 @@ static bool filter_with_acceptlist(uint16_t hb_src, uint16_t hb_dst) for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; if (hb_src == filter->src && hb_dst == filter->dst) { + BT_DBG("InAcceptList, Src 0x%04x Dst 0x%04x", hb_src, hb_dst); return false; } } @@ -273,6 +294,8 @@ void bt_mesh_pvnr_heartbeat_recv(uint16_t hb_src, uint16_t hb_dst, uint8_t init_ttl, uint8_t rx_ttl, uint8_t hops, uint16_t feat, int8_t rssi) { + BT_DBG("PvnrHeartbeatRecv"); + if (hb_rx.cb == NULL) { BT_DBG("Receiving heartbeat is not enabled"); return; @@ -280,16 +303,17 @@ void bt_mesh_pvnr_heartbeat_recv(uint16_t hb_src, uint16_t hb_dst, if (hb_rx.type == HEARTBEAT_FILTER_REJECTLIST) { if (filter_with_rejectlist(hb_src, hb_dst)) { - BT_INFO("Filtered by rejectlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); return; } } else { if (filter_with_acceptlist(hb_src, hb_dst)) { - BT_INFO("Filtered by acceptlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); return; } } + BT_DBG("Src 0x%04x Dst 0x%04x InitTTL %u RxTTL %u Hops %u Feat 0x%04x Rssi %d", + hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi); + if (hb_rx.cb) { hb_rx.cb(hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi); } diff --git a/components/bt/esp_ble_mesh/core/include/mesh/access.h b/components/bt/esp_ble_mesh/core/include/mesh/access.h index 38be1a6caccc..6aa64080bd7f 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/access.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/access.h @@ -14,6 +14,7 @@ #include "mesh/config.h" #include "mesh/buf.h" #include "mesh/timer.h" +#include "sys/types.h" /** * @brief Bluetooth Mesh Access Layer @@ -151,8 +152,15 @@ struct bt_mesh_elem { #define BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -#define BLE_MESH_MODEL_ID_MBT_SRV 0x1400 -#define BLE_MESH_MODEL_ID_MBT_CLI 0x1401 +#define BLE_MESH_MODEL_ID_BLOB_SRV 0x1400 +#define BLE_MESH_MODEL_ID_BLOB_CLI 0x1401 +#define BLE_MESH_MODEL_ID_DFU_SRV 0x1402 +#define BLE_MESH_MODEL_ID_DFU_CLI 0x1403 +#define BLE_MESH_MODEL_ID_DFD_SRV 0x1404 +#define BLE_MESH_MODEL_ID_DFD_CLI 0x1405 + +#define BLE_MESH_MODEL_ID_MBT_SRV BLE_MESH_MODEL_ID_BLOB_SRV +#define BLE_MESH_MODEL_ID_MBT_CLI BLE_MESH_MODEL_ID_BLOB_CLI typedef struct { uint32_t adv_itvl; @@ -520,6 +528,8 @@ struct bt_mesh_model_pub { .update = _update, \ } +typedef ssize_t (*settings_read_cb)(void *cb_arg, void *data, size_t len); + /** Model callback functions. */ struct bt_mesh_model_cb { /** @brief Model init callback. @@ -613,7 +623,7 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode); * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, @@ -642,7 +652,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model); * * @return Pointer to the element that the given model belongs to. */ -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); /** @brief Find a SIG model. * diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h index de8b01c95f14..39c359d695c8 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -512,20 +512,20 @@ struct bt_mesh_adv_param { #define ADV_TASK_ADV_INST_EVT(inst_id) BIT(inst_id) enum bt_mesh_adv_inst_type { - BLE_MESH_ADV_INS, + BLE_MESH_ADV_INST, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - BLE_MESH_ADV_PROXY_INS, + BLE_MESH_ADV_PROXY_INST, #endif #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - BLE_MESH_RELAY_ADV_INS, + BLE_MESH_RELAY_ADV_INST, #endif #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - BLE_MESH_BLE_ADV_INS, + BLE_MESH_BLE_ADV_INST, #endif #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ - BLE_MESH_ADV_INS_TYPES_NUM, + BLE_MESH_ADV_INST_TYPES_NUM, }; #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV diff --git a/components/bt/esp_ble_mesh/core/local.c b/components/bt/esp_ble_mesh/core/local.c index 4451e0d7b263..fb933cc804a2 100644 --- a/components/bt/esp_ble_mesh/core/local.c +++ b/components/bt/esp_ble_mesh/core/local.c @@ -22,14 +22,17 @@ static struct bt_mesh_model *find_model(uint16_t elem_addr, uint16_t cid, uint16 { struct bt_mesh_elem *elem = NULL; + BT_DBG("FindModelLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x", elem_addr, cid, mod_id); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_ERR("Invalid unicast address 0x%04x", elem_addr); + BT_ERR("InvalidUnicastAddr 0x%04x", elem_addr); return NULL; } elem = bt_mesh_elem_find(elem_addr); if (elem == NULL) { - BT_ERR("No element found, addr 0x%04x", elem_addr); + BT_ERR("NoElemFound 0x%04x", elem_addr); return NULL; } @@ -46,19 +49,23 @@ int bt_mesh_model_subscribe_group_addr(uint16_t elem_addr, uint16_t cid, struct bt_mesh_model *model = NULL; int i; + BT_DBG("ModelSubGroupAddrLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x GroupAddr 0x%04x", + elem_addr, cid, mod_id, group_addr); + model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Subscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id); + BT_ERR("ModelNotFound, CID 0x%04x ID 0x%04x", cid, mod_id); return -ENODEV; } if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) { - BT_ERR("Subscribe, not a group address 0x%04x", group_addr); + BT_ERR("NotGroupAddr 0x%04x", group_addr); return -EINVAL; } if (bt_mesh_model_find_group(model, group_addr)) { - BT_INFO("Group address 0x%04x already exists", group_addr); + BT_INFO("GroupAddrExist 0x%04x", group_addr); return 0; } @@ -74,12 +81,11 @@ int bt_mesh_model_subscribe_group_addr(uint16_t elem_addr, uint16_t cid, bt_mesh_lpn_group_add(group_addr); } - BT_INFO("Subscribe group address 0x%04x", group_addr); return 0; } } - BT_ERR("Subscribe, model sub is full!"); + BT_ERR("ModelSubFull"); return -ENOMEM; } @@ -89,20 +95,24 @@ int bt_mesh_model_unsubscribe_group_addr(uint16_t elem_addr, uint16_t cid, struct bt_mesh_model *model = NULL; uint16_t *match = NULL; + BT_DBG("ModelUnsubGroupAddrLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x GroupAddr 0x%04x", + elem_addr, cid, mod_id, group_addr); + model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Unsubscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id); + BT_ERR("ModelNotFound, CID 0x%04x ID 0x%04x", cid, mod_id); return -ENODEV; } if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) { - BT_ERR("Unsubscribe, not a group address 0x%04x", group_addr); + BT_ERR("NotGroupAddr 0x%04x", group_addr); return -EINVAL; } match = bt_mesh_model_find_group(model, group_addr); if (match == NULL) { - BT_WARN("Group address 0x%04x not exists", group_addr); + BT_WARN("GroupAddrExist 0x%04x", group_addr); return -EEXIST; } @@ -116,7 +126,6 @@ int bt_mesh_model_unsubscribe_group_addr(uint16_t elem_addr, uint16_t cid, bt_mesh_lpn_group_del(&group_addr, 1); } - BT_INFO("Unsubscribe group address 0x%04x", group_addr); return 0; } @@ -126,20 +135,24 @@ int bt_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwardin { struct bt_mesh_subnet *sub = NULL; + BT_DBG("EnableDFLocal, NetIdx 0x%04x DF %u DFRelay %u", + net_idx, directed_forwarding, directed_forwarding_relay); + if (net_idx > 0xFFF) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("InvalidNetIdx 0x%04x", net_idx); return -EINVAL; } sub = bt_mesh_subnet_get(net_idx); if (!sub) { - BT_ERR("NetKey 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return -EINVAL; } if (directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_DISABLED && directed_forwarding_relay == BLE_MESH_DIRECTED_RELAY_ENABLED) { - BT_ERR("Invalid Config directed forwarding: %d, directed forwarding relay: %d", directed_forwarding, directed_forwarding_relay); + BT_ERR("InvalidDFConfig %u/%u", + directed_forwarding, directed_forwarding_relay); return -EINVAL; } @@ -155,14 +168,16 @@ const uint8_t *bt_mesh_node_get_local_net_key(uint16_t net_idx) { struct bt_mesh_subnet *sub = NULL; + BT_DBG("NodeGetNetKeyLocal, NetIdx 0x%04x", net_idx); + if (net_idx > 0xFFF) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("InvalidNetIdx 0x%04x", net_idx); return NULL; } sub = bt_mesh_subnet_get(net_idx); if (!sub) { - BT_ERR("NetKey 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return NULL; } @@ -173,14 +188,16 @@ const uint8_t *bt_mesh_node_get_local_app_key(uint16_t app_idx) { struct bt_mesh_app_key *key = NULL; + BT_DBG("NodeGetAppKeyLocal, AppIdx 0x%04x", app_idx); + if (app_idx > 0xFFF) { - BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); + BT_ERR("InvalidAppIdx 0x%04x", app_idx); return NULL; } key = bt_mesh_app_key_get(app_idx); if (!key) { - BT_ERR("AppKey 0x%04x not exists", app_idx); + BT_ERR("AppIdxNotExist 0x%04x", app_idx); return NULL; } @@ -193,19 +210,21 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) int err = 0; int i; + BT_DBG("NodeAddNetKeyLocal, NetIdx 0x%04x", net_idx); + if (net_idx > 0xFFF || net_key == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to add NetKey"); + BT_ERR("NotProvisioned"); return -EIO; } sub = bt_mesh_subnet_get(net_idx); if (sub) { - BT_WARN("NetKey 0x%04x already exists", net_idx); + BT_WARN("NetIdxExist 0x%04x", net_idx); return -EEXIST; } @@ -215,7 +234,7 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) memcmp(bt_mesh.sub[i].keys[0].net, net_key, 16) == 0) || (bt_mesh.sub[i].kr_flag == true && memcmp(bt_mesh.sub[i].keys[1].net, net_key, 16) == 0)) { - BT_WARN("Key value %s already exists", bt_hex(net_key, 16)); + BT_WARN("NetKeyValExist %s", bt_hex(net_key, 16)); return -EEXIST; } } @@ -229,13 +248,13 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) } if (sub == NULL) { - BT_ERR("NetKey is full!"); + BT_ERR("NetKeyFull"); return -ENOMEM; } err = bt_mesh_net_keys_create(&sub->keys[0], net_key); if (err) { - BT_ERR("Failed to create keys for NetKey 0x%04x", net_idx); + BT_ERR("NetKeyCreateFail 0x%04x", net_idx); return -EIO; } @@ -249,7 +268,6 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) } if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -264,24 +282,26 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, { struct bt_mesh_app_key *key = NULL; + BT_DBG("NodeAddAppKeyLocal, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + if (net_idx > 0xFFF || app_idx > 0xFFF || app_key == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to add AppKey"); + BT_ERR("NotProvisioned"); return -EIO; } if (bt_mesh_subnet_get(net_idx) == NULL) { - BT_ERR("Subnet 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return -EIO; } key = bt_mesh_app_key_get(app_idx); if (key) { - BT_WARN("AppKey 0x%04x already exists", app_idx); + BT_WARN("AppIdxExist 0x%04x", app_idx); return -EEXIST; } @@ -291,7 +311,7 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, memcmp(bt_mesh.app_keys[i].keys[0].val, app_key, 16) == 0) || (bt_mesh.app_keys[i].updated == true && memcmp(bt_mesh.app_keys[i].keys[1].val, app_key, 16) == 0)) { - BT_WARN("Key value %s already exists", bt_hex(app_key, 16)); + BT_WARN("AppKeyValExist %s", bt_hex(app_key, 16)); return -EEXIST; } } @@ -302,7 +322,7 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, struct bt_mesh_app_keys *keys = &key->keys[0]; if (bt_mesh_app_id(app_key, &keys->id)) { - BT_ERR("Failed to generate AID"); + BT_ERR("GenAIDFail"); return -EIO; } @@ -312,15 +332,12 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, memcpy(keys->val, app_key, 16); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); bt_mesh_store_app_key(key); } - BT_INFO("Add AppKey 0x%04x, NetKeyIndex 0x%04x", app_idx, net_idx); return 0; } - BT_ERR("AppKey is full!"); return -ENOMEM; } @@ -330,25 +347,29 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, struct bt_mesh_model *model = NULL; int i; + BT_DBG("NodeBindAppKeyLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x AppIdx 0x%04x", + elem_addr, cid, mod_id, app_idx); + if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to bind AppKey"); + BT_ERR("NotProvisioned"); return -EIO; } model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Bind, model(id 0x%04x, cid 0x%04x) not found", mod_id, cid); + BT_ERR("ModelNotFound, ID 0x%04x CID 0x%04x", mod_id, cid); return -ENODEV; } if (bt_mesh_app_key_get(app_idx) == NULL) { - BT_ERR("Bind, AppKey 0x%03x not exists", app_idx); + BT_ERR("AppIdxNotExist 0x%04x", app_idx); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == app_idx) { - BT_WARN("Already bound to AppKey 0x%04x", app_idx); + BT_WARN("AppIdxBound 0x%04x", app_idx); return -EALREADY; } } @@ -356,16 +377,16 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == BLE_MESH_KEY_UNUSED) { model->keys[i] = app_idx; + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_mod_bind(model); } - BT_INFO("Model(id 0x%04x, cid 0x%04x) bound to AppKey 0x%04x", mod_id, cid, app_idx); return 0; } } - BT_ERR("Model bound is full!"); + BT_ERR("ModelBindFull"); return -ENOMEM; } #endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/esp_ble_mesh/core/lpn.c b/components/bt/esp_ble_mesh/core/lpn.c index 80f5b4321afc..a38b0944e4de 100644 --- a/components/bt/esp_ble_mesh/core/lpn.c +++ b/components/bt/esp_ble_mesh/core/lpn.c @@ -81,30 +81,30 @@ static const char *state2str(int state) { switch (state) { case BLE_MESH_LPN_DISABLED: - return "disabled"; + return "Disabled"; case BLE_MESH_LPN_CLEAR: - return "clear"; + return "Clear"; case BLE_MESH_LPN_TIMER: - return "timer"; + return "Timer"; case BLE_MESH_LPN_ENABLED: - return "enabled"; + return "Enabled"; case BLE_MESH_LPN_REQ_WAIT: - return "req wait"; + return "ReqWait"; case BLE_MESH_LPN_WAIT_OFFER: - return "wait offer"; + return "WaitOffer"; case BLE_MESH_LPN_ESTABLISHED: - return "established"; + return "Established"; case BLE_MESH_LPN_RECV_DELAY: - return "recv delay"; + return "RecvDelay"; case BLE_MESH_LPN_WAIT_UPDATE: - return "wait update"; + return "WaitUpdate"; case BLE_MESH_LPN_OFFER_RECV: - return "offer recv"; + return "OfferRecv"; default: - return "(unknown)"; + return "(Unknown)"; } } -#endif +#endif /* !CONFIG_BLE_MESH_NO_LOG */ static inline void lpn_set_state(int state) { @@ -120,9 +120,9 @@ static inline void group_zero(bt_mesh_atomic_t *target) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { bt_mesh_atomic_set(&target[i], 0); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ bt_mesh_atomic_set(target, 0); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static inline void group_set(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) @@ -133,9 +133,9 @@ static inline void group_set(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { (void)bt_mesh_atomic_or(&target[i], bt_mesh_atomic_get(&source[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ (void)bt_mesh_atomic_or(target, bt_mesh_atomic_get(source)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) @@ -146,9 +146,9 @@ static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *sourc for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { (void)bt_mesh_atomic_and(&target[i], ~bt_mesh_atomic_get(&source[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ (void)bt_mesh_atomic_and(target, ~bt_mesh_atomic_get(source)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static void clear_friendship(bool force, bool disable); @@ -159,6 +159,8 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("FrndClearSent, Err %d", err); + /* We're switching away from Low Power behavior, so permanently * enable scanning. */ @@ -169,6 +171,8 @@ static void friend_clear_sent(int err, void *user_data) lpn->req_attempts++; + BT_DBG("ReqAttempts %u", lpn->req_attempts); + if (err) { BT_ERR("Sending Friend Clear failed (err %d)", err); lpn_set_state(BLE_MESH_LPN_ENABLED); @@ -206,6 +210,8 @@ static int send_friend_clear(void) .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter), }; + BT_DBG("SendFrndClear"); + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, sizeof(req), &clear_sent_cb, NULL); } @@ -215,10 +221,12 @@ static void clear_friendship(bool force, bool disable) struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("force %u disable %u", force, disable); + BT_DBG("ClearFriendship, Force %u Disable %u", force, disable); if (!force && lpn->established && !lpn->clear_success && lpn->req_attempts < CLEAR_ATTEMPTS) { + BT_DBG("SendFrndClear, ReqAttempts %u", lpn->req_attempts); + send_friend_clear(); lpn->disable = disable; return; @@ -253,7 +261,7 @@ static void clear_friendship(bool force, bool disable) bt_mesh_restore_directed_forwarding_state(bt_mesh.sub[0].net_idx, lpn->old_directed_forwarding); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; lpn->fsn = 0U; @@ -306,6 +314,8 @@ static void friend_req_sent(uint16_t duration, int err, void *user_data) return; } + BT_DBG("FrndReqSent, duration %u", duration); + lpn->adv_duration = duration; if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { @@ -349,6 +359,8 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) .lpn_counter = sys_cpu_to_be16(lpn->counter), }; + BT_DBG("SendFrndReq, NetIdx 0x%04x", ctx.net_idx); + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req, sizeof(req), &friend_req_sent_cb, NULL); } @@ -357,7 +369,7 @@ static void req_sent(uint16_t duration, int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("req 0x%02x duration %u err %d state %s", + BT_DBG("ReqSent, Req 0x%02x Duration %u Err %d State %s", lpn->sent_req, duration, err, state2str(lpn->state)); if (err) { @@ -372,6 +384,9 @@ static void req_sent(uint16_t duration, int err, void *user_data) if (lpn->established || IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { lpn_set_state(BLE_MESH_LPN_RECV_DELAY); + + BT_DBG("RecvDelay %u ScanLatency %u", LPN_RECV_DELAY, SCAN_LATENCY); + /* We start scanning a bit early to eliminate risk of missing * response data due to HCI and other latencies. */ @@ -379,6 +394,9 @@ static void req_sent(uint16_t duration, int err, void *user_data) LPN_RECV_DELAY - SCAN_LATENCY); } else { lpn_set_state(BLE_MESH_LPN_OFFER_RECV); + + BT_DBG("RecvDelay %u RecvWin %u", LPN_RECV_DELAY, lpn->recv_win); + /** * Friend Update is replied by Friend Node with TTL set to 0 and Network * Transmit set to 30ms which will cause the packet easy to be missed. @@ -416,7 +434,7 @@ static int send_friend_poll(void) uint8_t fsn = lpn->fsn; int err = 0; - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + BT_DBG("SendFrndPoll, Req 0x%02x ", lpn->sent_req); if (lpn->sent_req) { if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { @@ -438,6 +456,8 @@ static int send_friend_poll(void) void bt_mesh_lpn_disable(bool force) { + BT_DBG("LPNDisable, Force %u State 0x%02x", force, bt_mesh.lpn.state); + if (bt_mesh.lpn.state == BLE_MESH_LPN_DISABLED) { return; } @@ -449,6 +469,8 @@ int bt_mesh_lpn_set(bool enable, bool force) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNSet, Enable %u Force %u State 0x%02x", enable, force, lpn->state); + if (enable) { if (lpn->state != BLE_MESH_LPN_DISABLED) { return 0; @@ -479,7 +501,7 @@ int bt_mesh_lpn_set(bool enable, bool force) send_friend_req(lpn); } else { if (IS_ENABLED(CONFIG_BLE_MESH_LPN_AUTO) && - lpn->state == BLE_MESH_LPN_TIMER) { + lpn->state == BLE_MESH_LPN_TIMER) { k_delayed_work_cancel(&lpn->timer); lpn_set_state(BLE_MESH_LPN_DISABLED); } else { @@ -492,7 +514,7 @@ int bt_mesh_lpn_set(bool enable, bool force) static void friend_response_received(struct bt_mesh_lpn *lpn) { - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + BT_DBG("FrndRspRecv, Req 0x%02x Fsn %u", lpn->sent_req, lpn->fsn); if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) { lpn->fsn++; @@ -509,6 +531,8 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNMsgRecv, Req 0x%02x State 0x%02x", lpn->sent_req, lpn->state); + if (lpn->state == BLE_MESH_LPN_TIMER) { BT_DBG("Restarting establishment timer"); k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); @@ -522,8 +546,6 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) friend_response_received(lpn); - BT_DBG("Requesting more messages from Friend"); - send_friend_poll(); } @@ -537,6 +559,8 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, uint16_t frnd_counter = 0U; int err = 0; + BT_DBG("LPNFrndOffer"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Offer"); return -EINVAL; @@ -554,9 +578,9 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, frnd_counter = sys_be16_to_cpu(msg->frnd_counter); - BT_INFO("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u", - msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi, - frnd_counter); + BT_INFO("Frnd 0x%04x RecvWin %u QueueSize %u SubListSize %u FrndCounter %u Rssi %d", + rx->ctx.addr, msg->recv_win, msg->queue_size, + msg->sub_list_size, frnd_counter, msg->rssi); lpn->frnd = rx->ctx.addr; @@ -575,6 +599,8 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, err = send_friend_poll(); if (err) { + BT_ERR("SendFrndPollFailed, Err %d", err); + friend_cred_clear(cred); lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; lpn->recv_win = 0U; @@ -598,6 +624,8 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_lpn *lpn = &bt_mesh.lpn; uint16_t addr = 0U, counter = 0U; + BT_DBG("LPNFrndClearCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Clear Confirm"); return -EINVAL; @@ -611,7 +639,7 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, addr = sys_be16_to_cpu(msg->lpn_addr); counter = sys_be16_to_cpu(msg->lpn_counter); - BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter); + BT_DBG("LPN 0x%04x Counter 0x%04x", addr, counter); if (addr != bt_mesh_primary_addr() || counter != lpn->counter) { BT_WARN("Invalid parameters in Friend Clear Confirm"); @@ -630,8 +658,11 @@ static void lpn_group_add(uint16_t group) uint16_t *free_slot = NULL; int i; + BT_DBG("LPNGroupAdd, Addr 0x%04x", group); + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (lpn->groups[i] == group) { + BT_DBG("ClearLPNToRemove"); bt_mesh_atomic_clear_bit(lpn->to_remove, i); return; } @@ -655,10 +686,13 @@ static void lpn_group_del(uint16_t group) struct bt_mesh_lpn *lpn = &bt_mesh.lpn; int i; + BT_DBG("LPNGroupDel, Addr 0x%04x", group); + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (lpn->groups[i] == group) { if (bt_mesh_atomic_test_bit(lpn->added, i) || bt_mesh_atomic_test_bit(lpn->pending, i)) { + BT_DBG("Set LPNToRemove"); bt_mesh_atomic_set_bit(lpn->to_remove, i); lpn->groups_changed = 1U; } else { @@ -676,9 +710,9 @@ static inline int group_popcount(bt_mesh_atomic_t *target) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { count += popcount(bt_mesh_atomic_get(&target[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ return popcount(bt_mesh_atomic_get(target)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static bool sub_update(uint8_t op) @@ -703,7 +737,7 @@ static bool sub_update(uint8_t op) struct bt_mesh_ctl_friend_sub req = {0}; size_t i = 0U, g = 0U; - BT_DBG("op 0x%02x sent_req 0x%02x", op, lpn->sent_req); + BT_DBG("SubUpdate, OP 0x%02x Req 0x%02x ", op, lpn->sent_req); if (lpn->sent_req) { return false; @@ -725,7 +759,8 @@ static bool sub_update(uint8_t op) } if (added_count + g >= lpn->queue_size) { - BT_WARN("Friend Queue Size exceeded"); + BT_WARN("FrndQueueExceeded, Added %u G %u Size %u", + added_count, g, lpn->queue_size); break; } @@ -744,6 +779,8 @@ static bool sub_update(uint8_t op) req.xact = lpn->xact_next++; + BT_DBG("Xact %u G %u", req.xact, g); + if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, &req_sent_cb, NULL) < 0) { group_zero(lpn->pending); @@ -752,14 +789,19 @@ static bool sub_update(uint8_t op) lpn->xact_pending = req.xact; lpn->sent_req = op; + return true; } static void update_timeout(struct bt_mesh_lpn *lpn) { + BT_DBG("UpdateTimeout"); + if (lpn->established) { BT_WARN("No response from Friend during ReceiveWindow"); + bt_mesh_scan_disable(); + lpn_set_state(BLE_MESH_LPN_ESTABLISHED); k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); } else { @@ -767,6 +809,8 @@ static void update_timeout(struct bt_mesh_lpn *lpn) bt_mesh_scan_disable(); } + BT_DBG("ReqAttempts %u", lpn->req_attempts); + if (lpn->req_attempts < FIRST_POLL_ATTEMPTS) { BT_WARN("Retrying first Friend Poll"); lpn->sent_req = 0U; @@ -784,7 +828,7 @@ static void lpn_timeout(struct k_work *work) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("state: %s", state2str(lpn->state)); + BT_DBG("LPNTimeout, State: %s", state2str(lpn->state)); switch (lpn->state) { case BLE_MESH_LPN_DISABLED: @@ -830,6 +874,8 @@ static void lpn_timeout(struct k_work *work) clear_friendship(true, false); break; case BLE_MESH_LPN_ESTABLISHED: + BT_DBG("ReqAttempts %u vs. %u", lpn->req_attempts, REQ_ATTEMPTS(lpn)); + if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { uint8_t req = lpn->sent_req; @@ -867,11 +913,13 @@ static void lpn_timeout(struct k_work *work) void bt_mesh_lpn_group_add(uint16_t group) { - BT_DBG("group 0x%04x", group); + BT_DBG("LPNGroupAdd, Addr 0x%04x", group); lpn_group_add(group); if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + BT_INFO("Established %u Req 0x%02x", + bt_mesh_lpn_established(), bt_mesh.lpn.sent_req); return; } @@ -882,6 +930,8 @@ void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) { int i; + BT_DBG("LPNGroupDel, GroupCount %u", group_count); + for (i = 0; i < group_count; i++) { if (groups[i] != BLE_MESH_ADDR_UNASSIGNED) { BT_DBG("group 0x%04x", groups[i]); @@ -890,6 +940,8 @@ void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) } if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + BT_INFO("Established %u Req 0x%02x", + bt_mesh_lpn_established(), bt_mesh.lpn.sent_req); return; } @@ -900,6 +952,7 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) { /* If we're waiting for segment acks keep polling at high freq */ if (bt_mesh_tx_in_progress()) { + BT_DBG("PollTimeout, Max %u", POLL_TIMEOUT_MAX(lpn)); return MIN(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); } @@ -909,7 +962,7 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) POLL_TIMEOUT_MAX(lpn)); } - BT_DBG("Poll Timeout is %ums", lpn->poll_timeout); + BT_DBG("PollTimeout %u", lpn->poll_timeout); return lpn->poll_timeout; } @@ -920,12 +973,15 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->data; struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNFrndSubCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Subscription Confirm"); return -EINVAL; } - BT_DBG("xact 0x%02x", msg->xact); + BT_DBG("Xact %u Req 0x%02x GroupsChanged %u PendingPoll %u", + msg->xact, lpn->sent_req, lpn->groups_changed, lpn->pending_poll); if (!lpn->sent_req) { BT_WARN("No pending subscription list message"); @@ -987,11 +1043,16 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, struct bt_mesh_subnet *sub = rx->sub; uint32_t iv_index = 0U; + BT_DBG("LPNFrndUpdate"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Update"); return -EINVAL; } + BT_DBG("Req 0x%02x KrPhase %u Established %u", + lpn->sent_req, sub->kr_phase, lpn->established); + if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { BT_WARN("Unexpected friend update"); return 0; @@ -1034,8 +1095,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } /* Set initial poll timeout */ - lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), - POLL_TIMEOUT_INIT); + lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), POLL_TIMEOUT_INIT); /* If the Low Power node supports directed forwarding functionality when * the friendship is established in a subnet, the Low Power node shall @@ -1046,18 +1106,16 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, */ #if CONFIG_BLE_MESH_DF_SRV lpn->old_directed_forwarding = bt_mesh_get_and_disable_directed_forwarding_state(sub); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } friend_response_received(lpn); iv_index = sys_be32_to_cpu(msg->iv_index); - BT_INFO("flags 0x%02x iv_index 0x%08x md %u", msg->flags, iv_index, - msg->md); + BT_INFO("Flags 0x%02x IVIndex 0x%08lx MD %u", msg->flags, iv_index, msg->md); - if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), - rx->new_key)) { + if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), rx->new_key)) { bt_mesh_net_secure_beacon_update(sub); } @@ -1086,12 +1144,12 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, int bt_mesh_lpn_poll(void) { + BT_DBG("LPNPoll, Established %u", bt_mesh.lpn.established); + if (!bt_mesh.lpn.established) { return -EAGAIN; } - BT_DBG("Requesting more messages"); - return send_friend_poll(); } @@ -1104,6 +1162,8 @@ int bt_mesh_lpn_init(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNInit"); + k_delayed_work_init(&lpn->timer, lpn_timeout); if (lpn->state == BLE_MESH_LPN_ENABLED) { @@ -1130,6 +1190,8 @@ int bt_mesh_lpn_deinit(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNDeinit"); + bt_mesh_lpn_disable(true); k_delayed_work_free(&lpn->timer); diff --git a/components/bt/esp_ble_mesh/core/main.c b/components/bt/esp_ble_mesh/core/main.c index 957234e312e3..3b6dcb140224 100644 --- a/components/bt/esp_ble_mesh/core/main.c +++ b/components/bt/esp_ble_mesh/core/main.c @@ -32,12 +32,14 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ static bool mesh_init = false; bool bt_mesh_is_initialized(void) { + BT_DBG("IsInitialized %u", mesh_init); + return mesh_init; } @@ -48,9 +50,10 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bool pb_gatt_enabled = false; int err = 0; - BT_INFO("Primary Element: 0x%04x", addr); - BT_INFO("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", - net_idx, flags, iv_index); + BT_INFO("NodeProvisioned"); + BT_INFO("PrimaryAddr 0x%04x", addr); + BT_INFO("NetIdx 0x%04x Flags 0x%02x IVIndex 0x%08lx", + net_idx, flags, iv_index); BT_INFO("DevKey %s", bt_hex(dev_key, 16)); BT_INFO("NetKey %s", bt_hex(net_key, 16)); @@ -69,9 +72,12 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, pb_gatt_enabled = false; } + BT_DBG("PbGattEnabled %u", pb_gatt_enabled); + err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); if (err) { BT_ERR("Create network for node failed"); + bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_VALID); if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && pb_gatt_enabled) { @@ -89,11 +95,11 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && IS_ENABLED(CONFIG_BLE_MESH_LPN_SUB_ALL_NODES_ADDR)) { + BT_DBG("LPNAllNodesAdded"); bt_mesh_lpn_group_add(BLE_MESH_ADDR_ALL_NODES); } if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing network information persistently"); bt_mesh_store_net(); bt_mesh_store_subnet(&bt_mesh.sub[0]); bt_mesh_store_iv(false); @@ -106,6 +112,8 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, void bt_mesh_node_reset(void) { + BT_DBG("NodeLocalReset"); + if (!bt_mesh_is_provisioned()) { BT_WARN("%s, Not provisioned", __func__); return; @@ -154,7 +162,7 @@ void bt_mesh_node_reset(void) #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_beacon_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_comp_unprovision(); @@ -165,7 +173,7 @@ void bt_mesh_node_reset(void) bt_mesh_clear_role(); #if CONFIG_BLE_MESH_DF_SRV bt_mesh_clear_all_directed_forwarding_table_data(); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); @@ -177,34 +185,52 @@ void bt_mesh_node_reset(void) bool bt_mesh_is_node(void) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_NODE); + bool is_node = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_NODE); + + BT_DBG("IsNode %u", is_node); + + return is_node; } bool bt_mesh_is_provisioned(void) { + bool is_provisioned = false; + if (bt_mesh_is_node()) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID); - } else { - return false; + is_provisioned = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID); } + + BT_DBG("IsProvisioned %u", is_provisioned); + + return is_provisioned; } bool bt_mesh_is_provisioner(void) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_PROVISIONER); + bool is_pvnr = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_PROVISIONER); + + BT_DBG("IsPvnr %u", is_pvnr); + + return is_pvnr; } bool bt_mesh_is_provisioner_en(void) { + bool is_pvnr_en = false; + if (bt_mesh_is_provisioner()) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID_PROV); + is_pvnr_en = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID_PROV); } - return false; + BT_DBG("IsPvnrEn %u", is_pvnr_en); + + return is_pvnr_en; } static bool prov_bearers_valid(bt_mesh_prov_bearer_t bearers) { + BT_DBG("ProvBearersValid, Bearers 0x%02x", bearers); + if ((!(bearers & (BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT))) || (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && @@ -215,6 +241,7 @@ static bool prov_bearers_valid(bt_mesh_prov_bearer_t bearers) BT_ERR("Invalid bearers 0x%02x", bearers); return false; } + return true; } @@ -222,6 +249,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) { int err = 0; + BT_DBG("ProvEnable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioned()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -247,6 +276,7 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) if (role == BLE_MESH_SETTINGS_ROLE_NONE) { bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_NODE); } + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY) || role == BLE_MESH_SETTINGS_ROLE_NONE) { if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { @@ -277,6 +307,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) { + BT_DBG("ProvDisable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioned()) { BT_WARN("%s, Already provisioned", __func__); return -EALREADY; @@ -309,6 +341,8 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ModelSuspend, Vnd %u Primary %u", vnd, primary); + if (mod->pub && mod->pub->update) { mod->pub->count = 0U; k_delayed_work_cancel(&mod->pub->timer); @@ -319,6 +353,8 @@ int bt_mesh_suspend(void) { int err = 0; + BT_DBG("Suspend"); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { return -EINVAL; } @@ -344,7 +380,7 @@ int bt_mesh_suspend(void) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_model_foreach(model_suspend, NULL); @@ -354,6 +390,8 @@ int bt_mesh_suspend(void) static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ModelResume, Vnd %u Primary %u", vnd, primary); + if (mod->pub && mod->pub->update) { int32_t period_ms = bt_mesh_model_pub_period_get(mod); @@ -367,6 +405,8 @@ int bt_mesh_resume(void) { int err = 0; + BT_DBG("Resume"); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { return -EINVAL; } @@ -390,7 +430,7 @@ int bt_mesh_resume(void) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_enable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_model_foreach(model_resume, NULL); @@ -402,6 +442,8 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, { int err = 0; + BT_DBG("Init"); + if (mesh_init == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -414,7 +456,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, BT_ERR("Bluetooth Mesh v1.1 init failed"); return err; } -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ bt_mesh_mutex_init(); @@ -452,7 +494,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, if (err) { return err; } -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { err = bt_mesh_prov_set(prov); @@ -507,6 +549,8 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) { int err = 0; + BT_DBG("Deinit"); + if (param == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -522,7 +566,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_beacon_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && @@ -583,7 +627,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) #if CONFIG_BLE_MESH_PROXY_SOLIC bt_mesh_proxy_solic_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ if ((IS_ENABLED(CONFIG_BLE_MESH_NODE) && IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || @@ -638,6 +682,8 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) { int err = 0; + BT_DBG("PvnrEnable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioner_en()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -703,7 +749,7 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); } -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && (bearers & BLE_MESH_PROV_GATT)) { @@ -722,7 +768,7 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_enable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ err = bt_mesh_scan_enable(); if (err) { @@ -736,6 +782,8 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) { bt_mesh_prov_bearer_t enable = 0U; + BT_DBG("PvnrDisable, Bearers 0x%02x", bearers); + if (!bt_mesh_is_provisioner_en()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -762,7 +810,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ } if (!(enable & (~bearers))) { @@ -776,7 +824,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); } -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ /* Clear corresponding flags */ bt_mesh_atomic_and(bt_mesh.flags, ~(BIT(BLE_MESH_PROVISIONER) | BIT(BLE_MESH_VALID_PROV))); @@ -794,7 +842,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index c81b15d37df1..fde5b5cdda76 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -33,7 +33,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* Minimum valid Mesh Network PDU length. The Network headers * themselves take up 9 bytes. After that there is a minimum of 1 byte @@ -41,23 +41,27 @@ * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. */ -#define BLE_MESH_NET_MIN_PDU_LEN (BLE_MESH_NET_HDR_LEN + 1 + 8) +#define BLE_MESH_NET_MIN_PDU_LEN (BLE_MESH_NET_HDR_LEN + 1 + 8) /* Seq limit after IV Update is triggered */ -#define IV_UPDATE_SEQ_LIMIT 8000000 +#define IV_UPDATE_SEQ_LIMIT 8000000 /* Determine how many friendship credentials we need */ #if CONFIG_BLE_MESH_FRIEND -#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT #elif CONFIG_BLE_MESH_LOW_POWER -#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT #else -#define FRIEND_CRED_COUNT 0 +#define FRIEND_CRED_COUNT 0 #endif +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +#define MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + #if FRIEND_CRED_COUNT > 0 static struct friend_cred friend_cred[FRIEND_CRED_COUNT]; -#endif +#endif /* FRIEND_CRED_COUNT > 0 */ static struct { uint32_t src:15, /* MSB of source address is always 0 */ @@ -83,10 +87,6 @@ struct bt_mesh_net bt_mesh = { static uint32_t dup_cache[4]; static int dup_cache_next; -#if CONFIG_BLE_MESH_RELAY_ADV_BUF -#define BLE_MESH_MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) -#endif - static bool check_dup(struct net_buf_simple *data) { const uint8_t *tail = net_buf_simple_tail(data); @@ -95,12 +95,17 @@ static bool check_dup(struct net_buf_simple *data) val = sys_get_be32(tail - 4) ^ sys_get_be32(tail - 8); + BT_DBG("CheckDup, Val 0x%08lx", val); + for (i = 0; i < ARRAY_SIZE(dup_cache); i++) { if (dup_cache[i] == val) { + BT_DBG("DupCacheFound"); return true; } } + BT_DBG("DupCacheAdd, CacheNext %ld %d", val, dup_cache_next); + dup_cache[dup_cache_next++] = val; dup_cache_next %= ARRAY_SIZE(dup_cache); @@ -112,9 +117,13 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx, { int i; + BT_DBG("MsgCacheMatch"); + for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { if (msg_cache[i].src == BLE_MESH_NET_HDR_SRC(pdu->data) && msg_cache[i].seq == (BLE_MESH_NET_HDR_SEQ(pdu->data) & BIT_MASK(17))) { + BT_DBG("CacheFound, Src 0x%04x Seq 0x%06x", + msg_cache[i].src, msg_cache[i].seq); return true; } } @@ -124,6 +133,9 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx, static void msg_cache_add(struct bt_mesh_net_rx *rx) { + BT_DBG("MsgCacheAdd, Src 0x%04x Seq 0x%06x CacheNext %u", + rx->ctx.addr, rx->seq, msg_cache_next); + rx->msg_cache_idx = msg_cache_next++; msg_cache[rx->msg_cache_idx].src = rx->ctx.addr; msg_cache[rx->msg_cache_idx].seq = rx->seq; @@ -135,6 +147,8 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num) { int i; + BT_DBG("MsgCacheClear, Addr 0x%04x ElemNum %u", unicast_addr, elem_num); + for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { if (msg_cache[i].src >= unicast_addr && msg_cache[i].src < unicast_addr + elem_num) { @@ -146,6 +160,8 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num) struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) { + BT_DBG("SubnetGet, NetIdx 0x%04x", net_idx); + if (bt_mesh_is_provisioned()) { #if CONFIG_BLE_MESH_NODE if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { @@ -161,7 +177,7 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) } else { return bt_mesh_fast_prov_subnet_get(net_idx); } -#endif +#endif /* CONFIG_BLE_MESH_NODE */ } else if (bt_mesh_is_provisioner_en()) { #if CONFIG_BLE_MESH_PROVISIONER if (net_idx == BLE_MESH_KEY_ANY) { @@ -174,7 +190,7 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) return bt_mesh.p_sub[i]; } } -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } return NULL; @@ -187,6 +203,8 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, uint8_t nid = 0U; int err = 0; + BT_DBG("NetKeysCreate"); + err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->enc, keys->privacy); if (err) { BT_ERR("Unable to generate NID, EncKey & PrivacyKey"); @@ -258,6 +276,9 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key uint8_t p[9] = {0}; int err = 0; + BT_DBG("FrndCredSet, NetIdx 0x%04x Addr 0x%04x Idx %u", + cred->net_idx, cred->addr, idx); + #if CONFIG_BLE_MESH_LOW_POWER if (cred->addr == bt_mesh.lpn.frnd) { lpn_addr = bt_mesh_primary_addr(); @@ -266,14 +287,13 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key lpn_addr = cred->addr; frnd_addr = bt_mesh_primary_addr(); } -#else +#else /* CONFIG_BLE_MESH_LOW_POWER */ lpn_addr = cred->addr; frnd_addr = bt_mesh_primary_addr(); -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ - BT_DBG("LPNAddress 0x%04x FriendAddress 0x%04x", lpn_addr, frnd_addr); - BT_DBG("LPNCounter 0x%04x FriendCounter 0x%04x", cred->lpn_counter, - cred->frnd_counter); + BT_DBG("LPN 0x%04x Frnd 0x%04x LPNCounter %u FrndCounter %u", + lpn_addr, frnd_addr, cred->lpn_counter, cred->frnd_counter); p[0] = 0x01; sys_put_be16(lpn_addr, p + 1); @@ -288,9 +308,9 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key return err; } - BT_DBG("Friend NID 0x%02x EncKey %s", cred->cred[idx].nid, - bt_hex(cred->cred[idx].enc, 16)); - BT_DBG("Friend PrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); + BT_DBG("FrndNID 0x%02x EncKey %s", + cred->cred[idx].nid, bt_hex(cred->cred[idx].enc, 16)); + BT_DBG("FrndPrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); return 0; } @@ -299,11 +319,14 @@ void friend_cred_refresh(uint16_t net_idx) { int i; + BT_DBG("FrndCredRefresh, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; if (cred->addr != BLE_MESH_ADDR_UNASSIGNED && cred->net_idx == net_idx) { + BT_DBG("Refreshed, Addr 0x%04x", cred->addr); memcpy(&cred->cred[0], &cred->cred[1], sizeof(cred->cred[0])); } @@ -314,7 +337,7 @@ int friend_cred_update(struct bt_mesh_subnet *sub) { int err = 0, i; - BT_DBG("net_idx 0x%04x", sub->net_idx); + BT_DBG("FrndCredUpdate, NetIdx 0x%04x", sub->net_idx); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -324,6 +347,8 @@ int friend_cred_update(struct bt_mesh_subnet *sub) continue; } + BT_DBG("UpdateFound, Addr 0x%04x", cred->addr); + err = friend_cred_set(cred, 1, sub->keys[1].net); if (err) { return err; @@ -339,7 +364,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr struct friend_cred *cred = NULL; int i, err = 0; - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + BT_DBG("FrndCredCreate, NetIdx 0x%04x KrFlag %u Addr 0x%04x", + sub->net_idx, sub->kr_flag, addr); for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) { if ((friend_cred[i].addr == BLE_MESH_ADDR_UNASSIGNED) || @@ -379,6 +405,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr void friend_cred_clear(struct friend_cred *cred) { + BT_DBG("FrndCredClear, NetIdx 0x%04x Addr 0x%04x", cred->net_idx, cred->addr); + cred->net_idx = BLE_MESH_KEY_UNUSED; cred->addr = BLE_MESH_ADDR_UNASSIGNED; cred->lpn_counter = 0U; @@ -390,9 +418,13 @@ int friend_cred_del(uint16_t net_idx, uint16_t addr) { int i; + BT_DBG("FrndCredDel, NetIdx 0x%04x Addr 0x%04x", net_idx, addr); + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; + BT_DBG("%u: NetIdx 0x%04x Addr 0x%04x", i, cred->net_idx, cred->addr); + if (cred->addr == addr && cred->net_idx == net_idx) { friend_cred_clear(cred); return 0; @@ -407,7 +439,8 @@ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, { int i; - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + BT_DBG("FrndCredGet, NetIdx 0x%04x KrFlag %u Addr 0x%04x", + sub->net_idx, sub->kr_flag, addr); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -437,13 +470,15 @@ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, return -ENOENT; } -#else +#else /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, const uint8_t **enc, const uint8_t **priv) { + BT_DBG("FrndCredGetNoEnt"); + return -ENOENT; } -#endif /* FRIEND || LOW_POWER */ +#endif /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) { @@ -457,36 +492,40 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) flags |= BLE_MESH_NET_FLAG_IVU; } + BT_DBG("NetFlags 0x%02x", flags); + return flags; } int bt_mesh_net_secure_beacon_update(struct bt_mesh_subnet *sub) { - uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; + uint8_t flags = 0; + + BT_DBG("SecureBeaconUpdate, NetIdx 0x%04x KrFlag %u IVIndex %lu", + sub->net_idx, sub->kr_flag, bt_mesh.iv_index); if (sub->kr_flag) { - BT_DBG("NetIndex %u Using new key", sub->net_idx); keys = &sub->keys[1]; } else { - BT_DBG("NetIndex %u Using current key", sub->net_idx); keys = &sub->keys[0]; } - BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); + flags = bt_mesh_net_flags(sub); return bt_mesh_secure_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index, sub->auth); } -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t net_idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index) { struct bt_mesh_subnet *sub = NULL; int err = 0; - BT_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); - + BT_DBG("NetCreate"); + BT_DBG("NetIdx 0x%04x Flags 0x%02x IVIndex %lu Hours %u", + net_idx, flags, iv_index, BLE_MESH_IVU_HOURS); BT_DBG("NetKey %s", bt_hex(key, 16)); (void)memset(msg_cache, 0, sizeof(msg_cache)); @@ -509,7 +548,7 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], } } - sub->net_idx = idx; + sub->net_idx = net_idx; if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; @@ -517,7 +556,7 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; #if CONFIG_BLE_MESH_PRB_SRV sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED; -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } bt_mesh.iv_index = iv_index; @@ -535,27 +574,29 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], #if CONFIG_BLE_MESH_DF_SRV return bt_mesh_directed_forwarding_sub_init(sub); -#endif - +#else /* CONFIG_BLE_MESH_DF_SRV */ return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ } void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) { int i; - BT_DBG("idx 0x%04x", sub->net_idx); + BT_DBG("RevokeKeys, NetIdx 0x%04x", sub->net_idx); memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Store updated NetKey persistently"); bt_mesh_store_subnet(sub); } for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + BT_DBG("Revoke, NetIdx 0x%04x AppIdx 0x%04x KeyUpdated %u", + key->net_idx, key->app_idx, key->updated); + if (key->net_idx != sub->net_idx || !key->updated) { continue; } @@ -564,7 +605,6 @@ void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) key->updated = false; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Store updated AppKey persistently"); bt_mesh_store_app_key(key); } } @@ -572,6 +612,9 @@ void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) { + BT_DBG("KrUpdate, NewKr %u NewKey %u KrFlag %u KrPhase %u", + new_kr, new_key, sub->kr_flag, sub->kr_phase); + if (new_kr != sub->kr_flag && sub->kr_phase == BLE_MESH_KR_NORMAL) { BT_WARN("KR change in normal operation. Are we blacklisted?"); return false; @@ -582,10 +625,10 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) if (sub->kr_flag) { if (sub->kr_phase == BLE_MESH_KR_PHASE_1) { BT_INFO("Phase 1 -> Phase 2"); + sub->kr_phase = BLE_MESH_KR_PHASE_2; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing kr phase persistently"); bt_mesh_store_subnet(sub); } @@ -606,14 +649,14 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) * Intentional fall-through. */ case BLE_MESH_KR_PHASE_2: - BT_INFO("KR Phase 0x%02x -> Normal", sub->kr_phase); + BT_INFO("KrPhase 0x%02x -> Normal", sub->kr_phase); #if CONFIG_BLE_MESH_PRB_SRV /* In this case, consider that kr_flag has changed, so * need to modify the content of the random field. */ bt_mesh_private_beacon_update_random(sub); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ sub->kr_phase = BLE_MESH_KR_NORMAL; bt_mesh_net_revoke_keys(sub); @@ -633,15 +676,21 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) #if CONFIG_BLE_MESH_IV_UPDATE_TEST void bt_mesh_iv_update_test(bool enable) { + BT_DBG("IVUpdateTest, Enable %u", enable); + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_TEST, enable); + /* Reset the duration variable - needed for some PTS tests */ bt_mesh.ivu_duration = 0U; } bool bt_mesh_iv_update(void) { + BT_DBG("IVUpdate, IVIndex %lu InProgress %u", bt_mesh.iv_index, + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)); + if (!bt_mesh_is_provisioned()) { - BT_ERR("Not yet provisioned"); + BT_ERR("NotProvisioned"); return false; } @@ -660,6 +709,8 @@ bool bt_mesh_iv_update(void) /* Used for sending immediate beacons to Friend queues and GATT clients */ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) { + BT_DBG("NetSecUpdate, NetIdx 0x%04x", sub ? sub->net_idx : BLE_MESH_KEY_ANY); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_sec_update(sub ? sub->net_idx : BLE_MESH_KEY_ANY); } @@ -667,8 +718,8 @@ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED #if CONFIG_BLE_MESH_PRB_SRV - || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif + || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED +#endif /* CONFIG_BLE_MESH_PRB_SRV */ )) { bt_mesh_proxy_server_beacon_send(sub); } @@ -678,6 +729,11 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) { int i; + BT_DBG("NetIVUpdate"); + BT_DBG("IVIndex %lu/%lu IVU %u InProgress %u", + iv_index, bt_mesh.iv_index, iv_update, + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)); + /* If a node in Normal Operation receives a Secure Network beacon or * a Mesh Private beacon with an IV index less than the last known * IV Index or greater than the last known IV Index + 42, the Secure @@ -685,7 +741,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) */ if (iv_index < bt_mesh.iv_index || iv_index > bt_mesh.iv_index + 42) { - BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", + BT_ERR("IVIndex out of sync: 0x%08x != 0x%08x", iv_index, bt_mesh.iv_index); return false; } @@ -721,7 +777,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) if ((iv_index > bt_mesh.iv_index + 1) #if CONFIG_BLE_MESH_IVU_RECOVERY_IVI || (iv_index == bt_mesh.iv_index + 1 && !iv_update) -#endif +#endif /* CONFIG_BLE_MESH_IVU_RECOVERY_IVI */ ) { BT_WARN("Performing IV Index Recovery"); (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); @@ -742,7 +798,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) BT_WARN("Ignoring new index in normal mode"); return false; } -#endif +#endif /* !CONFIG_BLE_MESH_IVU_RECOVERY_IVI */ if (!iv_update) { /* Nothing to do */ @@ -802,9 +858,11 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) bool bt_mesh_primary_subnet_exist(void) { if (bt_mesh_subnet_get(BLE_MESH_KEY_PRIMARY)) { + BT_DBG("PrimarySubnetExist"); return true; } + BT_DBG("PrimarySubnetNotExist"); return false; } @@ -812,6 +870,8 @@ uint32_t bt_mesh_next_seq(void) { uint32_t seq = bt_mesh.seq++; + BT_DBG("NextSeq %lu", seq); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_seq(); } @@ -839,8 +899,9 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, /* The variable is not used when proxy server or proxy client is disabled. */ ARG_UNUSED(dst); - BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key, - buf->len); + BT_DBG("NetResend"); + BT_DBG("NetIdx 0x%04x NewKey %u Len %u Tag 0x%02x", + sub->net_idx, new_key, buf->len, tx_tag); /* Previously when resending the segments, only managed flooding * security credentials will be used. @@ -887,13 +948,11 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); if (err) { - BT_ERR("De-obfuscate failed (err %d)", err); return err; } err = bt_mesh_net_decrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { - BT_ERR("Decrypt failed (err %d)", err); return err; } @@ -906,20 +965,18 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, err = bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { - BT_ERR("Encrypt failed (err %d)", err); return err; } err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); if (err) { - BT_ERR("Obfuscate failed (err %d)", err); return err; } - /** - * TODO: Find a way to determine how the message was sent previously + /* TODO: + * Find a way to determine how the message was sent previously * during a retransmission, to avoid ineffective advertising. - */ + */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (bt_mesh_proxy_server_relay(&buf->b, dst) && BLE_MESH_ADDR_IS_UNICAST(dst) && @@ -927,13 +984,14 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, send_cb_finalize(cb, cb_data); return 0; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT bt_mesh_proxy_client_relay(&buf->b, dst); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ bt_mesh_adv_send(buf, BLE_MESH_ADV(buf)->xmit, cb, cb_data); + return 0; } @@ -941,8 +999,10 @@ static void bt_mesh_net_local(void) { struct net_buf *buf = NULL; + BT_DBG("NetLocal"); + while ((buf = net_buf_slist_get(&bt_mesh.local_queue))) { - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_net_recv(&buf->b, 0, BLE_MESH_NET_IF_LOCAL); net_buf_unref(buf); } @@ -956,6 +1016,10 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, uint8_t nid = 0U; int err = 0; + BT_DBG("NetEncode"); + BT_DBG("Src 0x%04x Dst 0x%04x Cred 0x%02x CTL %u Proxy %u", + tx->src, tx->ctx->addr, tx->ctx->send_cred, ctl, proxy); + if (ctl && net_buf_simple_tailroom(buf) < BLE_MESH_MIC_LONG) { BT_ERR("Insufficient MIC space for CTL PDU"); return -EINVAL; @@ -966,9 +1030,6 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, return -EINVAL; } - BT_DBG("src 0x%04x dst 0x%04x ctl %u seq 0x%06x", - tx->src, tx->ctx->addr, ctl, bt_mesh.seq); - net_buf_simple_push_be16(buf, tx->ctx->addr); net_buf_simple_push_be16(buf, tx->src); @@ -980,8 +1041,6 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, net_buf_simple_push_u8(buf, tx->ctx->send_ttl); } - BT_INFO("Use security credentials 0x%02x, proxy %d", tx->ctx->send_cred, proxy); - if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && tx->ctx->send_cred == BLE_MESH_FRIENDSHIP_CRED) { err = friend_cred_get(tx->sub, BLE_MESH_ADDR_UNASSIGNED, @@ -1042,16 +1101,13 @@ static void bt_mesh_net_adv_xmit_update(struct bt_mesh_net_tx *tx) */ if (bt_mesh_tag_friendship(tx->ctx->send_tag)) { tx->xmit = BLE_MESH_TRANSMIT(0, BLE_MESH_TRANSMIT_INT(bt_mesh_net_transmit_get())); - return; - } - - if (bt_mesh_tag_relay(tx->ctx->send_tag)) { + } else if (bt_mesh_tag_relay(tx->ctx->send_tag)) { tx->xmit = bt_mesh_relay_retransmit_get(); } else { tx->xmit = bt_mesh_net_transmit_get(); } - return; + BT_INFO("NetAdvXmitUpdate, Tag 0x%02x Xmit 0x%02x", tx->ctx->send_tag, tx->xmit); } #endif /* !CONFIG_BLE_MESH_V11_SUPPORT */ @@ -1062,11 +1118,11 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, uint8_t bearer = BLE_MESH_ALL_BEARERS; int err = 0; - BT_DBG("src 0x%04x dst 0x%04x len %u headroom %u tailroom %u", - tx->src, tx->ctx->addr, buf->len, net_buf_headroom(buf), - net_buf_tailroom(buf)); - BT_DBG("Payload len %u: %s", buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("Seq 0x%06x", bt_mesh.seq); + BT_DBG("NetSend"); + BT_DBG("Src 0x%04x Dst 0x%04x TTL %u Cred %u Tag 0x%02x Seq 0x%06x Room %u/%u", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, tx->ctx->send_cred, + tx->ctx->send_tag, bt_mesh.seq, net_buf_headroom(buf), net_buf_tailroom(buf)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { tx->ctx->send_ttl = bt_mesh_default_ttl_get(); @@ -1100,6 +1156,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, #if CONFIG_BLE_MESH_DF_SRV bt_mesh_update_net_send_cred(tx, &bearer); + + BT_DBG("TxBearer 0x%02x", bearer); #endif /* CONFIG_BLE_MESH_DF_SRV */ err = bt_mesh_net_encode(tx, &buf->b, false); @@ -1140,9 +1198,10 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, * a advertising method. */ if (bt_mesh_proxy_server_find_client_by_addr(tx->ctx->addr)) { + BT_DBG("ProxyClientFound"); + send_cb_finalize(send_cb, cb_data); send_cb = NULL; - goto done; } @@ -1154,6 +1213,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT /* This message will not be transmitted by proxy client */ if (!bt_mesh_proxy_client_get_conn_count()) { + BT_DBG("ProxyClientNoConn"); goto done; } #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ @@ -1167,6 +1227,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, (tx->ctx->send_ttl != 1U || bt_mesh_tag_relay(tx->ctx->send_tag)) && tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_client_relay(&buf->b, tx->ctx->addr)) { + BT_DBG("ProxyClientRelay"); + /* If Proxy Client succeeds to send messages with GATT bearer, * we can directly finish here. And if not, which means no * connection has been created with Proxy Client, here we will @@ -1175,7 +1237,6 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { send_cb_finalize(send_cb, cb_data); send_cb = NULL; - goto done; } } @@ -1203,11 +1264,11 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, } bt_mesh_net_local(); - goto done; } net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + bt_mesh_net_local(); } @@ -1226,16 +1287,12 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, */ bt_mesh_net_adv_xmit_update(tx); - BT_INFO("Network PDU, count %d, interval %d", - BLE_MESH_TRANSMIT_COUNT(tx->xmit), BLE_MESH_TRANSMIT_INT(tx->xmit)); bt_mesh_adv_send(buf, tx->xmit, cb, cb_data); - goto done; } - BT_WARN("Not sent, src 0x%04x, dst 0x%04x, ttl %d, cred 0x%02x, tag 0x%02x", - tx->src, tx->ctx->addr, tx->ctx->send_ttl, tx->ctx->send_cred, - tx->ctx->send_tag); + BT_WARN("NetNotSend"); + err = -EIO; done: @@ -1249,7 +1306,10 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, { uint8_t net_auth[8] = {0}; + BT_DBG("AuthMatch"); + if (memcmp(net_id, keys->net_id, 8)) { + BT_DBG("NetID %s != %s", bt_hex(net_id, 8), bt_hex(keys->net_id, 8)); return false; } @@ -1257,8 +1317,7 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, net_auth); if (memcmp(auth, net_auth, 8)) { - BT_WARN("Authentication Value %s != %s", - bt_hex(auth, 8), bt_hex(net_auth, 8)); + BT_WARN("NetAuth %s != %s", bt_hex(auth, 8), bt_hex(net_auth, 8)); return false; } @@ -1274,6 +1333,8 @@ struct bt_mesh_subnet *bt_mesh_subnet_find_with_snb(const uint8_t net_id[8], uin subnet_size = bt_mesh_rx_netkey_size(); + BT_DBG("SubnetFindWithSnb, Size %lu", subnet_size); + for (i = 0; i < subnet_size; i++) { struct bt_mesh_subnet *sub = bt_mesh_rx_netkey_get(i); @@ -1304,8 +1365,10 @@ int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, size_t data_len, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); - BT_DBG("IVI %u net->iv_index 0x%08x", BLE_MESH_NET_HDR_IVI(data), bt_mesh.iv_index); + BT_DBG("NetDecrypt"); + BT_DBG("IVI %u NID 0x%02x NetIdx 0x%04x IVIndex %lu NetIf %u", + BLE_MESH_NET_HDR_IVI(data), BLE_MESH_NET_HDR_NID(data), + sub->net_idx, bt_mesh.iv_index, rx->net_if); rx->old_iv = (BLE_MESH_NET_HDR_IVI(data) != (bt_mesh.iv_index & 0x01)); @@ -1327,12 +1390,11 @@ int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, return -EALREADY; } - BT_DBG("src 0x%04x", rx->ctx.addr); + BT_DBG("Src 0x%04x", rx->ctx.addr); if (IS_ENABLED(CONFIG_BLE_MESH_PROXY) && rx->net_if == BLE_MESH_NET_IF_PROXY_CFG) { - return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), - true, false); + return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), true, false); } return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), false, false); @@ -1345,7 +1407,9 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, { int i; - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + BT_DBG("FrndDecrypt"); + BT_DBG("NID 0x%02x NetIdx 0x%04x KrPhase %u", + BLE_MESH_NET_HDR_NID(data), sub->net_idx, sub->kr_phase); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -1357,6 +1421,7 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == cred->cred[0].nid && !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, data, data_len, rx, buf)) { + BT_DBG("UseOldKey"); return 0; } @@ -1367,6 +1432,7 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == cred->cred[1].nid && !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, data, data_len, rx, buf)) { + BT_DBG("UseNewKey"); rx->new_key = 1U; return 0; } @@ -1380,11 +1446,14 @@ static int flooding_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, size_t data_len, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + BT_DBG("FloodingDecrypt"); + BT_DBG("NID 0x%02x NetIdx 0x%04x KrPhase %u", + BLE_MESH_NET_HDR_NID(data), sub->net_idx, sub->kr_phase); if (BLE_MESH_NET_HDR_NID(data) == sub->keys[0].nid && !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, data, data_len, rx, buf)) { + BT_DBG("UseOldKey"); return 0; } @@ -1395,6 +1464,7 @@ static int flooding_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == sub->keys[1].nid && !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, data, data_len, rx, buf)) { + BT_DBG("UseNewKey"); rx->new_key = 1U; return 0; } @@ -1412,10 +1482,12 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, array_size = bt_mesh_rx_netkey_size(); + BT_DBG("NetFindAndDecrypt, Size %u", array_size); + for (i = 0; i < array_size; i++) { sub = bt_mesh_rx_netkey_get(i); if (!sub) { - BT_DBG("Subnet not found"); + BT_DBG("SubNotFound"); continue; } @@ -1425,7 +1497,7 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, #if CONFIG_BLE_MESH_BRC_SRV sub->sbr_net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ #if (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) if (!friend_decrypt(sub, data, data_len, rx, buf)) { @@ -1434,7 +1506,7 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, rx->sub = sub; return true; } -#endif +#endif /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ #if CONFIG_BLE_MESH_DF_SRV if (!bt_mesh_directed_decrypt(sub, data, data_len, rx, buf)) { @@ -1463,6 +1535,8 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, */ static bool relay_to_adv(enum bt_mesh_net_if net_if) { + BT_DBG("RelayToAdv, NetIf %u", net_if); + switch (net_if) { case BLE_MESH_NET_IF_LOCAL: return true; @@ -1472,7 +1546,7 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED #if CONFIG_BLE_MESH_PRB_SRV || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ); default: return false; @@ -1483,6 +1557,8 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, uint8_t *cred, uint8_t *tag) { + BT_DBG("NetRetransmissionAdv"); + if (rx->ctx.recv_cred == BLE_MESH_FLOODING_CRED) { uint8_t bearer = BLE_MESH_NONE_BEARER; @@ -1506,6 +1582,8 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, *cred = BLE_MESH_FLOODING_CRED; } + BT_DBG("FloodingBearer 0x%02x", bearer); + return bearer; } @@ -1515,6 +1593,9 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, /* Condition: Directed friend is disabled. */ *cred = BLE_MESH_FLOODING_CRED; + + BT_DBG("FrndBearerAll"); + return BLE_MESH_ALL_BEARERS; } @@ -1524,6 +1605,8 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, static uint8_t net_retransmission_gatt(struct bt_mesh_net_rx *rx, uint8_t *cred, uint8_t *tag) { + BT_DBG("NetRetransmissionGatt"); + if (rx->ctx.recv_cred == BLE_MESH_FLOODING_CRED) { /* Inbound bearer: GATT; * Inbound Security Material: managed flooding; @@ -1533,6 +1616,9 @@ static uint8_t net_retransmission_gatt(struct bt_mesh_net_rx *rx, bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { /* Condition: Directed proxy is disabled. */ *cred = BLE_MESH_FLOODING_CRED; + + BT_DBG("FloodingBearerAll"); + return BLE_MESH_ALL_BEARERS; } @@ -1561,14 +1647,19 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, struct bt_mesh_net_rx *rx) { const uint8_t *enc = NULL, *priv = NULL; + bool netkey_changed = false; struct net_buf *buf = NULL; uint8_t bearer = 0; uint8_t xmit = 0U; uint8_t cred = 0; uint8_t nid = 0U; - bool netkey_changed = false; uint8_t tag = 0; + BT_DBG("NetRelay"); + BT_DBG("TTL %u CTL %u Dst 0x%04x RecvCred %u NetIf %u", + rx->ctx.recv_ttl, rx->ctl, rx->ctx.recv_dst, + rx->ctx.recv_cred, rx->net_if); + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { /* Locally originated PDUs with TTL=1 will only be delivered * to local elements as per Mesh Profile 1.0 section 3.4.5.2: @@ -1624,12 +1715,12 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, BT_ERR("Bridge RPL attack"); goto done; } -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ if (cred != BLE_MESH_FLOODING_CRED #if CONFIG_BLE_MESH_DF_SRV - && cred != BLE_MESH_DIRECTED_CRED -#endif + && cred != BLE_MESH_DIRECTED_CRED +#endif /* CONFIG_BLE_MESH_DF_SRV */ ) { BT_WARN("No outbound security cred found, inbound cred %d", rx->ctx.recv_cred); return; @@ -1645,8 +1736,6 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, return; } - BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, rx->ctx.recv_dst); - /* The Relay Retransmit state is only applied to adv-adv relaying. * Anything else (like GATT to adv, or locally originated packets) * use the Network Transmit state. @@ -1679,7 +1768,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (rx->ctx.enh.long_pkt_cfg) { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); } else -#endif +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); } @@ -1690,15 +1779,15 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; } } else -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); } -#else +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ /* Check if the number of relay packets in queue is too large, if so * use minimum relay retransmit value for later relay packets. */ - if (bt_mesh_get_stored_relay_count() >= BLE_MESH_MAX_STORED_RELAY_COUNT) { + if (bt_mesh_get_stored_relay_count() >= MAX_STORED_RELAY_COUNT) { xmit = BLE_MESH_TRANSMIT(0, 20); } #if CONFIG_BLE_MESH_EXT_ADV @@ -1707,7 +1796,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (rx->ctx.enh.long_pkt_cfg) { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); } else -#endif +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); } @@ -1718,11 +1807,11 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; } } else -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ { - buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); } -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ if (!buf) { BT_INFO("Out of relay buffers"); @@ -1754,10 +1843,12 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, /* Check if subnet bridge is supported & decide which NetKey is used */ if (bt_mesh_subnet_bridge_state_get() == BLE_MESH_SUBNET_BRIDGE_ENABLED) { netkey_changed = bt_mesh_bridge_change_net_key(rx, &enc, &priv, &nid, cred); + + BT_DBG("NetKeyChanged %u", netkey_changed); } -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ - BT_DBG("Relaying packet. TTL is now %u", BLE_MESH_NET_HDR_TTL(buf->data)); + BT_DBG("Relaying, NewTTL %u", BLE_MESH_NET_HDR_TTL(buf->data)); /* 1. Update NID if RX or RX was with friend credentials(included by case 3). * 2. Update NID if the net_key has changed. @@ -1773,12 +1864,10 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, * layer nonce includes the IVI. */ if (bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_RX(rx), false, false)) { - BT_ERR("Re-encrypting failed"); goto done; } if (bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_RX(rx), priv)) { - BT_ERR("Re-obfuscating failed"); goto done; } @@ -1795,14 +1884,15 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, cred != BLE_MESH_FRIENDSHIP_CRED) || #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED || -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ rx->net_if == BLE_MESH_NET_IF_LOCAL || rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED)) { if (bt_mesh_proxy_server_relay(&buf->b, rx->ctx.recv_dst) && BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - + /* Not relay if only GATT bearer is chosen or found Proxy Client */ if (((bearer & (~BLE_MESH_GATT_BEARER)) == 0) || bt_mesh_proxy_server_find_client_by_addr(rx->ctx.recv_dst)) { + BT_DBG("ProxyNotRelay"); goto done; } } @@ -1814,9 +1904,9 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED) { #if !CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_adv_send(buf, xmit, NULL, NULL); -#else +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ bt_mesh_relay_adv_send(buf, xmit, rx->ctx.addr, rx->ctx.recv_dst, NULL, NULL); -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ } done: @@ -1826,6 +1916,8 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, void bt_mesh_net_header_parse(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { + BT_DBG("NetHeaderParse"); + rx->old_iv = (BLE_MESH_NET_HDR_IVI(buf->data) != (bt_mesh.iv_index & 0x01)); rx->ctl = BLE_MESH_NET_HDR_CTL(buf->data); rx->ctx.recv_ttl = BLE_MESH_NET_HDR_TTL(buf->data); @@ -1837,9 +1929,10 @@ void bt_mesh_net_header_parse(struct net_buf_simple *buf, int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { + BT_DBG("NetDecode, NetIf %u", net_if); + if (data->len < BLE_MESH_NET_MIN_PDU_LEN) { BT_WARN("Dropping too short mesh packet (len %u)", data->len); - BT_WARN("%s", bt_hex(data->data, data->len)); return -EINVAL; } @@ -1847,7 +1940,7 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, return -EINVAL; } - BT_DBG("%u bytes: %s", data->len, bt_hex(data->data, data->len)); + BT_DBG("Len %u: %s", data->len, bt_hex(data->data, data->len)); rx->net_if = net_if; @@ -1883,8 +1976,6 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, rx->seq = BLE_MESH_NET_HDR_SEQ(buf->data); rx->ctx.recv_dst = BLE_MESH_NET_HDR_DST(buf->data); - BT_DBG("Decryption successful. Payload len %u", buf->len); - if (net_if != BLE_MESH_NET_IF_PROXY_CFG && rx->ctx.recv_dst == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("Destination address is unassigned; dropping packet"); @@ -1897,16 +1988,15 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, BT_ERR("Destination address is RFU; dropping packet 0x%02x", rx->ctx.recv_dst); return -EBADMSG; } -#endif +#endif /* !CONFIG_BLE_MESH_BQB_TEST */ if (net_if != BLE_MESH_NET_IF_LOCAL && bt_mesh_elem_find(rx->ctx.addr)) { BT_DBG("Dropping locally originated packet"); return -EBADMSG; } - BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst, - rx->ctx.recv_ttl); - BT_DBG("PDU: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL %u", rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_ttl); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); msg_cache_add(rx); @@ -1916,25 +2006,31 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, static bool ready_to_recv(void) { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + BT_DBG("NodeReadyToRecv"); return true; } if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { if (bt_mesh_provisioner_get_node_count()) { + BT_DBG("PvnrReadyToRecv"); return true; } } + BT_DBG("NotReadyToRecv"); return false; } static bool ignore_net_msg(uint16_t src, uint16_t dst) { + BT_DBG("IgnoreNetMsg, Src 0x%04x Dst 0x%04x", src, dst); + if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { /* When fast provisioning is enabled, the node addr * message will be sent to the Primary Provisioner, * which shall not be ignored here. */ + BT_DBG("FastProvNotIgnoreNetMsg"); return false; } @@ -1949,11 +2045,12 @@ static bool ignore_net_msg(uint16_t src, uint16_t dst) */ if (!bt_mesh_provisioner_get_node_with_addr(src) && !bt_mesh_elem_find(src)) { - BT_INFO("Not found node address 0x%04x", src); + BT_INFO("PvnrIgnoreNetMsg"); return true; } } + BT_DBG("NotIgnoreNetMsg"); return false; } @@ -1982,16 +2079,24 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, BT_DBG("rssi %d net_if %u", rx->ctx.recv_rssi, net_if); if (bt_mesh_net_decode(data, net_if, rx, buf)) { + BT_DBG("DecodeFailed"); goto free_net_msg_buf; } + BT_DBG("NetRecv, Src 0x%04x Dst 0x%04x Rssi %d NetIf %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_rssi, net_if); + if (ignore_net_msg(rx->ctx.addr, rx->ctx.recv_dst)) { + BT_DBG("IgnoreNetMsg"); goto free_net_msg_buf; } /* Save the state so the buffer can later be relayed */ net_buf_simple_save(buf, &state); + BT_DBG("NetRecv, Src 0x%04x Dst 0x%04x Rssi %d NetIf %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_rssi, net_if); + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_NET, "\nNetRecv: ctl: %d, src: %d, dst: %d, ttl: %d, data: 0x%s", @@ -2003,8 +2108,8 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, * corresponding subnet. */ rx->local_match = (bt_mesh_fixed_group_match(rx->ctx.recv_dst) || - bt_mesh_fixed_direct_match(rx->sub, rx->ctx.recv_dst) || - bt_mesh_elem_find(rx->ctx.recv_dst)); + bt_mesh_fixed_direct_match(rx->sub, rx->ctx.recv_dst) || + bt_mesh_elem_find(rx->ctx.recv_dst)); #if CONFIG_BLE_MESH_LONG_PACKET /* It should be noted that if the length of buf @@ -2018,8 +2123,10 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_gatt_proxy_state_get() != BLE_MESH_PRIVATE_GATT_PROXY_ENABLED && -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ net_if == BLE_MESH_NET_IF_PROXY) { + BT_DBG("ProxyServerAddrAdd"); + bt_mesh_proxy_server_addr_add(data, rx->ctx.addr); if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_DISABLED && @@ -2040,6 +2147,7 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, rx->sub->use_directed == BLE_MESH_PROXY_USE_DIRECTED_ENABLED && !bt_mesh_addr_in_uar(&rx->sub->proxy_client_uar, rx->ctx.addr) && !bt_mesh_proxy_server_find_client_by_addr(rx->ctx.addr)) { + BT_DBG("ImmutableCredTag"); rx->ctx.recv_tag |= BLE_MESH_TAG_IMMUTABLE_CRED; } #endif /* CONFIG_BLE_MESH_DF_SRV */ @@ -2080,7 +2188,7 @@ static void ivu_refresh(struct k_work *work) { bt_mesh.ivu_duration += BLE_MESH_IVU_HOURS; - BT_INFO("%s for %u hour%s", + BT_INFO("IVURefresh, %s for %u hour%s", bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) ? "IVU in Progress" : "IVU Normal mode", bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1U ? "" : "s"); @@ -2104,6 +2212,8 @@ static void ivu_refresh(struct k_work *work) void bt_mesh_net_start(void) { + BT_DBG("NetStart"); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_enable(); } else { @@ -2116,7 +2226,7 @@ void bt_mesh_net_start(void) } else { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { @@ -2129,7 +2239,7 @@ void bt_mesh_net_start(void) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { /* TODO: Enable duplicate scan in Low Power Mode */ @@ -2148,6 +2258,7 @@ void bt_mesh_net_start(void) uint32_t iv_index = bt_mesh.iv_index; uint8_t flags = (uint8_t)bt_mesh.sub[0].kr_flag; const uint8_t *net_key = bt_mesh.sub[0].keys[flags].net; + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { flags |= BLE_MESH_NET_FLAG_IVU; } @@ -2158,16 +2269,20 @@ void bt_mesh_net_start(void) void bt_mesh_net_init(void) { + BT_DBG("NetInit"); + k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); } void bt_mesh_net_reset(void) { + BT_DBG("NetReset"); + k_delayed_work_cancel(&bt_mesh.ivu_timer); #if FRIEND_CRED_COUNT > 0 memset(friend_cred, 0, sizeof(friend_cred)); -#endif +#endif /* FRIEND_CRED_COUNT > 0 */ memset(msg_cache, 0, sizeof(msg_cache)); msg_cache_next = 0U; @@ -2182,6 +2297,8 @@ void bt_mesh_net_reset(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_net_deinit(void) { + BT_DBG("NetDeinit"); + bt_mesh_net_reset(); k_delayed_work_free(&bt_mesh.ivu_timer); diff --git a/components/bt/esp_ble_mesh/core/net.h b/components/bt/esp_ble_mesh/core/net.h index e946daef0f23..1141bd2bd953 100644 --- a/components/bt/esp_ble_mesh/core/net.h +++ b/components/bt/esp_ble_mesh/core/net.h @@ -66,7 +66,7 @@ struct bt_mesh_subnet { #if CONFIG_BLE_MESH_BRC_SRV uint16_t sbr_net_idx; /* NetKeyIndex of bridged subnet */ -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ bool kr_flag; /* Key Refresh Flag */ uint8_t kr_phase; /* Key Refresh Phase */ @@ -163,17 +163,17 @@ struct bt_mesh_rpl { bool old_iv; #if CONFIG_BLE_MESH_SETTINGS bool store; -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS */ uint32_t seq; }; #if CONFIG_BLE_MESH_FRIEND #define FRIEND_SEG_RX CONFIG_BLE_MESH_FRIEND_SEG_RX #define FRIEND_SUB_LIST_SIZE CONFIG_BLE_MESH_FRIEND_SUB_LIST_SIZE -#else +#else /* CONFIG_BLE_MESH_FRIEND */ #define FRIEND_SEG_RX 0 #define FRIEND_SUB_LIST_SIZE 0 -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ struct bt_mesh_friend { uint16_t lpn; @@ -220,10 +220,10 @@ struct bt_mesh_friend { }; #if CONFIG_BLE_MESH_LOW_POWER -#define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS -#else -#define LPN_GROUPS 0 -#endif +#define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS +#else /* CONFIG_BLE_MESH_LOW_POWER */ +#define LPN_GROUPS 0 +#endif /* CONFIG_BLE_MESH_LOW_POWER */ /* Low Power Node state */ struct bt_mesh_lpn { @@ -275,7 +275,7 @@ struct bt_mesh_lpn { #if CONFIG_BLE_MESH_DF_SRV uint8_t old_directed_forwarding; -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ /* Duration reported for last advertising packet */ uint16_t adv_duration; @@ -331,11 +331,11 @@ struct bt_mesh_net { #if CONFIG_BLE_MESH_FRIEND /* Friend state, unique for each LPN that we're Friends for */ struct bt_mesh_friend frnd[CONFIG_BLE_MESH_FRIEND_LPN_COUNT]; -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ #if CONFIG_BLE_MESH_LOW_POWER struct bt_mesh_lpn lpn; /* Low Power Node state */ -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ /* Number of hours in current IV Update state */ uint8_t ivu_duration; @@ -362,7 +362,7 @@ struct bt_mesh_net { struct bt_mesh_subnet *p_sub[CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT]; /* Next net_idx can be assigned */ uint16_t p_net_idx_next; -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ }; /* Network interface */ @@ -393,7 +393,7 @@ struct bt_mesh_net_rx { friend_match:1, /* Matched an LPN we're friends for */ #if CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG replay_msg:1, /* Replayed messages */ -#endif +#endif /* CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG */ sbr_rpl:1; /* Bridge RPL attacker */ uint16_t msg_cache_idx; /* Index of entry in message cache */ }; @@ -431,7 +431,7 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num); int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, const uint8_t key[16]); -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t net_idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index); uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub); diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index f5fd0279fc43..4d598a333e28 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -993,16 +993,16 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_ADV_COMPLETE: - BT_DBG("advertise complete; reason=%d", - event->adv_complete.reason); + BT_DBG("advertise complete; reason=%d", event->adv_complete.reason); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ assert(CONFIG_BLE_MESH_ADV_INST_ID == event->adv_complete.instance); /* Limit Reached (0x43) and Advertising Timeout (0x3C) will cause BLE_HS_ETIMEOUT to be set. */ if (event->adv_complete.reason == BLE_HS_ETIMEOUT) { - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -1020,12 +1020,12 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) */ if (bt_mesh_is_ble_adv_running() && event->adv_complete.reason == 0) { - /* The unset operation must be performed before waking up the - * adv task; performing the unset after waking up the adv task - * could lead to resource contention issues. - */ + /* The unset operation must be performed before waking up the + * adv task; performing the unset after waking up the adv task + * could lead to resource contention issues. + */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -1124,12 +1124,12 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) BT_DBG("Provisioner advertise complete; reason=%d", event->adv_complete.reason); #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ assert(CONFIG_BLE_MESH_ADV_INST_ID == event->adv_complete.instance); /* Limit Reached (0x43) and Advertising Timeout (0x3C) will cause BLE_HS_ETIMEOUT to be set. */ if (event->adv_complete.reason == BLE_HS_ETIMEOUT) { - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -1152,7 +1152,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) * could lead to resource contention issues. */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -1167,7 +1167,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) static struct { bool set; struct ble_gap_ext_adv_params param; -} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; +} last_param[BLE_MESH_ADV_INST_TYPES_NUM]; int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, @@ -2516,8 +2516,7 @@ void bt_mesh_gatt_init(void) static bool init = false; if (init == false) { - - __ASSERT(g_gatts_svcs_add, "func bt_mesh_gatts_svcs_add should be called before mesh init"); + assert(g_gatts_svcs_add); ble_gatts_svc_set_visibility(prov_svc_start_handle, 1); ble_gatts_svc_set_visibility(proxy_svc_start_handle, 0); diff --git a/components/bt/esp_ble_mesh/core/prov_common.c b/components/bt/esp_ble_mesh/core/prov_common.c index 6f9e1dfa417c..bf5657852b87 100644 --- a/components/bt/esp_ble_mesh/core/prov_common.c +++ b/components/bt/esp_ble_mesh/core/prov_common.c @@ -48,6 +48,7 @@ void bt_mesh_prov_buf_init(struct net_buf_simple *buf, uint8_t type) bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action) { + BT_DBG("ProvOutputAction:%d", action); switch (action) { case OUTPUT_OOB_BLINK: return BLE_MESH_BLINK; @@ -66,6 +67,7 @@ bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action) bt_mesh_input_action_t bt_mesh_prov_input_action(uint8_t action) { + BT_DBG("ProvInputAction:%d", action); switch (action) { case INPUT_OOB_PUSH: return BLE_MESH_PUSH; @@ -151,20 +153,27 @@ static uint8_t bt_mesh_prov_buf_type_get(struct net_buf_simple *buf) uint8_t node_next_xact_id(struct bt_mesh_prov_link *link) { + uint8_t nxt_xact_id = 0; if (link->tx.id != 0 && link->tx.id != 0xFF) { - return ++link->tx.id; + nxt_xact_id = ++link->tx.id; + } else { + link->tx.id = 0x80; + nxt_xact_id = 0x80; } - link->tx.id = 0x80; - return link->tx.id; + BT_DBG("NodeNextXActId:%d", nxt_xact_id); + return nxt_xact_id; } uint8_t pvnr_next_xact_id(struct bt_mesh_prov_link *link) { + uint8_t nxt_xact_id = 0; if (link->tx.id > 0x7F) { link->tx.id = 0; } - return link->tx.id++; + nxt_xact_id = link->tx.id++; + BT_DBG("PvnrNextXActId:%d", nxt_xact_id); + return nxt_xact_id; } bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, @@ -186,7 +195,7 @@ bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, link->rx.id = rx->xact_id; link->rx.fcs = net_buf_simple_pull_u8(buf); - BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, + BT_DBG("LinkId:%08x,len %u last_seg %u total_len %u fcs 0x%02x", link->link_id, buf->len, START_LAST_SEG(rx->gpc), link->rx.buf->len, link->rx.fcs); /* At least one-octet pdu type is needed */ @@ -227,9 +236,10 @@ bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, link->rx.last_seg = START_LAST_SEG(rx->gpc); memcpy(link->rx.buf->data, buf->data, buf->len); XACT_SEG_RECV(link, 0); - + BT_DBG("Seg: %04x, lastSeg: %04x, Data: %s", link->rx.seg, link->rx.last_seg, bt_hex(buf->data, buf->len)); /* Still have some segments to receive */ if (link->rx.seg) { + BT_DBG("Still have some segments to receive: %02x", link->rx.seg); return false; } @@ -242,7 +252,7 @@ bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, { uint8_t seg = CONT_SEG_INDEX(rx->gpc); - BT_DBG("len %u, seg_index %u", buf->len, seg); + BT_DBG("LinkId:%08x,len %u,seg_index %u", link->link_id, buf->len, seg); if (link->rx.seg == 0 && link->rx.prev_id == rx->xact_id) { BT_INFO("Resending ack"); @@ -287,6 +297,7 @@ bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, /* Still have some segments to receive */ if (link->rx.seg) { + BT_DBG("Still have some segments to receive: %02x", link->rx.seg); return false; } @@ -346,12 +357,14 @@ void bt_mesh_gen_prov_ack_send(struct bt_mesh_prov_link *link, uint8_t xact_id) net_buf_add_u8(buf, xact_id); net_buf_add_u8(buf, GPC_ACK); + BT_DBG("GenericProvAckSend,LinkId:%08x,XActId:%02x", link->link_id, xact_id); bt_mesh_adv_send(buf, PROV_XMIT, complete, link); net_buf_unref(buf); } static void free_segments(struct bt_mesh_prov_link *link) { + BT_DBG("FreeSegments:%08x", link->link_id); for (size_t i = 0; i < ARRAY_SIZE(link->tx.buf); i++) { struct net_buf *buf = link->tx.buf[i]; @@ -386,6 +399,7 @@ static void buf_sent(int err, void *user_data) int32_t timeout = RETRANSMIT_TIMEOUT; if (!link->tx.buf[0]) { + BT_DBG("LinkId:%08x,NoTxBuf", link->link_id); return; } @@ -412,6 +426,8 @@ static void prov_retransmit(struct k_work *work) struct bt_mesh_prov_link *link = work->user_data; int64_t timeout = TRANSACTION_TIMEOUT; + BT_DBG("LinkRetransmit:%08x,flag:%s", link->link_id, bt_hex(link->flags, sizeof(link->flags))); + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) && !bt_mesh_atomic_test_bit(link->flags, LINK_CLOSING)) { BT_WARN("Link not active"); @@ -419,6 +435,9 @@ static void prov_retransmit(struct k_work *work) } #if CONFIG_BLE_MESH_FAST_PROV + BT_DBG("FastProv, TxPDUType %u LastTxPDU %u", + link->tx_pdu_type, link->last_tx_pdu); + if (link->tx_pdu_type >= link->last_tx_pdu) { timeout = K_SECONDS(30); } @@ -490,7 +509,7 @@ static void prov_retransmit(struct k_work *work) BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + if (likely(i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1])) { bt_mesh_adv_send(buf, PROV_XMIT, NULL, NULL); } else { bt_mesh_adv_send(buf, PROV_XMIT, &buf_sent_cb, link); @@ -518,7 +537,7 @@ static void send_reliable(struct bt_mesh_prov_link *link, uint8_t xmit) break; } - if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + if (likely(i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1])) { bt_mesh_adv_send(buf, xmit, NULL, NULL); } else { bt_mesh_adv_send(buf, xmit, &buf_sent_cb, link); @@ -651,6 +670,9 @@ int bt_mesh_prov_send_adv(struct bt_mesh_prov_link *link, struct net_buf_simple send_reliable(link, PROV_XMIT); #if CONFIG_BLE_MESH_FAST_PROV + BT_DBG("FastProv, TxPDUType %u LastTxPDU %u", + link->tx_pdu_type, link->last_tx_pdu); + if (link->tx_pdu_type >= link->last_tx_pdu) { timeout = K_SECONDS(60); } diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index cf78947071ab..973239097d75 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,7 @@ struct bt_mesh_prov_link *bt_mesh_prov_node_get_link(void) static void close_link(uint8_t reason) { + BT_DBG("LinkClose(Rpr:%d),Reason:%d", bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE), reason); if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { if (prov_link.pb_remote_close) { prov_link.pb_remote_close(&prov_link, reason); @@ -69,6 +70,7 @@ void bt_mesh_prov_node_close_link(uint8_t reason) static void reset_state(void) { + BT_INFO("ProvLinkStateReset"); k_delayed_work_cancel(&prov_link.prot_timer); /* Disable Attention Timer if it was set */ @@ -122,6 +124,7 @@ static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { ARG_UNUSED(link); + BT_INFO("ResetAdvLink:%08x", link->link_id); bt_mesh_prov_clear_tx(&prov_link, true); if (bt_mesh_prov_get()->link_close) { @@ -267,6 +270,7 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size) auth_size = PROV_AUTH_SIZE(&prov_link); + BT_INFO("ProvAuth:method:%d,action:%d,size:%d", method, action, size); switch (method) { case AUTH_METHOD_NO_OOB: if (action || size) { @@ -411,6 +415,7 @@ static void prov_start(const uint8_t *data) if ((bt_mesh_prov_get()->oob_type & BIT(PROV_ONLY_OOB_AUTH_SUPPORT)) && ((data[0] == PROV_ALG_P256_HMAC_SHA256 && data[2] == AUTH_METHOD_NO_OOB) || data[0] == PROV_ALG_P256_CMAC_AES128)) { + BT_WARN("InvalidCapabilities,Alg:%d,Method:%d", data[0], data[2]); close_link(PROV_ERR_NVAL_FMT); return; } @@ -561,9 +566,10 @@ int bt_mesh_input_number(uint32_t num) auth_size = PROV_AUTH_SIZE(&prov_link); - BT_INFO("%u", num); + BT_INFO("ProvInputNumber:%u", num); if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_NUMBER)) { + BT_WARN("InvalidFlag:WAIT_NUMBER"); return -EINVAL; } @@ -572,6 +578,7 @@ int bt_mesh_input_number(uint32_t num) send_input_complete(); if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { + BT_INFO("DHKeyExists"); return 0; } @@ -587,6 +594,7 @@ int bt_mesh_input_string(const char *str) BT_INFO("%s", str); if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_STRING)) { + BT_WARN("InvalidFlag:WAIT_STRING"); return -EINVAL; } @@ -595,6 +603,7 @@ int bt_mesh_input_string(const char *str) send_input_complete(); if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { + BT_INFO("DHKeyExists"); return 0; } @@ -712,6 +721,7 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], /* If remote public key is not got, just return */ if (!bt_mesh_atomic_test_bit(prov_link.flags, REMOTE_PUB_KEY)) { + BT_WARN("RemotePubKeyNotSet"); return 0; } @@ -902,6 +912,7 @@ static void prov_data(const uint8_t *data) uint8_t reason = 0; if (bt_mesh_rpr_srv_nppi_check(prov_link.pb_remote_nppi, pdu, net_idx, iv_index, addr, &reason) == false) { + BT_WARN("RprNppiCheckFail:%d", reason); close_link(reason); return; } @@ -924,6 +935,7 @@ static void prov_data(const uint8_t *data) pdu, net_idx, flags, iv_index, addr, dev_key); if (err) { + BT_WARN("RprNppiStoreFail:%d", err); close_link(PROV_ERR_UNEXP_ERR); return; } @@ -964,6 +976,7 @@ static void prov_data(const uint8_t *data) * using Node Identity. */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && identity_enable) { + BT_DBG("EnableProxyIdentity"); bt_mesh_proxy_identity_enable(); } } @@ -973,7 +986,7 @@ static void prov_complete(const uint8_t *data) static void prov_failed(const uint8_t *data) { - BT_WARN("Error: 0x%02x", data[0]); + BT_WARN("ProvError: 0x%02x", data[0]); #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { @@ -1011,7 +1024,7 @@ static const struct { #if CONFIG_BLE_MESH_PB_ADV static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkOpenLen:%u", buf->len); if (buf->len < 16) { BT_ERR("Too short bearer open message (len %u)", buf->len); @@ -1065,7 +1078,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkAckLen:%u",buf->len); #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { @@ -1094,7 +1107,7 @@ static void link_close(struct prov_rx *rx, struct net_buf_simple *buf) { uint8_t reason = 0; - BT_DBG("len %u", buf->len); + BT_DBG("LinkCloseLen %u", buf->len); if (buf->len != 1) { BT_ERR("Invalid Link Close length %d", buf->len); @@ -1258,12 +1271,14 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) BT_DBG("len %u", buf->len); if (!prov_link.tx.buf[0]) { + BT_DBG("AlreadyReceived"); return; } #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { if (prov_link.tx.id == 0) { + BT_DBG("ZeroTxId"); return; } @@ -1278,6 +1293,7 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) #endif /* CONFIG_BLE_MESH_RPR_SRV */ if (rx->xact_id == prov_link.tx.id) { + BT_DBG("XActId:%04x,ReceivedAck", rx->xact_id); bt_mesh_prov_clear_tx(&prov_link, true); } } @@ -1342,7 +1358,7 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) rx.xact_id = net_buf_simple_pull_u8(buf); rx.gpc = net_buf_simple_pull_u8(buf); - BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + BT_DBG("link_id 0x%08x xact_id %u gpc %u", rx.link_id, rx.xact_id, rx.gpc); if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE) && prov_link.link_id != rx.link_id) { @@ -1441,7 +1457,7 @@ int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) { - BT_DBG("conn %p", conn); + BT_DBG("ProvConnOpen %p", conn); /** * It's necessary to determine if it is PB_REMOTE because when the @@ -1482,7 +1498,7 @@ int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason) { - BT_DBG("conn %p", conn); + BT_DBG("ProvConnClose %p", conn); if (prov_link.conn != conn) { BT_ERR("Not connected"); diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index 091e3e860712..d1df4a69e11b 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -202,6 +202,7 @@ static inline void bt_mesh_pb_gatt_unlock(void) void bt_mesh_provisioner_pbg_count_dec(void) { + BT_DBG("PbgCntDec:%d", prov_ctx.pbg_count); if (prov_ctx.pbg_count) { prov_ctx.pbg_count--; } @@ -210,6 +211,7 @@ void bt_mesh_provisioner_pbg_count_dec(void) static inline void provisioner_pbg_count_inc(void) { prov_ctx.pbg_count++; + BT_DBG("PbgCntInc:%d", prov_ctx.pbg_count); } void bt_mesh_provisioner_clear_link_info(const uint8_t addr[6]) @@ -436,8 +438,8 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ */ if (assign_addr == BLE_MESH_ADDR_UNASSIGNED && prov_ctx.alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { - BT_ERR("No available unicast address to assign"); bt_mesh_pb_gatt_unlock(); + BT_ERR("No available unicast address to assign"); return -EIO; } @@ -451,6 +453,7 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ !bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE)) { if (bt_mesh_gattc_conn_create(addr, BLE_MESH_UUID_MESH_PROV_VAL)) { bt_mesh_pb_gatt_unlock(); + BT_ERR("ProvGattCreateFailed:%s", bt_hex(addr->val, 6)); return -EIO; } @@ -598,6 +601,7 @@ int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u start: /* If not provisioning immediately, directly return here */ if (!(flags & START_PROV_NOW)) { + BT_DBG("StartProvNotSet"); return 0; } @@ -617,6 +621,9 @@ int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u } if ((err = provisioner_check_unprov_dev_info(add_dev->uuid, add_dev->bearer))) { + if (err == -EALREADY) { + BT_INFO("The device is being provisioning"); + } return err; } @@ -710,6 +717,9 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint } if ((err = provisioner_check_unprov_dev_info(uuid, bearer))) { + if (err == -EALREADY) { + BT_INFO("The device is being provisioning"); + } return err; } @@ -749,10 +759,12 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) return -EINVAL; } + BT_INFO("ProvisionerDeleteDevice:%s", bt_hex(del_dev->uuid, 16)); /* Find if the device is in the device queue */ for (i = 0; i < ARRAY_SIZE(unprov_dev); i++) { if (!memcmp(unprov_dev[i].uuid, del_dev->uuid, 16)) { memset(&unprov_dev[i], 0, sizeof(struct unprov_dev_queue)); + BT_INFO("Device is in the queue"); break; } } @@ -761,6 +773,7 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) for (i = 0; i < ARRAY_SIZE(prov_links); i++) { if (!memcmp(prov_links[i].uuid, del_dev->uuid, 16)) { close_link(&prov_links[i], CLOSE_REASON_FAILED); + BT_INFO("Device is being provisioned"); break; } } @@ -776,6 +789,7 @@ int bt_mesh_provisioner_set_dev_uuid_match(uint8_t offset, uint8_t length, return -EINVAL; } + BT_INFO("SetUUIDMatch,offset:%d,value:%s,flag:%d", offset, bt_hex(match, length), prov_flag); (void)memset(prov_ctx.match_value, 0, 16); prov_ctx.match_offset = offset; @@ -795,6 +809,7 @@ int bt_mesh_provisioner_adv_pkt_cb_register(unprov_adv_pkt_cb_t cb) return -EINVAL; } + BT_INFO("RegisterAdvCB:%p", notify_unprov_adv_pkt_cb); notify_unprov_adv_pkt_cb = cb; return 0; } @@ -815,6 +830,7 @@ int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info) } prov_ctx.net_idx = info->net_idx; + BT_INFO("SetProvCtx,NetIndex:%d", info->net_idx); } return 0; @@ -881,6 +897,7 @@ void bt_mesh_provisioner_set_prov_bearer(bt_mesh_prov_bearer_t bearers, bool cle } else { prov_ctx.bearers &= ~bearers; } + BT_INFO("ProvCtxBearer:%04x,clear:%d", prov_ctx.bearers, clear); } bt_mesh_prov_bearer_t bt_mesh_provisioner_get_prov_bearer(void) @@ -909,7 +926,7 @@ int bt_mesh_provisioner_set_static_oob_value(const uint8_t *value, uint8_t lengt prov_ctx.static_oob_len = MIN(BLE_MESH_PROV_STATIC_OOB_MAX_LEN, length); memcpy(prov_ctx.static_oob_val, value, prov_ctx.static_oob_len); - + BT_INFO("SetStaticOob:%s", bt_hex(value, prov_ctx.static_oob_len)); return 0; } @@ -984,11 +1001,13 @@ int bt_mesh_test_provisioner_update_alloc_addr(uint16_t unicast_addr, uint16_t e void bt_mesh_provisioner_fast_prov_enable(bool enable) { prov_ctx.fast_prov.enable = enable; + BT_INFO("FastProvEnable:%d", enable); } void bt_mesh_provisioner_set_fast_prov_net_idx(uint16_t net_idx) { prov_ctx.fast_prov.net_idx = net_idx; + BT_INFO("FastProvNetIdx:%d", net_idx); } uint16_t bt_mesh_provisioner_get_fast_prov_net_idx(void) @@ -1017,7 +1036,7 @@ uint8_t bt_mesh_set_fast_prov_unicast_addr_range(uint16_t min, uint16_t max) prov_ctx.fast_prov.unicast_addr_max = max; prov_ctx.alloc_addr = prov_ctx.fast_prov.unicast_addr_min; - + BT_INFO("FastProv,AddrMin:%04x,Max:%04x,allocAddr:%04x", min, max, prov_ctx.alloc_addr); return 0x0; /* status: success */ } @@ -1038,6 +1057,7 @@ static struct net_buf_simple *get_rx_buf(const uint8_t idx) static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { + BT_INFO("ResetAdvLink:%08x", link->link_id); bt_mesh_prov_clear_tx(link, true); if (bt_mesh_prov_get()->prov_link_close) { @@ -1106,6 +1126,7 @@ static void send_link_open(struct bt_mesh_prov_link *link) if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && prov_links[i].link_id == link->link_id) { bt_mesh_rand(&link->link_id, sizeof(link->link_id)); + BT_DBG("ProvLinkIdx:%d,LinkId:%08x", i, link->link_id); break; } } @@ -1280,6 +1301,7 @@ static void prov_capabilities(struct bt_mesh_prov_link *link, if ((algorithms & BIT(PROV_ALG_P256_CMAC_AES128)) || (!((oob_type & BIT(PROV_STATIC_OOB_AVAILABLE)) == 0x00 || output_size == 0x00 || input_size == 0x00))) { + BT_INFO("InvalidOobTypeSet:%02x,Alg:%02x", oob_type, algorithms); goto fail; } } @@ -1358,6 +1380,7 @@ static void prov_capabilities(struct bt_mesh_prov_link *link, * send Remote Provisioning PDU Send with Public Key. */ if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + BT_DBG("WaitForRprClientCmd"); return; } @@ -1387,6 +1410,7 @@ static int prov_auth(struct bt_mesh_prov_link *link, bt_mesh_input_action_t input = 0U; uint8_t auth_size = PROV_AUTH_SIZE(link); + BT_INFO("ProvAuth:method:%d,action:%d,size:%d", method, action, size); switch (method) { case AUTH_METHOD_NO_OOB: if (action || size) { @@ -1778,6 +1802,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) */ if (link->auth_method == AUTH_METHOD_OUTPUT || link->auth_method == AUTH_METHOD_INPUT) { + BT_INFO("WaitForNextAction:%d", link->auth_method); return; } @@ -1814,6 +1839,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) * Input Complete, because if the authentication method is * Output OOB or Input OOB, it will directly return above. */ + BT_DBG("LinkExpect:%d", link->expect); if (link->expect != PROV_INPUT_COMPLETE) { send_confirm(link); } @@ -2094,6 +2120,7 @@ static void send_prov_data(struct bt_mesh_prov_link *link) link->unicast_addr = alloc_addr; } + BT_DBG("ProvAllocAddr:%04x", link->unicast_addr); bt_mesh_prov_buf_init(&buf, PROV_DATA); err = bt_mesh_prov_encrypt(session_key, nonce, pdu, net_buf_simple_add(&buf, 33)); @@ -2310,7 +2337,7 @@ static void prov_complete(struct bt_mesh_prov_link *link, static void prov_failed(struct bt_mesh_prov_link *link, struct net_buf_simple *buf) { - BT_WARN("Error 0x%02x", buf->data[0]); + BT_WARN("ProvError 0x%02x", buf->data[0]); close_link(link, CLOSE_REASON_FAILED); } @@ -2360,7 +2387,7 @@ static void close_link(struct bt_mesh_prov_link *link, uint8_t reason) #if CONFIG_BLE_MESH_PB_ADV static void link_ack(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkAckLen %u", buf->len); if (buf->len) { BT_ERR("Invalid Link ACK length %d", buf->len); @@ -2388,7 +2415,7 @@ static void link_ack(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct static void link_close(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkCloseLen %u", buf->len); if (buf->len != 1) { BT_ERR("Invalid Link Close length %d", buf->len); @@ -2511,10 +2538,12 @@ static void gen_prov_ack(struct bt_mesh_prov_link *link, BT_DBG("len %u", buf->len); if (!link->tx.buf[0]) { + BT_DBG("NullTxbuf"); return; } if (!link->tx.id) { + BT_DBG("ZeroTxId"); return; } @@ -2620,7 +2649,7 @@ void bt_mesh_provisioner_pb_adv_recv(struct net_buf_simple *buf) rx.xact_id = net_buf_simple_pull_u8(buf); rx.gpc = net_buf_simple_pull_u8(buf); - BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + BT_DBG("link_id 0x%08x xact_id %u gpc %u", rx.link_id, rx.xact_id, rx.gpc); link = find_pba_link(rx.link_id); if (link == NULL) { @@ -2783,7 +2812,7 @@ static void protocol_timeout(struct k_work *work) { struct bt_mesh_prov_link *link = work->user_data; - BT_WARN("Protocol timeout"); + BT_WARN("Protocol timeout,RmtAddr:%s", bt_hex(link->addr.val, 6)); close_link(link, CLOSE_REASON_TIMEOUT); } @@ -3112,6 +3141,7 @@ int bt_mesh_rpr_cli_pdu_recv(struct bt_mesh_prov_link *link, uint8_t type, return -EINVAL; } + BT_INFO("RprCliProvType:%d", type); prov_handlers[type].func(link, buf); return 0; } diff --git a/components/bt/esp_ble_mesh/core/proxy_client.c b/components/bt/esp_ble_mesh/core/proxy_client.c index ac05f92ffee8..710159fd2525 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.c +++ b/components/bt/esp_ble_mesh/core/proxy_client.c @@ -23,11 +23,11 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) static struct bt_mesh_proxy_server { struct bt_mesh_conn *conn; @@ -40,7 +40,8 @@ static struct bt_mesh_proxy_server { #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT uint16_t net_idx; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + uint8_t msg_type; struct k_delayed_work sar_timer; @@ -53,7 +54,7 @@ static struct { struct bt_mesh_prov_link *link; bt_mesh_addr_t addr; } waiting_conn_link[BLE_MESH_MAX_CONN]; -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ static uint8_t server_buf_data[BLE_MESH_PROXY_BUF_SIZE * BLE_MESH_MAX_CONN]; @@ -61,6 +62,8 @@ static struct bt_mesh_proxy_server *find_server(struct bt_mesh_conn *conn) { int i; + BT_DBG("FindServer, ConnHandle 0x%04x", conn->handle); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn == conn) { return &servers[i]; @@ -74,15 +77,16 @@ static void proxy_sar_timeout(struct k_work *work) { struct bt_mesh_proxy_server *server = NULL; - BT_WARN("%s", __func__); + BT_WARN("ProxySARTimeout"); server = CONTAINER_OF(work, struct bt_mesh_proxy_server, sar_timer.work); if (!server || !server->conn) { - BT_ERR("Invalid proxy server parameter"); + BT_ERR("InvalidProxyServerParam"); return; } net_buf_simple_reset(&server->buf); + bt_mesh_gattc_disconnect(server->conn); } @@ -90,6 +94,8 @@ static void proxy_sar_timeout(struct k_work *work) int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link *link, bt_mesh_addr_t *addr) { + BT_DBG("RPRSrvSetWaitingProvLink"); + for (size_t i = 0; i < ARRAY_SIZE(waiting_conn_link);i++) { if (waiting_conn_link[i].link == NULL) { waiting_conn_link[i].link = link; @@ -103,8 +109,7 @@ int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link *link, #endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT -/** - * The following callbacks are used to notify proper information +/* The following callbacks are used to notify proper information * to the application layer. */ static proxy_client_recv_adv_cb_t proxy_client_adv_recv_cb; @@ -139,6 +144,8 @@ static void filter_status(struct bt_mesh_proxy_server *server, uint8_t filter_type = 0U; uint16_t list_size = 0U; + BT_DBG("FilterStatus"); + if (buf->len != 3) { BT_ERR("Invalid Proxy Filter Status length %d", buf->len); return; @@ -152,10 +159,11 @@ static void filter_status(struct bt_mesh_proxy_server *server, list_size = net_buf_simple_pull_be16(buf); - BT_INFO("filter_type 0x%02x, list_size %d", filter_type, list_size); + BT_INFO("FilterType %u ListSize %u", filter_type, list_size); if (proxy_client_filter_status_recv_cb) { - proxy_client_filter_status_recv_cb(server - servers, rx->ctx.addr, server->net_idx, filter_type, list_size); + proxy_client_filter_status_recv_cb(server - servers, rx->ctx.addr, + server->net_idx, filter_type, list_size); } } @@ -167,7 +175,7 @@ static void recv_directed_proxy_caps_status(struct bt_mesh_proxy_server *server, uint8_t directed_proxy = net_buf_simple_pull_u8(buf); uint8_t use_directed = net_buf_simple_pull_u8(buf); - BT_INFO("Directed Proxy 0x%02x, Use Directed 0x%02x", directed_proxy, use_directed); + BT_INFO("DirectedProxy %u UseDirected %u", directed_proxy, use_directed); ARG_UNUSED(directed_proxy); ARG_UNUSED(use_directed); @@ -181,13 +189,14 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) uint8_t opcode = 0U; int err = 0; + BT_DBG("ProxyCfg"); + if (server->buf.len > 29) { BT_ERR("Too large proxy cfg pdu (len %d)", server->buf.len); return; } - err = bt_mesh_net_decode(&server->buf, BLE_MESH_NET_IF_PROXY_CFG, - &rx, &buf); + err = bt_mesh_net_decode(&server->buf, BLE_MESH_NET_IF_PROXY_CFG, &rx, &buf); if (err) { BT_ERR("Failed to decode Proxy Configuration (err %d)", err); return; @@ -201,7 +210,7 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) rx.local_match = 1U; if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx.ctx.addr, rx.ctx.recv_dst, rx.seq); return; } @@ -209,7 +218,7 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) /* Remove network headers */ net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + BT_DBG("Len %u: %s", buf.len, bt_hex(buf.data, buf.len)); if (buf.len < 3) { BT_WARN("Too short proxy configuration PDU"); @@ -243,6 +252,8 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) { + BT_DBG("ProxyCompletePDU"); + switch (server->msg_type) { #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT case BLE_MESH_PROXY_NET_PDU: @@ -265,14 +276,14 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) if (server->conn == bt_mesh_prov_node_get_link()->conn) { bt_mesh_pb_gatt_recv(server->conn, &server->buf); } else -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ { #if CONFIG_BLE_MESH_PROVISIONER bt_mesh_provisioner_pb_gatt_recv(server->conn, &server->buf); -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } break; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT && (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ default: BT_WARN("Unhandled Message Type 0x%02x", server->msg_type); break; @@ -291,6 +302,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, const uint8_t *data = buf; uint16_t srvc_uuid = 0U; + BT_DBG("ProxyRecv, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -377,7 +390,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + BT_DBG("ProxySend"); + BT_DBG("Len %u: %s", len, bt_hex(data, len)); return bt_mesh_gattc_write_no_rsp(conn, NULL, data, len); } @@ -388,13 +402,15 @@ int bt_mesh_proxy_client_segment_send(struct bt_mesh_conn *conn, uint8_t type, uint16_t mtu = 0U; int err = 0; + BT_DBG("ProxyClientSegSend"); + if (conn == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, - bt_hex(msg->data, msg->len)); + BT_DBG("ConnHandle 0x%04x Type %u", conn->handle, type); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); mtu = bt_mesh_gattc_get_mtu_info(conn); if (!mtu) { @@ -402,6 +418,8 @@ int bt_mesh_proxy_client_segment_send(struct bt_mesh_conn *conn, uint8_t type, return -ENOTCONN; } + BT_DBG("MTU %u", mtu); + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu -= 3; if (mtu > msg->len) { @@ -433,6 +451,8 @@ int bt_mesh_proxy_client_send(struct bt_mesh_conn *conn, uint8_t type, { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyClientSend, ConnHandle 0x%04x Type %u", conn->handle, type); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -450,6 +470,8 @@ static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int { struct bt_mesh_proxy_server *server = NULL; + BT_DBG("ProxyConnected, ConnHandle 0x%04x ID %d", conn->handle, id); + if (!servers[id].conn) { server = &servers[id]; } @@ -475,7 +497,7 @@ static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int break; } } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ bt_mesh_gattc_exchange_mtu(id); } @@ -484,7 +506,7 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, { struct bt_mesh_proxy_server *server = find_server(conn); - BT_DBG("conn %p, handle is %d, reason 0x%02x", conn, conn->handle, reason); + BT_DBG("ProxyDisconnected, ConnHandle 0x%04x Reason 0x%02x", conn->handle, reason); if (!server) { BT_ERR("No Proxy Server object found"); @@ -521,14 +543,15 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, proxy_client_disconnect_cb(addr, server - servers, server->net_idx, reason); } } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ k_delayed_work_cancel(&server->sar_timer); + server->conn = NULL; server->conn_type = CLI_NONE; #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ } #if CONFIG_BLE_MESH_PB_GATT && \ @@ -537,6 +560,8 @@ static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProvWriteCCC, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -555,11 +580,11 @@ static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) return bt_mesh_rpr_srv_recv_link_ack(addr->val, false); } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ #if CONFIG_BLE_MESH_PROVISIONER return bt_mesh_provisioner_pb_gatt_open(conn, addr->val); -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } return -ENOMEM; @@ -569,6 +594,8 @@ static ssize_t prov_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProvRecvNtf, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -585,6 +612,8 @@ int bt_mesh_proxy_client_prov_enable(void) { int i; + BT_DBG("ProxyClientProvEnable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { servers[i].conn_type = CLI_PROV; @@ -598,6 +627,8 @@ int bt_mesh_proxy_client_prov_disable(void) { int i; + BT_DBG("ProxyClientProvDisable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; @@ -616,6 +647,8 @@ static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyWriteCCC, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -631,11 +664,12 @@ static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) } #if CONFIG_BLE_MESH_BQB_TEST - /* notify maybe received first */ + /* Notification maybe received firstly */ if (server->conn_type == CLI_PROXY) { return 0; } -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ + return -EINVAL; } @@ -643,20 +677,23 @@ static ssize_t proxy_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyRecvNtf, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; } #if CONFIG_BLE_MESH_BQB_TEST - /* update conn type if notify received before write ccc */ + /* Update conn type if notification received before writing ccc */ if (server->conn_type == CLI_NONE) { server->conn_type = CLI_PROXY; + if (proxy_client_connect_cb) { proxy_client_connect_cb(&server->addr, server - servers, server->net_idx); } } -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ if (server->conn_type == CLI_PROXY) { return proxy_recv(conn, NULL, data, len, 0, 0); @@ -665,8 +702,7 @@ static ssize_t proxy_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t return -EINVAL; } -/** - * Currently proxy client doesn't need bt_mesh_proxy_client_gatt_enable() +/* Currently proxy client doesn't need bt_mesh_proxy_client_gatt_enable() * and bt_mesh_proxy_client_gatt_disable() functions, and once they are * used, proxy client can be enabled to parse node_id_adv and net_id_adv * in order to support proxy client role. @@ -677,6 +713,8 @@ int bt_mesh_proxy_client_gatt_enable(void) { int i; + BT_DBG("ProxyClientGattEnable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { servers[i].conn_type = CLI_PROXY; @@ -696,8 +734,9 @@ int bt_mesh_proxy_client_gatt_disable(void) { int i; - /** - * TODO: + BT_DBG("ProxyClientGattDisable"); + + /* TODO: * Once this function is invoked, proxy client shall stop handling * node_id & net_id adv packets, and if proxy connection exists, * it should be disconnected. @@ -739,6 +778,8 @@ static struct bt_mesh_subnet *bt_mesh_is_net_id_exist(const uint8_t net_id[8]) size = bt_mesh_rx_netkey_size(); + BT_DBG("IsNetIDExist, Size %u", size); + for (i = 0U; i < size; i++) { sub = bt_mesh_rx_netkey_get(i); if (sub && !memcmp(sub->keys[sub->kr_flag].net_id, net_id, 8)) { @@ -753,8 +794,11 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, int8_t rssi) { bt_mesh_proxy_adv_ctx_t ctx = {0}; + struct bt_mesh_subnet *sub = NULL; uint8_t type = 0U; + BT_DBG("ProxyClientGattAdvRecv, Rssi %d", rssi); + /* Check if connection reaches the maximum limitation */ if (bt_mesh_gattc_get_free_conn_count() == 0) { BT_INFO("BLE connections for mesh reach max limit"); @@ -763,14 +807,15 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, type = net_buf_simple_pull_u8(buf); + BT_DBG("Type %u", type); + switch (type) { - case BLE_MESH_PROXY_ADV_NET_ID: { + case BLE_MESH_PROXY_ADV_NET_ID: if (buf->len != sizeof(ctx.net_id.net_id)) { BT_WARN("Malformed Network ID"); return; } - struct bt_mesh_subnet *sub = NULL; sub = bt_mesh_is_net_id_exist(buf->data); if (!sub) { return; @@ -779,7 +824,6 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, memcpy(ctx.net_id.net_id, buf->data, buf->len); ctx.net_id.net_idx = sub->net_idx; break; - } case BLE_MESH_PROXY_ADV_NODE_ID: /* Gets node identity information. * hash = aes-ecb(identity key, 16 octets(padding + random + src)) mod 2^64, @@ -808,6 +852,8 @@ int bt_mesh_proxy_client_connect(const uint8_t addr[6], uint8_t addr_type, uint1 bt_mesh_addr_t remote_addr = {0}; int result = 0; + BT_DBG("ProxyClientConnect, NetIdx 0x%04x", net_idx); + if (!addr || addr_type > BLE_MESH_ADDR_RANDOM) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -830,13 +876,13 @@ int bt_mesh_proxy_client_disconnect(uint8_t conn_handle) { struct bt_mesh_conn *conn = NULL; + BT_DBG("ProxyClientDisconnect, ConnHandle 0x%04x", conn_handle); + if (conn_handle >= BLE_MESH_MAX_CONN) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn_handle %d", conn_handle); - conn = servers[conn_handle].conn; if (!conn) { BT_ERR("Not connected, conn handle %d", conn_handle); @@ -861,6 +907,8 @@ uint16_t bt_mesh_proxy_client_get_conn_count(void) count++; } + BT_DBG("ProxyClientGetConnCount, Count %u", count); + return count; } @@ -870,6 +918,8 @@ bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst) int err = 0; int i; + BT_DBG("ProxyClientRelay, Dst 0x%04x", dst); + for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; NET_BUF_SIMPLE_DEFINE(msg, 32); @@ -900,12 +950,15 @@ static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub, bo { NET_BUF_SIMPLE_DEFINE(buf, 28); + BT_DBG("BeaconSend, ConnHandle 0x%04x Private %u", conn->handle, private); + net_buf_simple_reserve(&buf, 1); + #if CONFIG_BLE_MESH_PRB_SRV if (private) { bt_mesh_private_beacon_create(sub, &buf); } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { bt_mesh_secure_beacon_create(sub, &buf); } @@ -919,6 +972,8 @@ bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub, bool private) int err = 0; int i; + BT_DBG("ProxyClientBeaconSend, Private %u", private); + /* NULL means we send Secure Network Beacon or Mesh Private Beacon on all subnets */ if (!sub) { #if CONFIG_BLE_MESH_NODE @@ -975,6 +1030,8 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt uint16_t alloc_len = 0U; int err = 0; + BT_DBG("SendProxyCfg, ConnHandle 0x%04x NetIdx 0x%04x", conn->handle, net_idx); + tx.sub = bt_mesh_subnet_get(net_idx); if (!tx.sub) { BT_ERR("NetKey 0x%04x not found", net_idx); @@ -1038,6 +1095,7 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt */ buf = bt_mesh_alloc_buf(1 + BLE_MESH_NET_HDR_LEN + alloc_len + 8); if (!buf) { + BT_ERR("Out of memory"); return -ENOMEM; } @@ -1072,11 +1130,10 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt #endif /* CONFIG_BLE_MESH_DF_SRV */ } - BT_DBG("len %u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy cfg message failed (err %d)", err); goto end; } @@ -1095,13 +1152,14 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, { struct bt_mesh_conn *conn = NULL; - if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || pdu->opcode > BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL) { + BT_DBG("ProxyClientCfgSend, ConnHandle 0x%04x NetIdx 0x%04x", conn_handle, net_idx); + + if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || + pdu->opcode > BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn_handle %d, net_idx 0x%04x", conn_handle, net_idx); - conn = servers[conn_handle].conn; if (!conn) { BT_ERR("Not connected, conn handle %d", conn_handle); @@ -1113,7 +1171,7 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, */ if (servers[conn_handle].net_idx != net_idx) { BT_ERR("NetKeyIndex 0x%04x mismatch, expect 0x%04x", - net_idx, servers[conn_handle].net_idx); + net_idx, servers[conn_handle].net_idx); return -EIO; } @@ -1125,16 +1183,19 @@ int bt_mesh_proxy_client_init(void) { int i; + BT_DBG("ProxyClientInit"); + /* Initialize the server receive buffers */ for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; k_delayed_work_init(&server->sar_timer, proxy_sar_timeout); + server->buf.size = BLE_MESH_PROXY_BUF_SIZE; server->buf.__buf = server_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ } bt_mesh_gattc_conn_cb_register(&conn_callbacks); @@ -1143,7 +1204,7 @@ int bt_mesh_proxy_client_init(void) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN && CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ return 0; } @@ -1153,6 +1214,8 @@ int bt_mesh_proxy_client_deinit(void) { int i; + BT_DBG("ProxyClientDeinit"); + /* Initialize the server receive buffers */ for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index 062bb9b247fe..6021ca7f8fb7 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -24,7 +24,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER @@ -36,8 +36,8 @@ _Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CON #endif #if CONFIG_BLE_MESH_USE_BLE_50 -static uint8_t proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; -#endif +static uint8_t proxy_adv_inst = BLE_MESH_ADV_INST_UNUSED; +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) @@ -58,7 +58,7 @@ static const struct bt_mesh_adv_param slow_adv_param = { .interval_max = BLE_MESH_GAP_ADV_SLOW_INT_MAX, .channel_map = BLE_MESH_ADV_CHAN_DEFAULT, #if CONFIG_BLE_MESH_USE_BLE_50 - .primary_phy = BLE_MESH_ADV_PHY_1M, + .primary_phy = BLE_MESH_ADV_PHY_1M, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, @@ -73,7 +73,7 @@ static const struct bt_mesh_adv_param fast_adv_param = { .interval_max = BLE_MESH_GAP_ADV_FAST_INT_MAX_0, .channel_map = BLE_MESH_ADV_CHAN_DEFAULT, #if CONFIG_BLE_MESH_USE_BLE_50 - .primary_phy = BLE_MESH_ADV_PHY_1M, + .primary_phy = BLE_MESH_ADV_PHY_1M, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, @@ -87,19 +87,19 @@ static bool proxy_adv_enabled; #if CONFIG_BLE_MESH_GATT_PROXY_SERVER static void proxy_send_beacons(struct k_work *work); static uint16_t proxy_ccc_val; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT static uint16_t prov_ccc_val; static bool prov_fast_adv; static uint32_t prov_start_time; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ static struct bt_mesh_proxy_client clients[BLE_MESH_MAX_CONN] = { [0 ... (BLE_MESH_MAX_CONN - 1)] = { #if CONFIG_BLE_MESH_PROXY_PRIVACY .proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED, -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ }, }; @@ -116,6 +116,8 @@ static char device_name[DEVICE_NAME_SIZE + 1]; struct bt_mesh_proxy_client *bt_mesh_proxy_server_get_client(uint8_t index) { + BT_DBG("ProxyServerGetClient, Index %u", index); + return &clients[0]; } @@ -126,11 +128,15 @@ uint8_t bt_mesh_proxy_server_get_client_count(void) int bt_mesh_set_device_name(const char *name) { + BT_DBG("SetDeviceName"); + if (!name) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + BT_DBG("Name %s", name); + if (strlen(name) > DEVICE_NAME_SIZE) { BT_ERR("Too long device name (len %d)", strlen(name)); return -EINVAL; @@ -144,6 +150,8 @@ int bt_mesh_set_device_name(const char *name) const char *bt_mesh_get_device_name(void) { + BT_DBG("GetDeviceName %s", device_name); + return device_name; } @@ -151,6 +159,8 @@ static struct bt_mesh_proxy_client *find_client(struct bt_mesh_conn *conn) { int i; + BT_DBG("FindClient, ConnHandle 0x%04x", conn->handle); + for (i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn == conn) { return &clients[i]; @@ -164,7 +174,7 @@ static void proxy_sar_timeout(struct k_work *work) { struct bt_mesh_proxy_client *client = NULL; - BT_WARN("Proxy SAR timeout"); + BT_WARN("ProxySARTimeout"); client = CONTAINER_OF(work, struct bt_mesh_proxy_client, sar_timer.work); if (!client || !client->conn) { @@ -178,12 +188,13 @@ static void proxy_sar_timeout(struct k_work *work) void bt_mesh_proxy_server_adv_flag_set(bool enable) { + BT_DBG("ProxyServerAdvFlagSet, Enable %u/%u", proxy_adv_enabled, enable); + proxy_adv_enabled = enable; } #if CONFIG_BLE_MESH_GATT_PROXY_SERVER -/** - * The following callbacks are used to notify proper information +/* The following callbacks are used to notify proper information * to the application layer. */ static proxy_server_connect_cb_t proxy_server_connect_cb; @@ -204,6 +215,8 @@ static int next_idx; bool bt_mesh_proxy_server_find_client_by_addr(uint16_t addr) { + BT_DBG("ProxyServerFindClient, Addr 0x%04x", addr); + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn) { for (size_t j = 0; j < ARRAY_SIZE(clients[i].filter); j++) { @@ -231,6 +244,8 @@ uint8_t bt_mesh_proxy_server_get_all_client_type(void) } } + BT_DBG("ProxyServerGetAllClientType, type 0x%02x", client_type); + return client_type; } @@ -239,13 +254,16 @@ static int filter_set(struct bt_mesh_proxy_client *client, { uint8_t type = 0U; + BT_INFO("FilterSet"); + if (buf->len < 1) { BT_WARN("Too short Filter Set message"); return -EINVAL; } type = net_buf_simple_pull_u8(buf); - BT_INFO("Set filter type 0x%02x", type); + + BT_INFO("Type 0x%02x", type); switch (type) { case 0x00: @@ -276,7 +294,7 @@ static void filter_add(struct bt_mesh_proxy_client *client, * is the element address of Proxy Client. */ - BT_DBG("addr 0x%04x", addr); + BT_DBG("FilterAdd, Addr 0x%04x ProxyClient %u", addr, proxy_client); if (addr == BLE_MESH_ADDR_UNASSIGNED) { return; @@ -306,14 +324,14 @@ static void filter_add(struct bt_mesh_proxy_client *client, } } - BT_WARN("Proxy filter is full!"); + BT_WARN("ProxyFilterFull"); } static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) { int i; - BT_DBG("addr 0x%04x", addr); + BT_DBG("FilterRemove, Addr 0x%04x", addr); if (addr == BLE_MESH_ADDR_UNASSIGNED) { return; @@ -341,6 +359,8 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, uint16_t filter_size = 0U; int i, err = 0; + BT_DBG("SetFilterStatus"); + /* Configuration messages always have dst unassigned */ tx.ctx->addr = BLE_MESH_ADDR_UNASSIGNED; tx.ctx->send_cred = BLE_MESH_FLOODING_CRED, @@ -364,11 +384,10 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, net_buf_simple_add_be16(buf, filter_size); - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy filter status failed (err %d)", err); return; } @@ -385,13 +404,14 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) uint8_t opcode = 0U; int err = 0; + BT_DBG("ProxyCfg"); + if (client->buf.len > 29) { BT_ERR("Too large proxy cfg pdu (len %d)", client->buf.len); return; } - err = bt_mesh_net_decode(&client->buf, BLE_MESH_NET_IF_PROXY_CFG, - &rx, &buf); + err = bt_mesh_net_decode(&client->buf, BLE_MESH_NET_IF_PROXY_CFG, &rx, &buf); if (err) { BT_ERR("Failed to decode Proxy Configuration (err %d)", err); return; @@ -400,7 +420,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) rx.local_match = 1U; if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx.ctx.addr, rx.ctx.recv_dst, rx.seq); return; } @@ -408,7 +428,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) /* Remove network headers */ net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + BT_DBG("Len %u: %s", buf.len, bt_hex(buf.data, buf.len)); if (buf.len < 1) { BT_WARN("Too short proxy configuration PDU"); @@ -464,6 +484,8 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne { NET_BUF_SIMPLE_DEFINE(buf, 28); + BT_DBG("BeaconSend"); + net_buf_simple_reserve(&buf, 1); #if CONFIG_BLE_MESH_PROXY_PRIVACY @@ -475,7 +497,7 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne bt_mesh_private_beacon_create(sub, &buf); } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ { bt_mesh_secure_beacon_create(sub, &buf); } @@ -485,10 +507,12 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne static void proxy_send_beacons(struct k_work *work) { - struct bt_mesh_proxy_client *client = NULL; + struct bt_mesh_proxy_client *client = CONTAINER_OF(work, + struct bt_mesh_proxy_client, + send_beacons);; int i; - client = CONTAINER_OF(work, struct bt_mesh_proxy_client, send_beacons); + BT_DBG("ProxySendBeacons"); /* Upon connection, the Proxy Server shall evaluate Proxy Privacy parameter * for the connection and the Proxy Server shall retain the value of the @@ -523,7 +547,7 @@ static void proxy_send_beacons(struct k_work *work) } else if (sub->proxy_privacy == BLE_MESH_PROXY_PRIVACY_ENABLED) { #if CONFIG_BLE_MESH_PRB_SRV /* TODO: Send Mesh Private Beacon */ -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } } #endif @@ -534,6 +558,8 @@ void bt_mesh_proxy_server_beacon_send(struct bt_mesh_subnet *sub) { int i; + BT_DBG("ProxyServerBeaconSend, Sub %p", sub); + if (!sub) { /* NULL means we send on all subnets */ for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { @@ -559,10 +585,14 @@ void bt_mesh_proxy_server_identity_start(struct bt_mesh_subnet *sub) /* Prioritize the recently enabled subnet */ next_idx = sub - bt_mesh.sub; + + BT_DBG("ProxyServerIdentityStart, NextIdx %d", next_idx); } void bt_mesh_proxy_server_identity_stop(struct bt_mesh_subnet *sub) { + BT_DBG("ProxyServerIdentityStop"); + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; sub->node_id_start = 0U; } @@ -571,7 +601,10 @@ int bt_mesh_proxy_identity_enable(void) { int i, count = 0; + BT_DBG("ProxyIdentityEnable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -587,9 +620,12 @@ int bt_mesh_proxy_identity_enable(void) } bt_mesh_proxy_server_identity_start(sub); + count++; } + BT_DBG("SubCount %u", count); + if (count) { bt_mesh_adv_update(); } @@ -605,16 +641,22 @@ void bt_mesh_proxy_server_private_identity_start(struct bt_mesh_subnet *sub) /* Prioritize the recently enabled subnet */ next_idx = sub - bt_mesh.sub; + + BT_DBG("ProxyServerPrivateIdentityStart, NextIdx %d", next_idx); } void bt_mesh_proxy_server_private_identity_stop(struct bt_mesh_subnet *sub) { + BT_DBG("ProxyServerPrivateIdentityStop"); + sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED; sub->node_id_start = 0U; } bool bt_mesh_proxy_server_is_node_id_enable(void) { + BT_DBG("ProxyServerIsNodeIDEnable"); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { /* If the Node Identity state of the node for any subnet * is 0x01 (i.e. running), return true. @@ -634,22 +676,27 @@ static bool is_exist_private_node_id_enable(void) { for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { /* If the value of the Node Identity state of the node - * for any subnet is 0x01,If exist return true. + * for any subnet is 0x01, if exist return true. */ struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; if (sub->net_idx != BLE_MESH_KEY_UNUSED && sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { + BT_DBG("PrivateNodeIDExist, NetIdx 0x%04x", sub->net_idx); return true; } } + BT_DBG("PrivateNodeIDNotExist"); return false; } int bt_mesh_proxy_private_identity_disable(void) { + BT_DBG("ProxyPrivateIdentityDisable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -675,7 +722,10 @@ int bt_mesh_proxy_private_identity_enable(void) { int count = 0; + BT_DBG("ProxyPrivateIdentityEnable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -691,9 +741,12 @@ int bt_mesh_proxy_private_identity_enable(void) } bt_mesh_proxy_server_private_identity_start(sub); + count++; } + BT_DBG("SubCount %u", count); + if (count) { bt_mesh_adv_update(); } @@ -701,10 +754,12 @@ int bt_mesh_proxy_private_identity_enable(void) return 0; } #endif /* CONFIG_BLE_MESH_PRB_SRV */ -#endif /* GATT_PROXY */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) { + BT_DBG("ProxyCompletePDU"); + switch (client->msg_type) { #if CONFIG_BLE_MESH_GATT_PROXY_SERVER case BLE_MESH_PROXY_NET_PDU: @@ -719,13 +774,13 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) BT_DBG("Mesh Configuration PDU"); proxy_cfg(client); break; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT case BLE_MESH_PROXY_PROV: BT_DBG("Mesh Provisioning PDU"); bt_mesh_pb_gatt_recv(client->conn, &client->buf); break; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ default: BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); break; @@ -736,27 +791,35 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (client->msg_type < BLE_MESH_PROXY_PROV && client->proxy_msg_recv == false) { - client->proxy_msg_recv = true; - /** - * @Spec: P626 - * When a new connection is established between a Proxy Client and the Directed Proxy Server, and the - * first message received from the Proxy Client is a successfully processed DIRECTED_PROXY_CONTROL - * message, then the Directed Proxy Server shall set the Proxy_Client_Type parameter to Directed Proxy Client, - * shall set the Use_Directed parameter to Disable for all subnets known to the Directed Proxy Server - * except the subnet identified by the received message; - * otherwise, the Directed Proxy Server shall set the Proxy_Client_Type parameter to Proxy Client. + /* @Spec: P626 + * When a new connection is established between a Proxy Client and + * the Directed Proxy Server, and the first message received from + * the Proxy Client is a successfully processed DIRECTED_PROXY_CONTROL + * message, then the Directed Proxy Server shall set the Proxy_Client_Type + * parameter to Directed Proxy Client, shall set the Use_Directed + * parameter to Disable for all subnets known to the Directed Proxy + * Server except the subnet identified by the received message; + * otherwise, the Directed Proxy Server shall set the Proxy_Client_Type + * parameter to Proxy Client. * - * If the first message received is DIRECTED_PROXY_CONTROL, proxy_client_type will be set to Directed Proxy Client, - * But if device didn't receive DIRECTED_PROXY_CONTROL message and all received is normal proxy message, That - * client type will be always in UNSET state, because we set client type in handle function of DIRECTED_PROXY_CONTROL. + * If the first message received is DIRECTED_PROXY_CONTROL, proxy_client_type + * will be set to Directed Proxy Client. + * But if device didn't receive DIRECTED_PROXY_CONTROL message and all + * received is normal proxy message, That client type will be always in + * UNSET state, because we set client type in handle function of + * DIRECTED_PROXY_CONTROL. * * So the flowing code was used to avoid that situation. - */ + */ + client->proxy_msg_recv = true; + + BT_DBG("ProxyClientTypeUpdate"); + if (client->proxy_client_type == BLE_MESH_PROXY_CLI_TYPE_UNSET) { client->proxy_client_type = BLE_MESH_PROXY_CLI_TYPE_PROXY_CLIENT; } } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ } #define ATTR_IS_PROV(attr) (attr->user_data != NULL) @@ -768,6 +831,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = find_client(conn); const uint8_t *data = buf; + BT_DBG("ProxyRecv"); + if (!client) { BT_ERR("No Proxy Client found"); return -ENOTCONN; @@ -853,7 +918,7 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) struct bt_mesh_proxy_client *client = NULL; int i; - BT_DBG("conn %p err 0x%02x", conn, err); + BT_DBG("ProxyConnected, ConnHandle 0x%04x Err 0x%02x", conn->handle, err); if (gatt_svc == MESH_GATT_PROV && conn_count == 1) { BT_WARN("Only one prov connection could exists"); @@ -866,7 +931,7 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) /* Since we use ADV_OPT_ONE_TIME */ #if !CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_proxy_server_adv_flag_set(false); -#endif +#endif /* !CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX /* Before re-enabling advertising, stop advertising @@ -874,7 +939,9 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) * Network Identity type. */ bt_mesh_proxy_server_stop_solic_adv_priv_net_id(); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + + BT_DBG("ConnCount %u vs. %u", conn_count, BLE_MESH_MAX_CONN); /* Try to re-enable advertising in case it's possible */ if (conn_count < BLE_MESH_MAX_CONN) { @@ -895,13 +962,15 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) client->conn = bt_mesh_conn_ref(conn); client->filter_type = SRV_NONE; + #if CONFIG_BLE_MESH_GATT_PROXY_SERVER (void)memset(client->filter, 0, sizeof(client->filter)); if (proxy_server_connect_cb) { proxy_server_connect_cb(conn->handle); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + net_buf_simple_reset(&client->buf); } @@ -909,7 +978,8 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) { int i; - BT_DBG("conn %p reason 0x%02x", conn, reason); + BT_DBG("ProxyDisconnected, ConnHandle 0x%04x Count %u Reason 0x%02x", + conn->handle, conn_count, reason); conn_count--; @@ -921,7 +991,8 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) if (proxy_server_disconnect_cb) { proxy_server_disconnect_cb(conn->handle, reason); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && client->filter_type == SRV_PROV) { bt_mesh_pb_gatt_close(conn, reason); @@ -929,11 +1000,11 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) #if CONFIG_BLE_MESH_PROXY_PRIVACY client->proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV k_delayed_work_cancel(&rand_upd_timer); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ k_delayed_work_cancel(&client->sar_timer); bt_mesh_conn_unref(client->conn); @@ -953,13 +1024,15 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) if (bt_mesh_directed_proxy_server_update_dep_node(NULL, &clients[i], 0)) { BT_ERR("Proxy disconnected, failed to update dependent node"); } -#endif /* CONFIG_BLE_MESH_DF_SRV */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_DF_SRV */ } struct net_buf_simple *bt_mesh_proxy_server_get_buf(void) { struct net_buf_simple *buf = &clients[0].buf; + BT_DBG("ProxyServerGetBuf"); + net_buf_simple_reset(buf); return buf; @@ -974,9 +1047,11 @@ static ssize_t prov_ccc_write(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = NULL; uint16_t *value = attr->user_data; - BT_DBG("len %u: %s", len, bt_hex(buf, len)); + BT_DBG("ProvCCCWrite"); + BT_DBG("Len %u: %s", len, bt_hex(buf, len)); if (len != sizeof(*value)) { + BT_WARN("MismatchLen %u != %u", len, sizeof(*value)); return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); } @@ -1007,6 +1082,8 @@ static ssize_t prov_ccc_read(struct bt_mesh_conn *conn, { uint16_t *value = attr->user_data; + BT_DBG("ProvCCCRead, Len %u", len); + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, sizeof(*value)); } @@ -1036,6 +1113,8 @@ int bt_mesh_proxy_server_prov_enable(void) { int i; + BT_DBG("ProxyServerProvEnable"); + if (gatt_svc == MESH_GATT_PROV) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1063,6 +1142,8 @@ int bt_mesh_proxy_server_prov_disable(bool disconnect) { int i; + BT_DBG("ProxyServerProvDisable, Disconnect %u", disconnect); + if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1106,9 +1187,11 @@ static ssize_t proxy_ccc_write(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = NULL; uint16_t value = 0U; - BT_DBG("len %u: %s", len, bt_hex(buf, len)); + BT_DBG("ProxyCCCWrite"); + BT_DBG("Len %u: %s", len, bt_hex(buf, len)); if (len != sizeof(value)) { + BT_WARN("MismatchLen %u != %u", len, sizeof(value)); return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); } @@ -1163,6 +1246,8 @@ static ssize_t proxy_ccc_read(struct bt_mesh_conn *conn, { uint16_t *value = attr->user_data; + BT_DBG("ProxyCCCRead, Len %u", len); + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, sizeof(*value)); } @@ -1192,6 +1277,8 @@ int bt_mesh_proxy_server_gatt_enable(void) { int i; + BT_DBG("ProxyServerGattEnable"); + if (gatt_svc == MESH_GATT_PROXY) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1218,6 +1305,8 @@ void bt_mesh_proxy_server_gatt_disconnect(void) { int i; + BT_DBG("ProxyServerGattDisconnect"); + for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1231,6 +1320,8 @@ void bt_mesh_proxy_server_gatt_disconnect(void) int bt_mesh_proxy_server_gatt_disable(void) { + BT_DBG("ProxyServerGattDisable"); + if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1255,7 +1346,7 @@ void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr) struct bt_mesh_proxy_client, buf); - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + BT_DBG("ProxyServerAddrAdd, Type %u Addr 0x%04x", client->filter_type, addr); if (client->filter_type == SRV_WHITELIST) { filter_add(client, addr, true); @@ -1264,16 +1355,16 @@ void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr) } } -static bool client_filter_match(struct bt_mesh_proxy_client *client, - uint16_t addr) +static bool client_filter_match(struct bt_mesh_proxy_client *client, uint16_t addr) { int i; - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + BT_DBG("ClientFilterMatch, Type %u Addr 0x%04x", client->filter_type, addr); if (client->filter_type == SRV_BLACKLIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { if (client->filter[i].addr == addr) { + BT_DBG("InBlackList"); return false; } } @@ -1282,12 +1373,14 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, } if (addr == BLE_MESH_ADDR_ALL_NODES) { + BT_DBG("AllNodes"); return true; } if (client->filter_type == SRV_WHITELIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { if (client->filter[i].addr == addr) { + BT_DBG("InWhiteList"); return true; } } @@ -1301,7 +1394,7 @@ bool bt_mesh_proxy_server_relay(struct net_buf_simple *buf, uint16_t dst) bool relayed = false; int i; - BT_DBG("%u bytes to dst 0x%04x", buf->len, dst); + BT_DBG("ProxyServerRelay, Len %u Dst 0x%04x", buf->len, dst); for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1327,24 +1420,24 @@ bool bt_mesh_proxy_server_relay(struct net_buf_simple *buf, uint16_t dst) return relayed; } - #endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + BT_DBG("ProxySend"); + BT_DBG("Len %u: %s", len, bt_hex(data, len)); #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (gatt_svc == MESH_GATT_PROXY) { return bt_mesh_gatts_notify(conn, &proxy_attrs[4], data, len); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT if (gatt_svc == MESH_GATT_PROV) { return bt_mesh_gatts_notify(conn, &prov_attrs[4], data, len); } -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ return 0; } @@ -1354,11 +1447,15 @@ int bt_mesh_proxy_server_segment_send(struct bt_mesh_conn *conn, uint8_t type, { uint16_t mtu = 0U; - BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, - bt_hex(msg->data, msg->len)); + BT_DBG("ProxyServerSegSend"); + BT_DBG("ConnHandle 0x%04x Type %u", conn->handle, type); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu = bt_mesh_gatt_get_mtu(conn) - 3; + + BT_DBG("MTU %u", mtu); + if (mtu > msg->len) { net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_COMP, type)); return proxy_send(conn, msg->data, msg->len); @@ -1388,6 +1485,8 @@ int bt_mesh_proxy_server_send(struct bt_mesh_conn *conn, uint8_t type, { struct bt_mesh_proxy_client *client = find_client(conn); + BT_DBG("ProxyServerSend, Type 0x%02x", type); + if (!client) { BT_ERR("No Proxy Client found"); return -ENOTCONN; @@ -1409,10 +1508,9 @@ static const struct bt_mesh_adv_data prov_ad[] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x27, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), }; -#endif /* PB_GATT */ +#endif /* CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER - #define NET_ID_LEN 11 #define NODE_ID_LEN 19 #define PRIVATE_NET_ID_LEN 19 @@ -1460,6 +1558,9 @@ static size_t gatt_proxy_adv_create(struct bt_mesh_adv_data *proxy_sd) /* One octet for Length, and another octet for AD type */ size_t sd_space = 29; + BT_DBG("GattProxyAdvCreate"); + BT_DBG("Name %u: %s", name_len, name); + if (name_len > sd_space) { proxy_sd->type = BLE_MESH_DATA_NAME_SHORTENED; proxy_sd->data_len = sd_space; @@ -1480,6 +1581,8 @@ static int node_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("NodeIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NODE_ID; err = bt_mesh_rand(proxy_svc_data + 11, 8); @@ -1502,10 +1605,10 @@ static int node_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, node_id_ad, ARRAY_SIZE(node_id_ad), &proxy_sd, proxy_sd_len); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, node_id_ad, ARRAY_SIZE(node_id_ad), &proxy_sd, proxy_sd_len); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise using Node ID (err %d)", err); return err; @@ -1522,10 +1625,10 @@ static int net_id_adv(struct bt_mesh_subnet *sub) size_t proxy_sd_len = 0U; int err = 0; - proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NET_ID; + BT_DBG("NetIDAdv, NetIdx 0x%04x", sub->net_idx); + BT_DBG("NetId %s", bt_hex(sub->keys[sub->kr_flag].net_id, 8)); - BT_DBG("Advertising with NetId %s", - bt_hex(sub->keys[sub->kr_flag].net_id, 8)); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NET_ID; memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8); proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); @@ -1533,10 +1636,10 @@ static int net_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_ext_adv_start(proxy_adv_inst, &slow_adv_param, net_id_ad, ARRAY_SIZE(net_id_ad), &proxy_sd, proxy_sd_len); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&slow_adv_param, net_id_ad, ARRAY_SIZE(net_id_ad), &proxy_sd, proxy_sd_len); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise using Network ID (err %d)", err); return err; @@ -1550,11 +1653,15 @@ static int net_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_PRB_SRV void bt_mesh_proxy_server_update_net_id_rand(void) { + BT_DBG("ProxyServerUpdateNetIDRand"); + k_delayed_work_submit(&rand_upd_timer, RAND_UPDATE_INTERVAL); } void bt_mesh_proxy_server_update_net_id_rand_stop(void) { + BT_DBG("ProxyServerUpdateNetIDRandStop"); + k_delayed_work_cancel(&rand_upd_timer); } @@ -1562,6 +1669,8 @@ static void random_update_timeout(struct k_work *work) { int err = 0; + BT_DBG("RandomUpdateTimeout"); + err = bt_mesh_rand(net_id_random, 8); if (err) { BT_ERR("Generate random value failed"); @@ -1578,6 +1687,8 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("PrivateNodeIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NODE_ID; err = bt_mesh_rand(proxy_svc_data + 11, 8); @@ -1598,8 +1709,13 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) memcpy(proxy_svc_data + 3, tmp + 8, 8); proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); +#if CONFIG_BLE_MESH_USE_BLE_50 + err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, private_node_id_ad, + ARRAY_SIZE(private_node_id_ad), &proxy_sd, proxy_sd_len); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, private_node_id_ad, ARRAY_SIZE(private_node_id_ad), &proxy_sd, proxy_sd_len); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise with Private Node ID (err %d)", err); return err; @@ -1611,8 +1727,7 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) } #endif /* CONFIG_BLE_MESH_PRB_SRV */ -#if (CONFIG_BLE_MESH_PRB_SRV || \ - CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) +#if (CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) static int private_net_id_adv(struct bt_mesh_subnet *sub) { struct bt_mesh_adv_data proxy_sd = {0}; @@ -1620,6 +1735,8 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("PrivateNetIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NET_ID; /* TODO: @@ -1642,8 +1759,13 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); +#if CONFIG_BLE_MESH_USE_BLE_50 + err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, private_net_id_ad, + ARRAY_SIZE(private_net_id_ad), &proxy_sd, proxy_sd_len); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, private_net_id_ad, ARRAY_SIZE(private_net_id_ad), &proxy_sd, proxy_sd_len); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise with Private Net ID (err %d)", err); return err; @@ -1653,11 +1775,12 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) return 0; } -#endif /* (CONFIG_BLE_MESH_PRB_SRV || \ - CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) */ +#endif /* (CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) */ static bool advertise_subnet(struct bt_mesh_subnet *sub) { + BT_DBG("AdvSubnet, NetIdx 0x%04x", sub->net_idx); + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { return false; } @@ -1667,7 +1790,7 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_PRB_SRV || sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ); } @@ -1676,10 +1799,13 @@ static struct bt_mesh_subnet *next_sub(void) struct bt_mesh_subnet *sub = NULL; int i; + BT_DBG("NextSub"); + for (i = next_idx; i < ARRAY_SIZE(bt_mesh.sub); i++) { sub = &bt_mesh.sub[i]; if (advertise_subnet(sub)) { next_idx = (i + 1) % ARRAY_SIZE(bt_mesh.sub); + BT_DBG("NextIdx %d", next_idx); return sub; } } @@ -1691,6 +1817,7 @@ static struct bt_mesh_subnet *next_sub(void) sub = &bt_mesh.sub[i]; if (advertise_subnet(sub)) { next_idx = (i + 1) % ARRAY_SIZE(bt_mesh.sub); + BT_DBG("NextIdx %d", next_idx); return sub; } } @@ -1710,6 +1837,8 @@ static int sub_count(void) } } + BT_DBG("SubCount %ld", count); + return count; } @@ -1719,6 +1848,8 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) int subnet_count = 0; uint32_t active = 0U; + BT_DBG("GattProxyAdvertise"); + if (conn_count == BLE_MESH_MAX_CONN) { BT_WARN("Connectable advertising deferred (max connections %d)", conn_count); return remaining; @@ -1729,6 +1860,8 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) return remaining; } + BT_DBG("NetIdx 0x%04x NodeID %u", sub->net_idx, sub->node_id); + if (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { active = k_uptime_get_32() - sub->node_id_start; @@ -1741,6 +1874,7 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) BT_DBG("Node ID stopped"); } } + #if CONFIG_BLE_MESH_PRB_SRV else if (sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { active = k_uptime_get_32() - sub->node_id_start; @@ -1759,7 +1893,7 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) if (sub->node_id == BLE_MESH_NODE_IDENTITY_STOPPED #if CONFIG_BLE_MESH_PRB_SRV && sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ) { /* advertising node identity forever */ if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { @@ -1769,11 +1903,10 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) else if (bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED) { private_net_id_adv(sub); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } subnet_count = sub_count(); - BT_DBG("sub_count %u", subnet_count); if (subnet_count > 1) { int32_t max_timeout = 0; @@ -1786,16 +1919,18 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); max_timeout = MAX(max_timeout, K_SECONDS(1)); + BT_DBG("Remaining %d MaxTimeout %d", remaining, max_timeout); + if (remaining > max_timeout || remaining < 0) { remaining = max_timeout; } } - BT_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); + BT_DBG("Remaining %d NetIdx 0x%04x", remaining, sub->net_idx); return remaining; } -#endif /* GATT_PROXY */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) @@ -1805,6 +1940,8 @@ static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) size_t prov_sd_len = 0U; size_t sd_space = 31U; + BT_DBG("GattProvAdvCreate"); + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return 0; @@ -1855,41 +1992,51 @@ static int32_t solic_adv_private_net_id(void) struct bt_mesh_subnet *sub = NULL; int32_t remaining = 0; + BT_DBG("SolicAdvPrivateNetID"); + remaining = bt_mesh_proxy_server_get_solic_adv_remaining(); if (remaining == 0) { + BT_DBG("RemainingZero"); return 0; } net_idx = bt_mesh_proxy_server_get_solic_adv_net_idx(); if (net_idx == BLE_MESH_KEY_UNUSED) { + BT_DBG("UnusedNetIdx"); return 0; } sub = bt_mesh_subnet_get(net_idx); if (sub == NULL) { + BT_DBG("NoSub"); return 0; } private_net_id_adv(sub); + return remaining; } #endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ int32_t bt_mesh_proxy_server_adv_start(void) { - BT_DBG("proxy server start"); + BT_DBG("ProxyServerAdvStart"); if (gatt_svc == MESH_GATT_NONE) { + BT_DBG("GattSvcNone"); return K_FOREVER; } #if CONFIG_BLE_MESH_USE_BLE_50 - if (proxy_adv_inst == BLE_MESH_ADV_INS_UNUSED) { + if (proxy_adv_inst == BLE_MESH_ADV_INST_UNUSED) { + BT_DBG("ProxyAdvInstUnused"); return K_FOREVER; } -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_PB_GATT + BT_DBG("ProvFastAdv %u", prov_fast_adv); + if (prov_fast_adv) { prov_start_time = k_uptime_get_32(); } @@ -1899,6 +2046,8 @@ int32_t bt_mesh_proxy_server_adv_start(void) struct bt_mesh_adv_data prov_sd[2]; size_t prov_sd_len; + BT_DBG("NotProvisioned"); + if (k_uptime_get_32() - prov_start_time < K_SECONDS(60)) { param = &fast_adv_param; } else { @@ -1914,7 +2063,6 @@ int32_t bt_mesh_proxy_server_adv_start(void) if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), prov_sd, prov_sd_len) == 0) { #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ - bt_mesh_proxy_server_adv_flag_set(true); /* Advertise 60 seconds using fast interval */ @@ -1924,7 +2072,7 @@ int32_t bt_mesh_proxy_server_adv_start(void) } } } -#endif /* PB_GATT */ +#endif /* CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (bt_mesh_is_provisioned()) { @@ -1953,26 +2101,29 @@ int bt_mesh_proxy_server_adv_stop(void) { int err = 0; + BT_DBG("ProxyServerAdvStop, Enabled %u", proxy_adv_enabled); + if (!proxy_adv_enabled) { return -EALREADY; } #if CONFIG_BLE_MESH_USE_BLE_50 - if (proxy_adv_inst == BLE_MESH_ADV_INS_UNUSED) { + if (proxy_adv_inst == BLE_MESH_ADV_INST_UNUSED) { BT_ERR("Proxy adv inst is not initialized!"); return -EINVAL; } err = bt_le_ext_adv_stop(proxy_adv_inst); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_stop(); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_ERR("Failed to stop advertising (err %d)", err); return -EINVAL; } bt_mesh_proxy_server_adv_flag_set(false); + return 0; } @@ -1985,21 +2136,23 @@ int bt_mesh_proxy_server_init(void) { int i; + BT_DBG("ProxyServerInit"); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV proxy_adv_inst = CONFIG_BLE_MESH_PROXY_ADV_INST_ID; #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ proxy_adv_inst = CONFIG_BLE_MESH_ADV_INST_ID; -#endif -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_register(&proxy_svc); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_register(&prov_svc); -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ /* Initialize the client receive buffers */ for (i = 0; i < ARRAY_SIZE(clients); i++) { @@ -2007,9 +2160,10 @@ int bt_mesh_proxy_server_init(void) client->buf.size = BLE_MESH_PROXY_BUF_SIZE; client->buf.__buf = client_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER k_delayed_work_init(&client->send_beacons, proxy_send_beacons); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ k_delayed_work_init(&client->sar_timer, proxy_sar_timeout); } @@ -2018,11 +2172,12 @@ int bt_mesh_proxy_server_init(void) BT_ERR("Failed to create a random update timer"); return -EIO; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_gatts_conn_cb_register(&conn_callbacks); strncpy(device_name, "ESP-BLE-MESH", DEVICE_NAME_SIZE); + return bt_mesh_gatts_set_local_device_name(device_name); } @@ -2031,9 +2186,11 @@ int bt_mesh_proxy_server_deinit(void) { int i; + BT_DBG("ProxyServerDeinit"); + #if CONFIG_BLE_MESH_USE_BLE_50 - proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; -#endif + proxy_adv_inst = BLE_MESH_ADV_INST_UNUSED; +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ bt_mesh_proxy_server_adv_flag_set(false); gatt_svc = MESH_GATT_NONE; @@ -2041,24 +2198,26 @@ int bt_mesh_proxy_server_deinit(void) #if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_deregister(&proxy_svc); next_idx = 0; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_deregister(&prov_svc); -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER k_delayed_work_free(&client->send_beacons); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ k_delayed_work_free(&client->sar_timer); + memset(client, 0, sizeof(struct bt_mesh_proxy_client)); } #if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV k_delayed_work_free(&rand_upd_timer); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ memset(client_buf_data, 0, sizeof(client_buf_data)); memset(device_name, 0, sizeof(device_name)); diff --git a/components/bt/esp_ble_mesh/core/proxy_server.h b/components/bt/esp_ble_mesh/core/proxy_server.h index fc4041f8774e..d16d0d390f06 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.h +++ b/components/bt/esp_ble_mesh/core/proxy_server.h @@ -58,7 +58,7 @@ struct bt_mesh_proxy_client { #if CONFIG_BLE_MESH_PROXY_PRIVACY uint8_t proxy_privacy; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ #endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ struct k_delayed_work sar_timer; diff --git a/components/bt/esp_ble_mesh/core/rpl.c b/components/bt/esp_ble_mesh/core/rpl.c index 4e3e4c91cbce..43f4a4afdaa1 100644 --- a/components/bt/esp_ble_mesh/core/rpl.c +++ b/components/bt/esp_ble_mesh/core/rpl.c @@ -17,6 +17,9 @@ void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) { + BT_DBG("UpdateRPL, Src 0x%04x Seq 0x%06x OldIV %u", + rx->ctx.addr, rx->seq, rx->old_iv); + rpl->src = rx->ctx.addr; rpl->seq = rx->seq; rpl->old_iv = rx->old_iv; @@ -33,9 +36,16 @@ void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) */ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { + BT_DBG("%s, Src 0x%04x Seq %lu OldIV %u", + match ? "RPLOnlyCheck" : "RPLCheckAndStore", + rx->ctx.addr, rx->seq, rx->old_iv); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("RPL%u, Src 0x%04x Seq %lu OldIV %u", + i, rpl->src, rpl->seq, rpl->old_iv); + /* Empty slot */ if (rpl->src == BLE_MESH_ADDR_UNASSIGNED) { if (match) { @@ -50,6 +60,7 @@ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl ** /* Existing slot for given address */ if (rpl->src == rx->ctx.addr) { if (rx->old_iv && !rpl->old_iv) { + BT_DBG("DueToOldIV"); return true; } @@ -66,25 +77,30 @@ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl ** #if CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG rx->replay_msg = 1; -#endif +#endif /* CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG */ + BT_DBG("DueToSeq"); return true; } } - BT_ERR("RPL is full!"); + BT_ERR("RPLFull"); return true; } bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { + BT_DBG("RPLCheck"); + /* Don't bother checking messages from ourselves */ if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + BT_DBG("LocalNetIf"); return false; } /* The RPL is used only for the local node */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return false; } @@ -96,9 +112,14 @@ void bt_mesh_rpl_update(void) /* Discard "old old" IV Index entries from RPL and flag * any other ones (which are valid) as old. */ + BT_DBG("RPLUpdate"); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("RPL%u, Src 0x%04x Seq %lu OldIV %u", + i, rpl->src, rpl->seq, rpl->old_iv); + if (rpl->src) { if (rpl->old_iv) { (void)memset(rpl, 0, sizeof(*rpl)); @@ -115,6 +136,8 @@ void bt_mesh_rpl_update(void) void bt_mesh_rpl_reset_single(uint16_t src, bool erase) { + BT_DBG("RPLResetSingle, Src 0x%04x Erase %u", src, erase); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -132,6 +155,8 @@ void bt_mesh_rpl_reset_single(uint16_t src, bool erase) void bt_mesh_rpl_reset(bool erase) { + BT_DBG("RPLReset, Erase %u", erase); + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && erase) { diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index df6f22e117ec..a7a685d099ee 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -29,7 +29,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* Scan Window and Interval are equal for continuous scanning */ #define SCAN_INTERVAL 0x20 @@ -43,18 +43,18 @@ static struct bt_mesh_scan_param scan_param = { #if CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN - .type = BLE_MESH_SCAN_ACTIVE, -#else - .type = BLE_MESH_SCAN_PASSIVE, -#endif + .type = BLE_MESH_SCAN_ACTIVE, +#else /* CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ + .type = BLE_MESH_SCAN_PASSIVE, +#endif /* CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN - .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, -#else - .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, -#endif - .interval = SCAN_INTERVAL, - .window = SCAN_WINDOW, - .scan_fil_policy = BLE_MESH_SP_ADV_ALL, + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, +#else /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ + .interval = SCAN_INTERVAL, + .window = SCAN_WINDOW, + .scan_fil_policy = BLE_MESH_SP_ADV_ALL, }; #if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) @@ -76,6 +76,11 @@ int bt_mesh_unprov_dev_fifo_dequeue(uint8_t *uuid, uint8_t *addr) { uint8_t idx = 0; + BT_DBG("UnprovDevFifoDequeue, PairNum %u StartIdx %u EndIdx %u", + unprov_dev_info_fifo.pair_num, + unprov_dev_info_fifo.start_idx, + unprov_dev_info_fifo.end_idx); + if (unprov_dev_info_fifo.pair_num == 0) { return 0; } @@ -100,9 +105,11 @@ int bt_mesh_unprov_dev_fifo_dequeue(uint8_t *uuid, uint8_t *addr) int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], uint8_t *adv_type, uint8_t query_type) { + uint8_t pair_num = unprov_dev_info_fifo.pair_num; uint8_t idx = 0; uint8_t cnt = 0; - uint8_t pair_num = unprov_dev_info_fifo.pair_num; + + BT_DBG("UnprovDevInfoQuery, QueryType 0x%02x PairNum %u", query_type, pair_num); if (uuid == NULL && addr == NULL) { BT_WARN("No available information to query"); @@ -111,42 +118,49 @@ int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], while (cnt < pair_num) { idx = (cnt + unprov_dev_info_fifo.start_idx) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; + + BT_DBG("Count %u StartIdx %u Idx %u", cnt, unprov_dev_info_fifo.start_idx, idx); + if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_UUID) { if (!memcmp(unprov_dev_info_fifo.info[idx].addr, addr, 6)) { if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { return 0; - } else { - memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); - *adv_type = unprov_dev_info_fifo.info[idx].adv_type; - break; } + + memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; } } else { if (!memcmp(unprov_dev_info_fifo.info[idx].uuid, uuid, 16)) { if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { return 0; - } else { - memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); - *adv_type = unprov_dev_info_fifo.info[idx].adv_type; - break; } + + memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; } } + cnt++; } if (cnt == pair_num) { + BT_DBG("Count == PairNum"); return -1; } return 0; - } int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uint8_t adv_type) { uint8_t idx = 0; + BT_DBG("UnprovDevFifoEnqueue, EndIdx %u PairNum %u", + unprov_dev_info_fifo.end_idx, unprov_dev_info_fifo.pair_num); + if (uuid == NULL || addr == NULL) { BT_ERR("Invalid argument %s", __func__); return -EINVAL; @@ -170,6 +184,9 @@ int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uin idx = (idx + 1) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; unprov_dev_info_fifo.end_idx = idx; unprov_dev_info_fifo.pair_num++; + + BT_DBG("EndIdx %u PairNum %u", unprov_dev_info_fifo.end_idx, unprov_dev_info_fifo.pair_num); + return 0; } @@ -180,19 +197,22 @@ const bt_mesh_addr_t *bt_mesh_get_unprov_dev_addr(void) uint8_t bt_mesh_get_adv_type(void) { + BT_DBG("CurrentAdvType %u", current_adv_type); + return current_adv_type; } - #endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) static bool adv_flags_valid(struct net_buf_simple *buf) { uint8_t flags = 0U; + BT_DBG("IsAdvFlagsValid"); + if (buf->len != 1U) { BT_DBG("Unexpected adv flags length %d", buf->len); return false; @@ -200,7 +220,7 @@ static bool adv_flags_valid(struct net_buf_simple *buf) flags = net_buf_simple_pull_u8(buf); - BT_DBG("Received adv pkt with flags: 0x%02x", flags); + BT_DBG("Flags 0x%02x", flags); /* Flags context will not be checked currently */ ARG_UNUSED(flags); @@ -210,6 +230,8 @@ static bool adv_flags_valid(struct net_buf_simple *buf) static bool adv_service_uuid_valid(struct net_buf_simple *buf, uint16_t *uuid) { + BT_DBG("IsAdvServiceUUIDValid"); + if (buf->len != 2U) { BT_DBG("Length not match mesh service uuid"); return false; @@ -217,40 +239,42 @@ static bool adv_service_uuid_valid(struct net_buf_simple *buf, uint16_t *uuid) *uuid = net_buf_simple_pull_le16(buf); - BT_DBG("Received adv pkt with service UUID: %d", *uuid); + BT_DBG("UUID 0x%04x", *uuid); if (*uuid != BLE_MESH_UUID_MESH_PROV_VAL && *uuid != BLE_MESH_UUID_MESH_PROXY_VAL && *uuid != BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL) { + BT_DBG("UnexpectMeshUUID"); return false; } - /** - * @brief In remote provisioning. - * A Node could handle the unprovisioned beacon. + /* In remote provisioning, Node could handle unprovisioned device beacon. * CASE: MESH/SR/RPR/SCN/BV-01-C - */ + */ #if CONFIG_BLE_MESH_RPR_SRV if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + BT_DBG("IgnorePBGattUUID"); return false; } -#else +#else /* CONFIG_BLE_MESH_RPR_SRV */ if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && (bt_mesh_is_provisioner_en() == false || !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT))) { + BT_DBG("IgnorePBGattUUID"); return false; } -#endif - +#endif /* CONFIG_BLE_MESH_RPR_SRV */ if (*uuid == BLE_MESH_UUID_MESH_PROXY_VAL && !IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)) { + BT_DBG("IgnoreProxyUUID"); return false; } if (*uuid == BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL && !IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX)) { + BT_DBG("IgnoreProxySolicUUID"); return false; } @@ -263,6 +287,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, { uint16_t type = 0U; + BT_DBG("HandleAdvServiceData, UUID 0x%04x", uuid); + if (!buf || !addr) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -270,7 +296,7 @@ static void handle_adv_service_data(struct net_buf_simple *buf, type = net_buf_simple_pull_le16(buf); if (type != uuid) { - BT_DBG("Invalid Mesh Service Data UUID 0x%04x", type); + BT_DBG("UnexpectMeshUUID 0x%04x", type); return; } @@ -292,8 +318,13 @@ static void handle_adv_service_data(struct net_buf_simple *buf, #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_is_provisioned()) { - const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + const bt_mesh_addr_t *addr = NULL; + + addr = bt_mesh_get_unprov_dev_addr(); + assert(addr); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); } #endif /* CONFIG_BLE_MESH_RPR_SRV */ @@ -316,7 +347,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Proxy Service Data"); bt_mesh_proxy_client_gatt_adv_recv(buf, addr, rssi); break; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX case BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL: if (buf->len != (1 + BLE_MESH_NET_HDR_LEN + 8)) { @@ -327,7 +359,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Proxy Solic Service Data"); bt_mesh_proxy_server_solic_recv(buf, addr, rssi); break; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + default: break; } @@ -342,6 +375,8 @@ static bool ble_scan_en; int bt_mesh_start_ble_scan(struct bt_mesh_ble_scan_param *param) { + BT_DBG("StartBLEScan"); + if (ble_scan_en == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -354,6 +389,8 @@ int bt_mesh_start_ble_scan(struct bt_mesh_ble_scan_param *param) int bt_mesh_stop_ble_scan(void) { + BT_DBG("StopBLEScan"); + if (ble_scan_en == false) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -366,6 +403,8 @@ int bt_mesh_stop_ble_scan(void) bool bt_mesh_ble_scan_state_get(void) { + BT_DBG("BLEScanEn %u", ble_scan_en); + return ble_scan_en; } @@ -375,6 +414,7 @@ static void inline callback_ble_adv_pkt(const bt_mesh_addr_t *addr, { #if !CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_ble_adv_report_t adv_rpt = {0}; + if (ble_scan_en) { memcpy(adv_rpt.addr, addr->val, BD_ADDR_LEN); adv_rpt.addr_type = addr->type; @@ -382,9 +422,12 @@ static void inline callback_ble_adv_pkt(const bt_mesh_addr_t *addr, adv_rpt.length = length; adv_rpt.data = length ? data : NULL; adv_rpt.rssi = rssi; + + BT_DBG("CallbackBLEAdvPkt, AdvType 0x%02x Len %u", adv_type, length); + bt_mesh_ble_scan_cb_evt_to_btc(&adv_rpt); } -#endif +#endif /* !CONFIG_BLE_MESH_USE_BLE_50 */ } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ @@ -395,6 +438,8 @@ static bool rpr_ext_scan_handle_adv_pkt(const bt_mesh_addr_t *addr, struct net_buf_simple buf = {0}; bool rpr_adv = false; + BT_DBG("RPRExtScanHandleAdvPkt, Provisioned %u", bt_mesh_is_provisioned()); + if (bt_mesh_is_provisioned() == false) { return false; } @@ -408,19 +453,19 @@ static bool rpr_ext_scan_handle_adv_pkt(const bt_mesh_addr_t *addr, static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) { - struct net_buf_simple_state buf_state = {0}; struct net_buf_simple *buf = &adv_rpt->adv_data; + struct net_buf_simple_state buf_state = {0}; #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) uint16_t uuid = 0U; #endif #if (CONFIG_BLE_MESH_RPR_SRV || CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) uint8_t *adv_data = buf->data; uint16_t adv_len = buf->len; -#endif +#endif /* (CONFIG_BLE_MESH_RPR_SRV || CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) */ net_buf_simple_save(buf, &buf_state); @@ -429,41 +474,42 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) adv_rpt->adv_type != 0 && #endif adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND && - adv_rpt->adv_type != BLE_MESH_ADV_IND + adv_rpt->adv_type != BLE_MESH_ADV_IND #if CONFIG_BLE_MESH_EXT_ADV - && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND + && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND #endif #if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN - && adv_rpt->adv_type != BLE_MESH_ADV_SCAN_RSP -#endif - ) { + && adv_rpt->adv_type != BLE_MESH_ADV_SCAN_RSP +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ + ) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } - BT_DBG("scan, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("MeshScan"); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) unprov_dev_addr = &adv_rpt->addr; current_adv_type = adv_rpt->adv_type; -#endif +#endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN if (adv_rpt->adv_type == BLE_MESH_ADV_SCAN_RSP) { - /** - * scan response is only visible for remote provisioning extend scan. - */ + /* scan response is only visible for remote provisioning extend scan */ if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { return; - } else { -#if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN - callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif - net_buf_simple_restore(buf, &buf_state); } + +#if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN + callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + + net_buf_simple_restore(buf, &buf_state); } #endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ @@ -472,20 +518,24 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) uint8_t len, type; len = net_buf_simple_pull_u8(buf); + /* Check for early termination */ if (len == 0U) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } if (len > buf->len) { - BT_DBG("AD malformed"); + BT_DBG("MalformedAD"); + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } @@ -496,13 +546,15 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) buf->len = len - 1; - if ((type == BLE_MESH_DATA_MESH_PROV || type == BLE_MESH_DATA_MESH_MESSAGE || - type == BLE_MESH_DATA_MESH_BEACON) && (adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND + if ((type == BLE_MESH_DATA_MESH_PROV || + type == BLE_MESH_DATA_MESH_MESSAGE || + type == BLE_MESH_DATA_MESH_BEACON) && + (adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND #if CONFIG_BLE_MESH_EXT_ADV - && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND + && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND #endif )) { - BT_DBG("Ignore mesh packet (type 0x%02x) with adv_type 0x%02x", type, adv_rpt->adv_type); + BT_DBG("IgnorePkt, Type 0x%02x AdvType 0x%02x", type, adv_rpt->adv_type); return; } @@ -526,36 +578,44 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) #endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_generic_net_recv(buf, &rx, BLE_MESH_NET_IF_ADV); break; + #if CONFIG_BLE_MESH_PB_ADV case BLE_MESH_DATA_MESH_PROV: if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { bt_mesh_pb_adv_recv(buf); } + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { bt_mesh_provisioner_pb_adv_recv(buf); } break; #endif /* CONFIG_BLE_MESH_PB_ADV */ + case BLE_MESH_DATA_MESH_BEACON: bt_mesh_beacon_recv(buf, adv_rpt->rssi); break; + #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) case BLE_MESH_DATA_FLAGS: if (!adv_flags_valid(buf)) { BT_DBG("Adv Flags mismatch, ignore this adv pkt"); + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } break; + case BLE_MESH_DATA_UUID16_ALL: if (!adv_service_uuid_valid(buf, &uuid)) { BT_DBG("Adv Service UUID mismatch, ignore this adv pkt"); + #if CONFIG_BLE_MESH_RPR_SRV if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { /* If handled as extended scan report successfully, then not @@ -563,18 +623,25 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) */ return; } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } break; + case BLE_MESH_DATA_SVC_DATA16: handle_adv_service_data(buf, &adv_rpt->addr, uuid, adv_rpt->rssi); break; -#endif +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + default: #if CONFIG_BLE_MESH_RPR_SRV if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { @@ -583,10 +650,12 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) */ return; } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } @@ -600,9 +669,11 @@ int bt_mesh_scan_enable(void) { int err = 0; + BT_DBG("ScanEnable"); + err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("starting scan failed (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } @@ -613,9 +684,11 @@ int bt_mesh_scan_disable(void) { int err = 0; + BT_DBG("ScanDisable"); + err = bt_le_scan_stop(); if (err && err != -EALREADY) { - BT_ERR("stopping scan failed (err %d)", err); + BT_ERR("StopScanFailed, Err %d", err); return err; } @@ -629,9 +702,13 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) if (param == NULL || param->interval == 0 || param->interval < param->window) { + BT_ERR("InvalidScanParam"); return -EINVAL; } + BT_DBG("ScanParamUpdate, Type %u Interval %u Window %u", + param->type, param->interval, param->window); + scan_param.interval = param->interval; scan_param.window = param->window; @@ -641,24 +718,22 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) BT_INFO("New scan parameters will take effect after scan starts"); return 0; } - BT_ERR("Failed to stop scan (err %d)", err); + + BT_ERR("StopScanFailed, Err %d", err); return err; } - /** - * Since the user only needs to set the scan interval - * and scan window parameters, only the interval and - * window parameters in the `param` are correct. + /* Since the user only needs to set the scan interval and scan window, + * only the interval and window parameters in the `param` are correct. * - * For the aforementioned reason, when updating the scan - * parameters, the other parameters also need to be set - * correctly, and these other parameters are saved in the - * `scan_param`. Therefore, `scan_param` must be used instead - * of `param` here. + * For the aforementioned reason, when updating the scan parameters, + * the other parameters also need to be set correctly, and these other + * parameters are saved in the `scan_param`. Therefore, `scan_param` + * must be used instead of `param` here. */ err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("Failed to start scan (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } @@ -668,23 +743,24 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) #if CONFIG_BLE_MESH_TEST_USE_WHITE_LIST int bt_mesh_scan_with_wl_enable(void) { - int err = 0; - struct bt_mesh_scan_param scan_param = { .type = BLE_MESH_SCAN_PASSIVE, #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, -#else +#else /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .interval = SCAN_INTERVAL, .window = SCAN_WINDOW, .scan_fil_policy = BLE_MESH_SP_ADV_WL, }; + int err = 0; + + BT_DBG("ScanWithWLEnable"); err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("starting scan failed (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } diff --git a/components/bt/esp_ble_mesh/core/storage/settings.c b/components/bt/esp_ble_mesh/core/storage/settings.c index 40cf117f2e06..b48274eadec2 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.c +++ b/components/bt/esp_ble_mesh/core/storage/settings.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2018 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,7 +24,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* BLE Mesh NVS Key and corresponding data struct. * Note: The length of nvs key must be <= 15. @@ -45,10 +45,12 @@ * key: "mesh/s/xxxx/b" -> write/read to set/get SIG MODEL Bind AppKey List * key: "mesh/s/xxxx/s" -> write/read to set/get SIG MODEL Subscription List * key: "mesh/s/xxxx/p" -> write/read to set/get SIG MODEL Publication + * key: "mesh/s/xxxx/d" -> write/read to set/get SIG MODEL Data * key: "mesh/vnd" -> write/read to set/get all VENDOR MODEL model_keys. * key: "mesh/v/xxxx/b" -> write/read to set/get VENDOR MODEL Bind AppKey List * key: "mesh/v/xxxx/s" -> write/read to set/get VENDOR MODEL Subscription List * key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication + * key: "mesh/v/xxxx/d" -> write/read to set/get VENDOR MODEL Data * key: "mesh/vaddr" -> write/read to set/get all virtual addresses * key: "mesh/va/xxxx" -> write/read to set/get the "xxxx" virtual address * key: "mesh/dkca" -> write/read to set/get Device Key Candidate @@ -207,6 +209,8 @@ static int role_set(const char *name) bool exist = false; int err = 0; + BT_DBG("RoleSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)bt_mesh.flags, sizeof(bt_mesh.flags), &exist); if (err) { BT_ERR("Failed to load mesh device role"); @@ -219,9 +223,9 @@ static int role_set(const char *name) !IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER)) { bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_NODE); } -#else +#else /* CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY */ return 0; -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY */ } return 0; @@ -233,6 +237,8 @@ static int net_set(const char *name) bool exist = false; int err = 0; + BT_DBG("NetSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&net, sizeof(net), &exist); if (err) { BT_ERR("Failed to load node net info"); @@ -259,6 +265,8 @@ static int dkca_set(const char *name) bool exist = false; int err = 0; + BT_DBG("DkcaSet, Name %s", name); + err = bt_mesh_load_core_settings(name, bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca), &exist); if (err) { BT_ERR("Failed to load DevKey Candidate"); @@ -280,6 +288,8 @@ static int iv_set(const char *name) bool exist = false; int err = 0; + BT_DBG("IVSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&iv, sizeof(iv), &exist); if (err) { BT_ERR("Failed to load iv_index"); @@ -297,7 +307,7 @@ static int iv_set(const char *name) bt_mesh.ivu_duration = iv.iv_duration; BT_INFO("Restored IV Index 0x%08x (IV Update Flag %u) duration %u hours", - iv.iv_index, iv.iv_update, iv.iv_duration); + iv.iv_index, iv.iv_update, iv.iv_duration); return 0; } @@ -308,6 +318,8 @@ static int seq_set(const char *name) bool exist = false; int err = 0; + BT_DBG("SeqSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&seq, sizeof(seq), &exist); if (err) { BT_ERR("Failed to load sequence number"); @@ -329,7 +341,7 @@ static int seq_set(const char *name) bt_mesh.seq += (CONFIG_BLE_MESH_SEQ_STORE_RATE - (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)); bt_mesh.seq--; -#endif +#endif /* CONFIG_BLE_MESH_SEQ_STORE_RATE > 0 */ BT_INFO("Restored Sequence Number 0x%06x", bt_mesh.seq); @@ -340,6 +352,8 @@ static struct bt_mesh_rpl *rpl_find(uint16_t src) { int i; + BT_DBG("RPLFind, Src 0x%04x", src); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (bt_mesh.rpl[i].src == src) { return &bt_mesh.rpl[i]; @@ -353,6 +367,8 @@ static struct bt_mesh_rpl *rpl_alloc(uint16_t src) { int i; + BT_DBG("RPLAlloc, Src 0x%04x", src); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (bt_mesh.rpl[i].src == BLE_MESH_ADDR_UNASSIGNED) { bt_mesh.rpl[i].src = src; @@ -374,6 +390,8 @@ static int rpl_set(const char *name) int err = 0; int i; + BT_DBG("RPLSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -427,6 +445,8 @@ static struct bt_mesh_subnet *subnet_exist(uint16_t net_idx) { int i; + BT_DBG("SubnetExist, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx == net_idx) { return &bt_mesh.sub[i]; @@ -440,6 +460,8 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) { int i; + BT_DBG("SubnetAlloc, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx == BLE_MESH_KEY_UNUSED) { bt_mesh.sub[i].net_idx = net_idx; @@ -454,6 +476,8 @@ static struct bt_mesh_app_key *appkey_exist(uint16_t app_idx) { int i; + BT_DBG("AppKeyExist, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && bt_mesh.app_keys[i].app_idx == app_idx) { @@ -475,6 +499,8 @@ static int net_key_set(const char *name) int err = 0; int i; + BT_DBG("NetKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -533,6 +559,8 @@ static int app_key_set(const char *name) int err = 0; int i; + BT_DBG("AppKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -564,7 +592,6 @@ static int app_key_set(const char *name) if (!app) { app = bt_mesh_app_key_alloc(app_idx); if (!app) { - BT_ERR("No space for a new appkey 0x%03x", app_idx); err = -ENOMEM; goto free; } @@ -579,7 +606,7 @@ static int app_key_set(const char *name) bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); BT_INFO("Restored AppKeyIndex 0x%03x, NetKeyIndex 0x%03x", - app->app_idx, app->net_idx); + app->app_idx, app->net_idx); BT_INFO("Restored AppKey %s", bt_hex(app->keys[0].val, 16)); } @@ -595,6 +622,8 @@ static int hb_pub_set(const char *name) bool exist = false; int err = 0; + BT_DBG("HbPubSet, Name %s", name); + if (!hb_pub) { BT_ERR("Invalid heartbeat publication"); return -EINVAL; @@ -639,6 +668,8 @@ static int cfg_set(const char *name) bool exist = false; int err = 0; + BT_DBG("CfgSet, Name %s", name); + if (!cfg) { BT_ERR("Invalid configuration"); stored_cfg.valid = false; @@ -672,6 +703,8 @@ static int model_set_bind(bool vnd, struct bt_mesh_model *model, uint16_t model_ int err = 0; int i; + BT_DBG("ModelSetBind, Key 0x%04x Vnd %u", model_key, vnd); + /* Start with empty array regardless of cleared or set value */ for (i = 0; i < ARRAY_SIZE(model->keys); i++) { model->keys[i] = BLE_MESH_KEY_UNUSED; @@ -698,6 +731,8 @@ static int model_set_sub(bool vnd, struct bt_mesh_model *model, uint16_t model_k int err = 0; int i; + BT_DBG("ModelSetSub, Key 0x%04x Vnd %u", model_key, vnd); + /* Start with empty array regardless of cleared or set value */ for (i = 0; i < ARRAY_SIZE(model->groups); i++) { model->groups[i] = BLE_MESH_ADDR_UNASSIGNED; @@ -724,6 +759,8 @@ static int model_set_pub(bool vnd, struct bt_mesh_model *model, uint16_t model_k bool exist = false; int err = 0; + BT_DBG("ModelSetPub, Key 0x%04x Vnd %u", model_key, vnd); + if (!model->pub) { BT_INFO("Not support publication, model_id 0x%04x, cid 0x%04x", vnd ? model->vnd.id : model->id, vnd ? model->vnd.company : 0xFFFF); @@ -774,6 +811,8 @@ static int model_set(bool vnd, const char *name) size_t length = 0U; int i; + BT_DBG("ModelSet, Name %s Vnd %u", name, vnd); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -790,7 +829,7 @@ static int model_set(bool vnd, const char *name) model = bt_mesh_model_get(vnd, elem_idx, model_idx); if (!model) { BT_ERR("%s model not found, elem_idx %u, model_idx %u", - vnd ? "vnd" : "sig", elem_idx, model_idx); + vnd ? "vnd" : "sig", elem_idx, model_idx); continue; } @@ -825,6 +864,8 @@ static int va_set(const char *name) int err = 0; int i; + BT_DBG("VaSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -869,7 +910,7 @@ static int va_set(const char *name) bt_mesh_free_buf(buf); return err; } -#endif +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ #if CONFIG_BLE_MESH_PROVISIONER static int p_prov_set(const char *name) @@ -878,6 +919,8 @@ static int p_prov_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrProvSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&val, sizeof(val), &exist); if (err) { BT_ERR("Failed to load next address allocation"); @@ -891,7 +934,7 @@ static int p_prov_set(const char *name) bt_mesh_provisioner_restore_prov_info(val.primary_addr, val.alloc_addr); BT_INFO("Restored Primary Address 0x%04x, next address alloc 0x%04x", - val.primary_addr, val.alloc_addr); + val.primary_addr, val.alloc_addr); return 0; } @@ -902,6 +945,8 @@ static int p_net_idx_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrNetIdxSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&net_idx, sizeof(net_idx), &exist); if (err) { BT_ERR("Failed to load next NetKeyIndex alloc"); @@ -925,6 +970,8 @@ static int p_app_idx_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrAppIdxSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&app_idx, sizeof(app_idx), &exist); if (err) { BT_ERR("Failed to load next AppKeyIndex alloc"); @@ -946,6 +993,8 @@ static struct bt_mesh_subnet *p_subnet_exist(uint16_t net_idx) { int i; + BT_DBG("PvnrSubnetExist, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { if (bt_mesh.p_sub[i] && bt_mesh.p_sub[i]->net_idx == net_idx) { @@ -960,6 +1009,8 @@ static struct bt_mesh_subnet *p_subnet_alloc(void) { int i; + BT_DBG("PvnrSubnetAlloc"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { if (bt_mesh.p_sub[i] == NULL) { bt_mesh.p_sub[i] = bt_mesh_calloc(sizeof(struct bt_mesh_subnet)); @@ -979,6 +1030,8 @@ static struct bt_mesh_app_key *p_appkey_exist(uint16_t app_idx) { int i; + BT_DBG("PvnrAppKeyExist, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { if (bt_mesh.p_app_keys[i] && bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && @@ -994,6 +1047,8 @@ static struct bt_mesh_app_key *p_appkey_alloc(void) { int i; + BT_DBG("PvnrAppKeyAlloc"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { if (bt_mesh.p_app_keys[i] == NULL) { bt_mesh.p_app_keys[i] = bt_mesh_calloc(sizeof(struct bt_mesh_app_key)); @@ -1020,6 +1075,8 @@ static int p_net_key_set(const char *name) int err = 0; int i; + BT_DBG("PvnrNetKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1078,6 +1135,8 @@ static int p_app_key_set(const char *name) int err = 0; int i; + BT_DBG("PvnrAppKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1124,7 +1183,7 @@ static int p_app_key_set(const char *name) bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); BT_INFO("Restored AppKeyIndex 0x%03x, NetKeyIndex 0x%03x", - app->app_idx, app->net_idx); + app->app_idx, app->net_idx); BT_INFO("Restored AppKey %s", bt_hex(app->keys[0].val, 16)); } @@ -1140,6 +1199,8 @@ static int node_info_set(uint16_t addr, bool *exist) char get[16] = {'\0'}; int err = 0; + BT_DBG("NodeInfoSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/i", addr); err = bt_mesh_load_core_settings(get, (uint8_t *)&info, sizeof(info), exist); if (err) { @@ -1180,6 +1241,8 @@ static int node_name_set(uint16_t addr) bool exist = false; int err = 0; + BT_DBG("NodeNameSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/n", addr); err = bt_mesh_load_core_settings(get, (uint8_t *)name, BLE_MESH_NODE_NAME_SIZE, &exist); if (err) { @@ -1208,6 +1271,8 @@ static int node_comp_data_set(uint16_t addr) char get[16] = {'\0'}; int err = 0; + BT_DBG("NodeCompDataSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/c", addr); buf = bt_mesh_get_core_settings_item(get); if (!buf) { @@ -1232,6 +1297,8 @@ static int p_node_set(const char *name) size_t length = 0U; int i; + BT_DBG("PvnrNodeSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1286,7 +1353,7 @@ const struct bt_mesh_setting { { "mesh/vnd", vnd_mod_set }, /* For Node & Provisioner */ #if CONFIG_BLE_MESH_LABEL_COUNT > 0 { "mesh/vaddr", va_set }, /* For Node */ -#endif +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ #if CONFIG_BLE_MESH_PROVISIONER { "mesh/p_prov", p_prov_set }, /* For Provisioner */ { "mesh/p_netidx", p_net_idx_set }, /* For Provisioner */ @@ -1294,7 +1361,7 @@ const struct bt_mesh_setting { { "mesh/p_netkey", p_net_key_set }, /* For Provisioner */ { "mesh/p_appkey", p_app_key_set }, /* For Provisioner */ { "mesh/p_node", p_node_set }, /* For Provisioner */ -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ }; /** @@ -1316,6 +1383,8 @@ int settings_core_load(void) { int i; + BT_DBG("SettingsCoreLoad"); + for (i = 0; i < ARRAY_SIZE(settings); i++) { if ((!strcmp(settings[i].name, "mesh/net") || !strcmp(settings[i].name, "mesh/netkey") || @@ -1367,6 +1436,8 @@ static int subnet_init(struct bt_mesh_subnet *sub) { int err = 0; + BT_DBG("SubnetInit, NetIdx 0x%04x KrPhase %u", sub->net_idx, sub->kr_phase); + err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net); if (err) { BT_ERR("Unable to generate keys for subnet"); @@ -1394,7 +1465,7 @@ static int subnet_init(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_directed_forwarding_sub_init(sub); bt_mesh_recovery_directed_forwarding_table(sub); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return 0; } @@ -1402,8 +1473,10 @@ static int subnet_init(struct bt_mesh_subnet *sub) static void commit_model(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("CommitModel, Vnd %u Primary %u", vnd, primary); + if (model->pub && model->pub->update && - model->pub->addr != BLE_MESH_ADDR_UNASSIGNED) { + model->pub->addr != BLE_MESH_ADDR_UNASSIGNED) { int32_t ms = bt_mesh_model_pub_period_get(model); if (ms) { BT_DBG("Starting publish timer (period %u ms)", ms); @@ -1418,10 +1491,13 @@ int settings_core_commit(void) int err = 0; int i; + BT_DBG("SettingsCoreCommit"); + #if CONFIG_BLE_MESH_NODE if (bt_mesh_is_node()) { if (bt_mesh.sub[0].net_idx == BLE_MESH_KEY_UNUSED) { /* Nothing to do since we're not yet provisioned */ + BT_INFO("NodeNotYetProvisioned"); return 0; } @@ -1511,20 +1587,22 @@ int settings_core_commit(void) } /* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BLE_MESH_NET_PENDING) | \ - BIT(BLE_MESH_IV_PENDING) | \ - BIT(BLE_MESH_SEQ_PENDING)) +#define NO_WAIT_PENDING_BITS (BIT(BLE_MESH_NET_PENDING) | \ + BIT(BLE_MESH_IV_PENDING) | \ + BIT(BLE_MESH_SEQ_PENDING)) /* Pending flags that use CONFIG_BLE_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BLE_MESH_KEYS_PENDING) | \ - BIT(BLE_MESH_HB_PUB_PENDING) | \ - BIT(BLE_MESH_CFG_PENDING) | \ - BIT(BLE_MESH_MOD_PENDING)) +#define GENERIC_PENDING_BITS (BIT(BLE_MESH_KEYS_PENDING) | \ + BIT(BLE_MESH_HB_PUB_PENDING) | \ + BIT(BLE_MESH_CFG_PENDING) | \ + BIT(BLE_MESH_MOD_PENDING)) static void schedule_store(int flag) { int32_t timeout = 0, remaining = 0; + BT_DBG("ScheduleStore, Flag %ld", flag); + bt_mesh_atomic_set_bit(bt_mesh.flags, flag); /* When Node is not provisioned OR Provisioner is disabled, @@ -1562,7 +1640,8 @@ static void schedule_store(int flag) static void clear_net(void) { - BT_DBG("Clearing Network"); + BT_DBG("ClearNet"); + bt_mesh_erase_core_settings("mesh/net"); } @@ -1570,8 +1649,9 @@ static void store_pending_net(void) { struct net_val net = {0}; - BT_DBG("Primary address 0x%04x DevKey %s", bt_mesh_primary_addr(), - bt_hex(bt_mesh.dev_key, 16)); + BT_DBG("StorePendingNet"); + BT_DBG("PrimaryAddr 0x%04x DevKey %s", + bt_mesh_primary_addr(), bt_hex(bt_mesh.dev_key, 16)); net.primary_addr = bt_mesh_primary_addr(); memcpy(net.dev_key, bt_mesh.dev_key, 16); @@ -1581,13 +1661,15 @@ static void store_pending_net(void) void bt_mesh_store_role(void) { - BT_DBG("Store, device role %lu", bt_mesh_atomic_get(bt_mesh.flags) & BLE_MESH_SETTINGS_ROLE_BIT_MASK); + BT_DBG("StoreRole %lu", bt_mesh_atomic_get(bt_mesh.flags) & BLE_MESH_SETTINGS_ROLE_BIT_MASK); bt_mesh_save_core_settings("mesh/role", (const uint8_t *)bt_mesh.flags, sizeof(bt_mesh.flags)); } void bt_mesh_store_net(void) { + BT_DBG("StoreNetSchedule"); + schedule_store(BLE_MESH_NET_PENDING); } @@ -1595,6 +1677,8 @@ static void store_pending_iv(void) { struct iv_val iv = {0}; + BT_DBG("StorePendingIV"); + iv.iv_index = bt_mesh.iv_index; iv.iv_update = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); iv.iv_duration = bt_mesh.ivu_duration; @@ -1604,6 +1688,8 @@ static void store_pending_iv(void) void bt_mesh_store_iv(bool only_duration) { + BT_DBG("StoreIVSchedule, OnlyDuration %u", only_duration); + schedule_store(BLE_MESH_IV_PENDING); if (!only_duration) { @@ -1614,7 +1700,8 @@ void bt_mesh_store_iv(bool only_duration) static void clear_iv(void) { - BT_DBG("Clearing IV"); + BT_DBG("ClearIV"); + bt_mesh_erase_core_settings("mesh/iv"); } @@ -1622,6 +1709,8 @@ static void store_pending_seq(void) { struct seq_val seq = {0}; + BT_DBG("StorePendingSeq, Seq 0x%06x", bt_mesh.seq); + sys_put_le24(bt_mesh.seq, seq.val); bt_mesh_save_core_settings("mesh/seq", (const uint8_t *)&seq, sizeof(seq)); @@ -1629,6 +1718,8 @@ static void store_pending_seq(void) void bt_mesh_store_seq(void) { + BT_DBG("StoreSeqSchedule, Seq 0x%06x", bt_mesh.seq); + if (CONFIG_BLE_MESH_SEQ_STORE_RATE && (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)) { return; @@ -1639,7 +1730,8 @@ void bt_mesh_store_seq(void) void bt_mesh_clear_seq(void) { - BT_DBG("Clearing Seq"); + BT_DBG("ClearSeq"); + bt_mesh_erase_core_settings("mesh/seq"); } @@ -1649,7 +1741,8 @@ static void store_rpl(struct bt_mesh_rpl *entry) char name[16] = {'\0'}; int err = 0; - BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq, entry->old_iv); + BT_DBG("StoreRPL"); + BT_DBG("Src 0x%04x Seq 0x%06x OldIV %u", entry->src, entry->seq, entry->old_iv); rpl.seq = entry->seq; rpl.old_iv = entry->old_iv; @@ -1675,6 +1768,8 @@ static void clear_rpl(void) uint16_t src = 0U; int i; + BT_DBG("ClearRPL"); + buf = bt_mesh_get_core_settings_item("mesh/rpl"); if (!buf) { bt_mesh_erase_core_settings("mesh/rpl"); @@ -1704,9 +1799,14 @@ static void store_pending_rpl(void) { int i; + BT_DBG("StorePendingRPL"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("%u: Src 0x%04x Seq 0x%06x OldIV %u Store %u", + i, rpl->src, rpl->seq, rpl->old_iv, rpl->store); + if (rpl->store) { rpl->store = false; store_rpl(rpl); @@ -1719,6 +1819,8 @@ static void store_pending_hb_pub(void) struct bt_mesh_hb_pub *hb_pub = bt_mesh_hb_pub_get(); struct hb_pub_val val = {0}; + BT_DBG("StorePendingHbPub"); + if (!hb_pub) { BT_ERR("Invalid heartbeat publication"); return; @@ -1736,7 +1838,8 @@ static void store_pending_hb_pub(void) static void clear_hb_pub(void) { - BT_DBG("Clear heartbeat publication"); + BT_DBG("ClearHbPub"); + bt_mesh_erase_core_settings("mesh/hb_pub"); } @@ -1745,6 +1848,8 @@ static void store_pending_cfg(void) struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct cfg_val val = {0}; + BT_DBG("StorePendingCfg"); + if (!cfg) { BT_WARN("NULL configuration state"); return; @@ -1763,7 +1868,8 @@ static void store_pending_cfg(void) static void clear_cfg(void) { - BT_DBG("Clearing configuration"); + BT_DBG("ClearCfg"); + bt_mesh_erase_core_settings("mesh/cfg"); } @@ -1772,7 +1878,7 @@ static void clear_app_key(uint16_t app_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("AppKeyIndex 0x%03x", app_idx); + BT_DBG("ClearAppKey, AppIdx 0x%04x", app_idx); sprintf(name, "mesh/ak/%04x", app_idx); bt_mesh_erase_core_settings(name); @@ -1788,7 +1894,7 @@ static void clear_net_key(uint16_t net_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x", net_idx); + BT_DBG("ClearNetKey, NetIdx 0x%04x", net_idx); sprintf(name, "mesh/nk/%04x", net_idx); bt_mesh_erase_core_settings(name); @@ -1800,7 +1906,7 @@ static void clear_net_key(uint16_t net_idx) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_clear_directed_forwarding_table_data(net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } static void store_net_key(struct bt_mesh_subnet *sub) @@ -1809,8 +1915,8 @@ static void store_net_key(struct bt_mesh_subnet *sub) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net, 16)); + BT_DBG("StoreNetKey, NetIdx 0x%04x KrFlag %u KrPhase %u", + sub->net_idx, sub->kr_flag, sub->kr_phase); memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); @@ -1836,6 +1942,9 @@ static void store_app_key(struct bt_mesh_app_key *app) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreAppKey, NetIdx 0x%04x AppIdx 0x%04x Updated %u", + app->net_idx, app->app_idx, app->updated); + key.net_idx = app->net_idx; key.updated = app->updated; memcpy(key.val[0], app->keys[0].val, 16); @@ -1858,9 +1967,14 @@ static void store_pending_keys(void) { int i; + BT_DBG("StorePendingKeys"); + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { struct key_update *update = &key_updates[i]; + BT_DBG("%u: KeyIdx 0x%04x Valid %u AppKey %u Clear %u", + i, update->key_idx, update->valid, update->app_key, update->clear); + if (!update->valid) { continue; } @@ -1874,6 +1988,7 @@ static void store_pending_keys(void) } else { if (update->app_key) { struct bt_mesh_app_key *key = NULL; + key = bt_mesh_app_key_get(update->key_idx); if (key) { store_app_key(key); @@ -1882,6 +1997,7 @@ static void store_pending_keys(void) } } else { struct bt_mesh_subnet *sub = NULL; + sub = bt_mesh_subnet_get(update->key_idx); if (sub) { store_net_key(sub); @@ -1901,6 +2017,8 @@ static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModBind, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); @@ -1913,7 +2031,7 @@ static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); if (err) { BT_ERR("Failed to add bound key to %s, model_key 0x%04x", - vnd ? "mesh/vnd" : "mesh/sig", model_key); + vnd ? "mesh/vnd" : "mesh/sig", model_key); } } @@ -1923,6 +2041,8 @@ static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModSub, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); @@ -1935,7 +2055,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); if (err) { BT_ERR("Failed to add subscription to %s, model_key 0x%04x", - vnd ? "mesh/vnd" : "mesh/sig", model_key); + vnd ? "mesh/vnd" : "mesh/sig", model_key); } } @@ -1946,6 +2066,8 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModPub, Vnd %u", vnd); + if (!model->pub) { BT_WARN("Model has no publication support"); return; @@ -1964,7 +2086,7 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) #if CONFIG_BLE_MESH_DF_SRV pub.directed_pub_policy = model->pub->directed_pub_policy; /**< Directed publish policy */ -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ err = bt_mesh_save_core_settings(name, (const uint8_t *)&pub, sizeof(pub)); if (err) { @@ -1983,6 +2105,8 @@ static void store_pending_mod(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("StorePendingMod, Flags %u Vnd %u", model->flags, vnd); + if (!model->flags) { return; } @@ -2008,6 +2132,8 @@ static void clear_mod_bind(struct bt_mesh_model *model, bool vnd) char name[16] = {'\0'}; uint16_t model_key = 0U; + BT_DBG("ClearModBind, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); @@ -2020,6 +2146,8 @@ static void clear_mod_sub(struct bt_mesh_model *model, bool vnd) char name[16] = {'\0'}; uint16_t model_key = 0U; + BT_DBG("ClearModSub, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); @@ -2029,8 +2157,10 @@ static void clear_mod_sub(struct bt_mesh_model *model, bool vnd) static void clear_mod_pub(struct bt_mesh_model *model, bool vnd) { - char name[16] = {'\0'}; uint16_t model_key = 0U; + char name[16] = {'\0'}; + + BT_DBG("ClearModPub, Vnd %u", vnd); model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/p", vnd ? "v" : "s", model_key); @@ -2043,6 +2173,8 @@ static void clear_pending_mod(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ClearPendingMod, Flags 0x%04x Vnd %u", model->flags, vnd); + if (!model->flags) { return; } @@ -2066,12 +2198,14 @@ static void clear_pending_mod(struct bt_mesh_model *model, #define IS_VA_DEL(_label) ((_label)->ref == 0) static void store_pending_va(void) { + struct label *lab = NULL; struct va_val va = {0}; char name[16] = {'\0'}; - struct label *lab = NULL; uint16_t i = 0U; int err = 0; + BT_DBG("StorePendingVa"); + for (i = 0U; (lab = get_label(i)) != NULL; i++) { if (!bt_mesh_atomic_test_and_clear_bit(lab->flags, BLE_MESH_VA_CHANGED)) { @@ -2090,7 +2224,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s virtual address %s", - IS_VA_DEL(lab) ? "delete" : "store", name); + IS_VA_DEL(lab) ? "delete" : "store", name); return; } @@ -2101,7 +2235,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s 0x%04x in mesh/vaddr", - IS_VA_DEL(lab) ? "delete" : "store", i); + IS_VA_DEL(lab) ? "delete" : "store", i); return; } @@ -2111,6 +2245,8 @@ static void store_pending_va(void) static void store_pending(struct k_work *work) { + BT_DBG("StorePending"); + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_RPL_PENDING)) { if (bt_mesh_is_provisioned() || bt_mesh_is_provisioner_en()) { store_pending_rpl(); @@ -2172,6 +2308,7 @@ static void store_pending(struct k_work *work) bt_mesh_model_foreach(store_pending_mod, NULL); } else { bt_mesh_model_foreach(clear_pending_mod, NULL); + bt_mesh_erase_core_settings("mesh/sig"); bt_mesh_erase_core_settings("mesh/vnd"); } @@ -2185,6 +2322,9 @@ static void store_pending(struct k_work *work) void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) { + BT_DBG("StoreRPLSchedule"); + BT_DBG("Src 0x%04x Seq 0x%06x OldIV %u", entry->src, entry->seq, entry->old_iv); + entry->store = true; schedule_store(BLE_MESH_RPL_PENDING); } @@ -2197,6 +2337,8 @@ static struct key_update *key_update_find(bool app_key, uint16_t key_idx, *free_slot = NULL; + BT_DBG("KeyUpdateFind, KeyIdx 0x%04x AppKey %u", key_idx, app_key); + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { struct key_update *update = &key_updates[i]; @@ -2222,7 +2364,7 @@ void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("StoreSubnetSchedule, NetIdx 0x%04x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { @@ -2232,6 +2374,7 @@ void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) } if (!free_slot) { + BT_DBG("NoFreeSlotForSubnet"); store_net_key(sub); return; } @@ -2249,7 +2392,7 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("StoreAppKeySchedule, AppIdx 0x%04x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { @@ -2259,6 +2402,7 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) } if (!free_slot) { + BT_DBG("NoFreeSlotForAppKey"); store_app_key(key); return; } @@ -2273,22 +2417,29 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) void bt_mesh_store_hb_pub(void) { + BT_DBG("StoreHbPubSchedule"); + schedule_store(BLE_MESH_HB_PUB_PENDING); } void bt_mesh_store_cfg(void) { + BT_DBG("StoreCfgSchedule"); + schedule_store(BLE_MESH_CFG_PENDING); } void bt_mesh_clear_role(void) { - BT_DBG("Clear device role"); + BT_DBG("ClearRole"); + bt_mesh_erase_core_settings("mesh/role"); } void bt_mesh_clear_net(void) { + BT_DBG("ClearNetSchedule"); + schedule_store(BLE_MESH_NET_PENDING); schedule_store(BLE_MESH_IV_PENDING); schedule_store(BLE_MESH_CFG_PENDING); @@ -2299,7 +2450,7 @@ void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("ClearSubnetSchedule, NetIdx 0x%04x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { @@ -2326,7 +2477,7 @@ void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("ClearAppKeySchedule, AppIdx 0x%04x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { @@ -2353,6 +2504,8 @@ void bt_mesh_clear_rpl_single(uint16_t src) char name[16] = {'\0'}; int err = 0; + BT_DBG("ClearRPLSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { BT_ERR("Invalid src 0x%04x", src); return; @@ -2369,39 +2522,53 @@ void bt_mesh_clear_rpl_single(uint16_t src) void bt_mesh_clear_rpl(void) { + BT_DBG("ClearRPLSchedule"); + schedule_store(BLE_MESH_RPL_PENDING); } void bt_mesh_store_mod_bind(struct bt_mesh_model *model) { + BT_DBG("StoreModBindSchedule"); + model->flags |= BLE_MESH_MOD_BIND_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_mod_sub(struct bt_mesh_model *model) { + BT_DBG("StoreModSubSchedule"); + model->flags |= BLE_MESH_MOD_SUB_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_mod_pub(struct bt_mesh_model *model) { + BT_DBG("StoreModPubSchedule"); + model->flags |= BLE_MESH_MOD_PUB_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_label(void) { + BT_DBG("StoreLabelSchedule"); + schedule_store(BLE_MESH_VA_PENDING); } void bt_mesh_store_dkca(void) { + BT_DBG("StoreDkca"); + bt_mesh_save_core_settings("mesh/dkca", bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca)); } void bt_mesh_clear_dkca(void) { + BT_DBG("ClearDkca"); + bt_mesh_erase_core_settings("mesh/dkca"); } @@ -2423,7 +2590,7 @@ void bt_mesh_store_prov_info(uint16_t primary_addr, uint16_t alloc_addr) { struct prov_info val = {0}; - BT_DBG("Primary address 0x%04x, next address allocation 0x%04x", primary_addr, alloc_addr); + BT_DBG("StoreProvInfo, PrimaryAddr 0x%04x AllocAddr 0x%04x", primary_addr, alloc_addr); val.primary_addr = primary_addr; val.alloc_addr = alloc_addr; @@ -2433,7 +2600,8 @@ void bt_mesh_store_prov_info(uint16_t primary_addr, uint16_t alloc_addr) void bt_mesh_clear_prov_info(void) { - BT_DBG("Clearing prov info"); + BT_DBG("ClearProvInfo"); + bt_mesh_erase_core_settings("mesh/p_prov"); } @@ -2443,6 +2611,9 @@ static void store_p_net_key(struct bt_mesh_subnet *sub) char name[16] = {'\0'}; int err = 0; + BT_DBG("StorePvnrNetKey, NetIdx 0x%04x KrFlag %u KrPhase %u", + sub->net_idx, sub->kr_flag, sub->kr_phase); + memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); key.kr_flag = sub->kr_flag; @@ -2467,6 +2638,9 @@ static void store_p_app_key(struct bt_mesh_app_key *app) char name[16] = {'\0'}; int err = 0; + BT_DBG("StorePvnrAppKey, NetIdx 0x%04x AppIdx 0x%04x Updated %u", + app->net_idx, app->app_idx, app->updated); + key.net_idx = app->net_idx; key.updated = app->updated; memcpy(key.val[0], app->keys[0].val, 16); @@ -2487,7 +2661,7 @@ static void store_p_app_key(struct bt_mesh_app_key *app) void bt_mesh_store_p_net_idx(void) { - BT_DBG("Store, p_net_idx_next 0x%03x", bt_mesh.p_net_idx_next); + BT_DBG("StorePvnrNetIdx, NetIdxNext 0x%04x", bt_mesh.p_net_idx_next); bt_mesh_save_core_settings("mesh/p_netidx", (const uint8_t *)&bt_mesh.p_net_idx_next, sizeof(bt_mesh.p_net_idx_next)); @@ -2495,13 +2669,14 @@ void bt_mesh_store_p_net_idx(void) void bt_mesh_clear_p_net_idx(void) { - BT_DBG("Clearing NetKey Index"); + BT_DBG("ClearPvnrNetIdx"); + bt_mesh_erase_core_settings("mesh/p_netidx"); } void bt_mesh_store_p_app_idx(void) { - BT_DBG("Store, p_app_idx_next 0x%03x", bt_mesh.p_app_idx_next); + BT_DBG("StorePvnrAppIdx, AppIdxNext 0x%04x", bt_mesh.p_app_idx_next); bt_mesh_save_core_settings("mesh/p_appidx", (const uint8_t *)&bt_mesh.p_app_idx_next, sizeof(bt_mesh.p_app_idx_next)); @@ -2509,32 +2684,37 @@ void bt_mesh_store_p_app_idx(void) void bt_mesh_clear_p_app_idx(void) { - BT_DBG("Clearing AppKey Index"); + BT_DBG("ClearPvnrAppIdx"); + bt_mesh_erase_core_settings("mesh/p_appidx"); } void bt_mesh_store_p_subnet(struct bt_mesh_subnet *sub) { + BT_DBG("StorePvnrSubnet"); + if (sub == NULL) { BT_ERR("Invalid subnet"); return; } - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net, 16)); + BT_DBG("NetIdx 0x%04x NetKey %s", + sub->net_idx, bt_hex(sub->keys[0].net, 16)); store_p_net_key(sub); } void bt_mesh_store_p_app_key(struct bt_mesh_app_key *key) { + BT_DBG("StorePvnrAppKey"); + if (key == NULL) { BT_ERR("Invalid AppKey"); return; } - BT_DBG("AppKeyIndex 0x%03x AppKey %s", key->app_idx, - bt_hex(key->keys[0].val, 16)); + BT_DBG("AppIdx 0x%03x AppKey %s", + key->app_idx, bt_hex(key->keys[0].val, 16)); store_p_app_key(key); } @@ -2544,7 +2724,7 @@ void bt_mesh_clear_p_subnet(uint16_t net_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x", net_idx); + BT_DBG("ClearPvnrSubnet, NetIdx 0x%04x", net_idx); sprintf(name, "mesh/pnk/%04x", net_idx); bt_mesh_erase_core_settings(name); @@ -2560,7 +2740,7 @@ void bt_mesh_clear_p_app_key(uint16_t app_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("AppKeyIndex 0x%03x", app_idx); + BT_DBG("ClearPvnrAppKey, AppIdx 0x%04x", app_idx); sprintf(name, "mesh/pak/%04x", app_idx); bt_mesh_erase_core_settings(name); @@ -2577,11 +2757,17 @@ void bt_mesh_store_node_info(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeInfo"); + if (node == NULL) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x ElemNum %u NetIdx 0x%04x Flags %u IVIndex %lu", + node->unicast_addr, node->element_num, + node->net_idx, node->flags, node->iv_index); + memcpy(val.addr, node->addr, BLE_MESH_ADDR_LEN); val.addr_type = node->addr_type; memcpy(val.dev_uuid, node->dev_uuid, 16); @@ -2611,6 +2797,8 @@ static void clear_node(uint16_t addr) char name[16] = {'\0'}; int err = 0; + BT_DBG("ClearNode, Addr 0x%04x", addr); + /* Clear node information */ sprintf(name, "mesh/pn/%04x/i", addr); bt_mesh_erase_core_settings(name); @@ -2631,13 +2819,13 @@ static void clear_node(uint16_t addr) void bt_mesh_clear_node_info(uint16_t unicast_addr) { + BT_DBG("ClearNodeInfo, Addr 0x%04x", unicast_addr); + if (!BLE_MESH_ADDR_IS_UNICAST(unicast_addr)) { BT_ERR("Invalid unicast address 0x%04x", unicast_addr); return; } - BT_DBG("Unicast address 0x%04x", unicast_addr); - clear_node(unicast_addr); } @@ -2647,11 +2835,15 @@ void bt_mesh_store_node_name(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeName"); + if (node == NULL) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x NodeName %s", node->unicast_addr, node->name); + strncpy(node_name, node->name, BLE_MESH_NODE_NAME_SIZE + 1); sprintf(name, "mesh/pn/%04x/n", node->unicast_addr); @@ -2666,11 +2858,15 @@ void bt_mesh_store_node_comp_data(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeCompData"); + if (!node || !node->comp_data || node->comp_length == 0U) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x CompLength %u", node->unicast_addr, node->comp_length); + sprintf(name, "mesh/pn/%04x/c", node->unicast_addr); err = bt_mesh_save_core_settings(name, (const uint8_t *)node->comp_data, node->comp_length); if (err) { @@ -2681,12 +2877,16 @@ void bt_mesh_store_node_comp_data(struct bt_mesh_node *node) int settings_core_init(void) { + BT_DBG("SettingsCoreInit"); + k_delayed_work_init(&pending_store, store_pending); return 0; } int bt_mesh_settings_init(void) { + BT_DBG("SettingsInit"); + bt_mesh_settings_mutex_new(); bt_mesh_settings_init_foreach(); return 0; @@ -2695,12 +2895,16 @@ int bt_mesh_settings_init(void) #if CONFIG_BLE_MESH_DEINIT int settings_core_deinit(void) { + BT_DBG("SettingsCoreDeinit"); + k_delayed_work_free(&pending_store); return 0; } int settings_core_erase(void) { + BT_DBG("SettingsCoreErase"); + /* Erase here must not use the pending_store timer. * This is used for erasing the information which * could not be erased during the previous deinit @@ -2714,6 +2918,8 @@ int settings_core_erase(void) int bt_mesh_settings_deinit(bool erase) { + BT_DBG("SettingsDeinit, Erase %u", erase); + bt_mesh_settings_deinit_foreach(erase); bt_mesh_settings_mutex_free(); return 0; @@ -2722,6 +2928,8 @@ int bt_mesh_settings_deinit(bool erase) void bt_mesh_settings_reset(bool erase) { + BT_DBG("SettingsReset, Erase %u", erase); + k_delayed_work_cancel(&pending_store); if (erase) { bt_mesh_clear_net(); @@ -2731,3 +2939,40 @@ void bt_mesh_settings_reset(bool erase) } #endif /* CONFIG_BLE_MESH_SETTINGS */ + +#define SETTINGS_MAX_DIR_DEPTH 8 + +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len) +{ + int err = 0; + + char path[30] = {'\0'}; + uint16_t model_key = 0U; + + model_key = BLE_MESH_GET_MODEL_KEY(mod->elem_idx, mod->model_idx); + sprintf(path, "mesh/%s/%04x/d", vnd ? "v" : "s", model_key); + if (name) { + strcat(path, "/"); + strncat(path, name, SETTINGS_MAX_DIR_DEPTH); + } + + if (data_len) { + err = bt_mesh_save_core_settings(path, data, data_len); + if (err) { + BT_ERR("Failed to store %s", path); + return err; + } + + err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + if (err) { + BT_ERR("Failed to add model data to %s, model_key 0x%04x", + vnd ? "mesh/vnd" : "mesh/sig", model_key); + } + } else { + bt_mesh_erase_core_settings(path); + bt_mesh_remove_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + } + return err; +} diff --git a/components/bt/esp_ble_mesh/core/storage/settings.h b/components/bt/esp_ble_mesh/core/storage/settings.h index 255eb2c34340..7ad8cf3cd6e7 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.h +++ b/components/bt/esp_ble_mesh/core/storage/settings.h @@ -35,6 +35,10 @@ void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); void bt_mesh_store_label(void); +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len); + void bt_mesh_clear_role(void); void bt_mesh_clear_net(void); void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); diff --git a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c index ca3ac144ef5d..f539c0a35af4 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c @@ -17,7 +17,7 @@ enum settings_type { SETTINGS_CORE, #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE SETTINGS_UID, -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ }; struct settings_context { @@ -62,15 +62,20 @@ static struct settings_context settings_ctx[] = { int bt_mesh_settings_nvs_open(const char* name, bt_mesh_nvs_handle_t *handle) { + assert(name); + BT_DBG("SettingsNVSOpen, Name %s", name); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION return nvs_open_from_partition(CONFIG_BLE_MESH_PARTITION_NAME, name, NVS_READWRITE, handle); -#else +#else /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ return nvs_open(name, NVS_READWRITE, handle); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } void bt_mesh_settings_nvs_close(bt_mesh_nvs_handle_t handle) { + BT_DBG("SettingsNVSClose, Handle %lu", handle); + nvs_close(handle); } @@ -79,6 +84,8 @@ void bt_mesh_settings_init_foreach(void) int err = 0; int i; + BT_DBG("SettingsInitForeach"); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME); if (err != ESP_OK) { @@ -134,6 +141,8 @@ void bt_mesh_settings_deinit_foreach(bool erase) { int i; + BT_DBG("SettingsDeinitForeach, Erase %u", erase); + for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) { struct settings_context *ctx = &settings_ctx[i]; @@ -152,7 +161,7 @@ void bt_mesh_settings_deinit_foreach(bool erase) #if CONFIG_BLE_MESH_SPECIFIC_PARTITION nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -161,6 +170,8 @@ int bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t *handle) int err = 0; int i; + BT_DBG("SettingsDirectOpen"); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME); if (err != ESP_OK) { @@ -178,6 +189,8 @@ int bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t *handle) return -EIO; } + BT_DBG("%u: NVSName %s Handle %lu", i, ctx->nvs_name, ctx->handle); + if (i == SETTINGS_CORE && handle) { *handle = ctx->handle; } @@ -190,25 +203,30 @@ void bt_mesh_settings_direct_close(void) { int i; + BT_DBG("SettingsDirectClose"); + for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) { bt_mesh_settings_nvs_close(settings_ctx[i].handle); } #if CONFIG_BLE_MESH_SPECIFIC_PARTITION nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } /* API used to get BLE Mesh related nvs handle */ static inline bt_mesh_nvs_handle_t settings_get_nvs_handle(enum settings_type type) { + BT_DBG("SettingsGetNVSHandle, Type %u", type); + #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE if (type == SETTINGS_CORE) { extern bt_mesh_nvs_handle_t get_core_settings_handle(void); return get_core_settings_handle(); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ + return settings_ctx[type].handle; } @@ -218,12 +236,8 @@ static int settings_save(bt_mesh_nvs_handle_t handle, const char *key, const uin { int err = 0; - if (key == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return -EINVAL; - } - - BT_DBG("nvs %s, key %s", val ? "set" : "erase", key); + BT_DBG("Settings%s, Handle %lu Len %lu Key %s", + val ? "Store" : "Erase", handle, len, key); if (val) { err = nvs_set_blob(handle, key, val, len); @@ -236,7 +250,7 @@ static int settings_save(bt_mesh_nvs_handle_t handle, const char *key, const uin } if (err != ESP_OK) { BT_ERR("Failed to %s %s data (err %d)", - val ? "set" : "erase", key, err); + val ? "set" : "erase", key, err); return -EIO; } @@ -262,6 +276,10 @@ int bt_mesh_save_settings(bt_mesh_nvs_handle_t handle, const char *key, int bt_mesh_save_core_settings(const char *key, const uint8_t *val, size_t len) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("SaveCoreSettings, Handle %lu Len %lu Key %s", handle, len, key); + return bt_mesh_save_settings(handle, key, val, len); } @@ -269,26 +287,39 @@ int bt_mesh_save_core_settings(const char *key, const uint8_t *val, size_t len) int bt_mesh_save_uid_settings(const char *key, const uint8_t *val, size_t len) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("SaveUIDSettings, Handle %lu Len %lu Key %s", handle, len, key); + return bt_mesh_save_settings(handle, key, val, len); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ int bt_mesh_erase_settings(bt_mesh_nvs_handle_t handle, const char *key) { + assert(key); + BT_DBG("EraseSettings, Handle %lu Key %s", handle, key); + return bt_mesh_save_settings(handle, key, NULL, 0); } int bt_mesh_erase_core_settings(const char *key) { + assert(key); + BT_DBG("EraseCoreSettings, Key %s", key); + return bt_mesh_save_core_settings(key, NULL, 0); } #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE int bt_mesh_erase_uid_settings(const char *name) { + assert(name); + BT_DBG("EraseUIDSettings, Name %s", name); + return bt_mesh_save_uid_settings(name, NULL, 0); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to load BLE Mesh related settings */ @@ -297,10 +328,9 @@ static int settings_load(bt_mesh_nvs_handle_t handle, const char *key, { int err = 0; - if (key == NULL || buf == NULL || exist == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return -EINVAL; - } + BT_DBG("SettingsLoad, Handle %lu Key %s", handle, key); + + assert(buf && exist); err = nvs_get_blob(handle, key, buf, &buf_len); if (err != ESP_OK) { @@ -331,6 +361,10 @@ int bt_mesh_load_settings(bt_mesh_nvs_handle_t handle, const char *key, int bt_mesh_load_core_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("LoadCoreSettings, Handle %lu Key %s", handle, key); + return bt_mesh_load_settings(handle, key, buf, buf_len, exist); } @@ -338,9 +372,13 @@ int bt_mesh_load_core_settings(const char *key, uint8_t *buf, size_t buf_len, bo int bt_mesh_load_uid_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("LoadUIDSettings, Handle %lu Key %s", handle, key); + return bt_mesh_load_settings(handle, key, buf, buf_len, exist); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to get length of BLE Mesh related settings */ @@ -349,10 +387,7 @@ static size_t settings_get_length(bt_mesh_nvs_handle_t handle, const char *key) size_t len = 0U; int err = 0; - if (key == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return 0; - } + BT_DBG("SettingsGetLength, Handle %lu Key %s", handle, key); err = nvs_get_blob(handle, key, NULL, &len); if (err != ESP_OK) { @@ -362,6 +397,8 @@ static size_t settings_get_length(bt_mesh_nvs_handle_t handle, const char *key) return 0; } + BT_DBG("Len %lu", len); + return len; } @@ -419,6 +456,10 @@ struct net_buf_simple *bt_mesh_get_settings_item(bt_mesh_nvs_handle_t handle, co struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("GetCoreSettingsItem, Handle %lu Key %s", handle, key); + return bt_mesh_get_settings_item(handle, key); } @@ -426,9 +467,13 @@ struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key) struct net_buf_simple *bt_mesh_get_uid_settings_item(const char *key) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("GetUIDSettingsItem, Handle %lu Key %s", handle, key); + return bt_mesh_get_settings_item(handle, key); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to check if the settings item exists */ @@ -438,6 +483,8 @@ bool bt_mesh_is_settings_item_exist(struct net_buf_simple *buf, const uint16_t v size_t length = 0U; int i; + BT_DBG("IsSettingsItemExist, Val 0x%04x", val); + if (!buf) { return false; } @@ -508,6 +555,10 @@ int bt_mesh_add_settings_item(bt_mesh_nvs_handle_t handle, const char *key, cons int bt_mesh_add_core_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("AddCoreSettingsItem, Handle %lu Val 0x%04x Key %s", handle, val, key); + return bt_mesh_add_settings_item(handle, key, val); } @@ -515,9 +566,13 @@ int bt_mesh_add_core_settings_item(const char *key, const uint16_t val) int bt_mesh_add_uid_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("AddUIDSettingsItem, Handle %lu Val 0x%04x Key %s", handle, val, key); + return bt_mesh_add_settings_item(handle, key, val); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to remove the settings item */ @@ -580,6 +635,10 @@ int bt_mesh_remove_settings_item(bt_mesh_nvs_handle_t handle, const char *key, c int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("RemoveCoreSettingsItem, Val 0x%04x Key %s", val, key); + return bt_mesh_remove_settings_item(handle, key, val); } @@ -587,14 +646,21 @@ int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val) int bt_mesh_remove_uid_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("RemoveUIDSettingsItem, Val 0x%04x Key %s", val, key); + return bt_mesh_remove_settings_item(handle, key, val); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ int bt_mesh_settings_erase_key(bt_mesh_nvs_handle_t handle, const char *key) { int err = 0; + assert(key); + BT_DBG("SettingsEraseKey, Handle %lu Key %s", handle, key); + err = nvs_erase_key(handle, key); if (err != ESP_OK) { if (err == ESP_ERR_NVS_NOT_FOUND) { @@ -618,6 +684,8 @@ int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle) { int err = 0; + BT_DBG("SettingsEraseAll, Handle %lu", handle); + err = nvs_erase_all(handle); if (err != ESP_OK) { BT_ERR("Failed to erase all (err %d)", err); @@ -632,4 +700,5 @@ int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle) return 0; } + #endif /* CONFIG_BLE_MESH_SETTINGS */ diff --git a/components/bt/esp_ble_mesh/core/storage/settings_uid.c b/components/bt/esp_ble_mesh/core/storage/settings_uid.c index 511709f1ecdc..c6bbcf236e51 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_uid.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_uid.c @@ -38,15 +38,22 @@ static int settings_direct_erase(uint8_t index); static inline bool settings_uid_empty(struct settings_uid *uid) { - return (uid->id[0] == '\0') ? true : false; + bool empty = (uid->id[0] == '\0') ? true : false; + + BT_DBG("SettingsUIDEmpty, Empty %u", empty); + + return empty; } bt_mesh_nvs_handle_t get_core_settings_handle(void) { int i; + BT_DBG("GetCoreSettingsHandle"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (user_ids[i].open) { + BT_DBG("I %u Handle %lu", i, user_ids[i].handle); return user_ids[i].handle; } } @@ -59,6 +66,8 @@ int settings_uid_init(void) { int i; + BT_DBG("SettingsUIDInit"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { memset(&user_ids[i], 0, sizeof(struct settings_uid)); user_ids[i].handle = INVALID_SETTINGS_HANDLE; @@ -76,6 +85,8 @@ int settings_uid_load(void) int err = 0; int i; + BT_DBG("SettingsUIDLoad"); + /* Before using user id to search settings, we need to * restore all the settings user_ids properly. */ @@ -114,6 +125,8 @@ int settings_uid_deinit(bool erase) { int i; + BT_DBG("SettingsUIDDeinit, Erase %u", erase); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { memset(&user_ids[i], 0, offsetof(struct settings_uid, handle)); /* Can not reset handle here, since it will be used @@ -128,6 +141,8 @@ int settings_uid_erase(void) { int i; + BT_DBG("SettingsUIDErase"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (user_ids[i].open == true) { /* When a nvs namespace is open, which means it is @@ -158,6 +173,8 @@ static int settings_direct_erase(uint8_t index) char name[16] = {'\0'}; int err = 0; + BT_DBG("SettingsDirectErase, Index %u", index); + sprintf(name, "%s_%02x", "mesh_core", index); /* Get handle for core settings */ @@ -191,6 +208,8 @@ static uint8_t settings_index_get(const char *id, uint8_t *index) uint8_t idx = 0; int i; + BT_DBG("SettingsIndexGet"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (strlen(user_ids[i].id) != strlen(id)) { continue; @@ -206,6 +225,8 @@ static uint8_t settings_index_get(const char *id, uint8_t *index) idx = INVALID_SETTINGS_INDEX; } + BT_DBG("Index %u", idx); + if (index) { *index = idx; } @@ -219,6 +240,8 @@ static int settings_open(uint8_t index) int err = 0; int i; + BT_DBG("SettingsOpen, Index %u UID %s", index, uid->id); + /* Check if the nvs namespace is already open */ if (uid->open == true) { BT_WARN("Settings already open, index %d", index); @@ -251,8 +274,6 @@ static int settings_open(uint8_t index) sprintf(uid->id, "%04x", index); } - BT_INFO("Open settings, index %d, uid %s", index, uid->id); - sprintf(name, "mesh/id/%04x", index); err = bt_mesh_save_uid_settings(name, (const uint8_t *)uid->id, SETTINGS_UID_SIZE); if (err) { @@ -288,6 +309,8 @@ static int settings_open(uint8_t index) int bt_mesh_provisioner_open_settings_with_index(uint8_t index) { + BT_DBG("PvnrOpenSettingsWithIndex, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -301,6 +324,8 @@ int bt_mesh_provisioner_open_settings_with_uid(const char *id, uint8_t *index) uint8_t idx = 0; int i; + BT_DBG("PvnrOpenSettingsWithUID"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -328,6 +353,8 @@ int bt_mesh_provisioner_open_settings_with_uid(const char *id, uint8_t *index) idx = i; } + BT_DBG("Index %u", idx); + return settings_open(idx); } @@ -337,13 +364,14 @@ static int settings_close(uint8_t index, bool erase) char name[16] = {'\0'}; int err = 0; + BT_DBG("SettingsClose"); + BT_DBG("Index %u Erase %u UID %s", index, erase, uid->id); + if (uid->open == false) { BT_ERR("Settings not open, index %d", index); return -EIO; } - BT_INFO("Close settings, index %d, uid %s", index, uid->id); - /* Disable Provisioner firstly */ err = bt_mesh_provisioner_disable(BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT); if (err && err != -EALREADY) { @@ -378,6 +406,8 @@ static int settings_close(uint8_t index, bool erase) int bt_mesh_provisioner_close_settings_with_index(uint8_t index, bool erase) { + BT_DBG("PvnrCloseSettingsWithIndex, Index %u Erase %u", index, erase); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -390,6 +420,8 @@ int bt_mesh_provisioner_close_settings_with_uid(const char *id, bool erase, uint { uint8_t idx = 0; + BT_DBG("PvnrCloseSettingsWithUID, Erase %u", erase); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -401,6 +433,8 @@ int bt_mesh_provisioner_close_settings_with_uid(const char *id, bool erase, uint return -ENODEV; } + BT_DBG("Index %u ID %s", idx, id); + return settings_close(idx, erase); } @@ -412,13 +446,13 @@ static int settings_delete(uint8_t index) */ struct settings_uid *uid = &user_ids[index]; + BT_DBG("SettingsDelete, Index %u UID %s", index, uid->id); + if (uid->open == true) { BT_ERR("Settings being used, index %d", index); return -EBUSY; } - BT_INFO("Delete settings, index %d, uid %s", index, uid->id); - settings_direct_erase(index); memset(uid, 0, sizeof(struct settings_uid)); @@ -429,6 +463,8 @@ static int settings_delete(uint8_t index) int bt_mesh_provisioner_delete_settings_with_index(uint8_t index) { + BT_DBG("PvnrDeleteSettingsWithIndex, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -441,6 +477,8 @@ int bt_mesh_provisioner_delete_settings_with_uid(const char *id, uint8_t *index) { uint8_t idx = 0; + BT_DBG("PvnrDeleteSettingsWithUID"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -452,16 +490,22 @@ int bt_mesh_provisioner_delete_settings_with_uid(const char *id, uint8_t *index) return -ENODEV; } + BT_DBG("Index %u ID %s", idx, id); + return settings_delete(idx); } const char *bt_mesh_provisioner_get_settings_uid(uint8_t index) { + BT_DBG("PvnrGetSettingsUID, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return NULL; } + BT_DBG("ID %s", user_ids[index].id); + return user_ids[index].id; } @@ -469,6 +513,8 @@ uint8_t bt_mesh_provisioner_get_settings_index(const char *id) { uint8_t idx = 0; + BT_DBG("PvnrGetSettingsIndex"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return INVALID_SETTINGS_INDEX; @@ -479,6 +525,8 @@ uint8_t bt_mesh_provisioner_get_settings_index(const char *id) BT_ERR("Settings uid %s not exists", id); } + BT_DBG("Index %u ID %s", idx, id); + return idx; } @@ -487,12 +535,16 @@ uint8_t bt_mesh_provisioner_get_free_settings_count(void) uint8_t count = 0; int i; + BT_DBG("PvnrGetFreeSettingsCount"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (settings_uid_empty(&user_ids[i])) { count++; } } + BT_DBG("Count %u", count); + return count; } #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ @@ -503,6 +555,8 @@ int bt_mesh_provisioner_direct_erase_settings(void) bt_mesh_nvs_handle_t handle = 0; int err = 0; + BT_DBG("PvnrDirectEraseSettings"); + err = bt_mesh_settings_direct_open(&handle); if (err) { return err; @@ -514,9 +568,9 @@ int bt_mesh_provisioner_direct_erase_settings(void) } bt_mesh_erase_uid_settings("mesh/uid"); -#else +#else /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ err = bt_mesh_settings_erase_all(handle); -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ bt_mesh_settings_direct_close(); return err; diff --git a/components/bt/esp_ble_mesh/core/test.c b/components/bt/esp_ble_mesh/core/test.c index 3d3cc3bbd902..6433f9c0d4c9 100644 --- a/components/bt/esp_ble_mesh/core/test.c +++ b/components/bt/esp_ble_mesh/core/test.c @@ -41,6 +41,8 @@ int bt_mesh_device_auto_enter_network(struct bt_mesh_device_network_info *info) int i, j, k; int err = 0; + BT_DBG("DeviceAutoEnterNetwork"); + if (info == NULL || !BLE_MESH_ADDR_IS_UNICAST(info->unicast_addr) || !BLE_MESH_ADDR_IS_GROUP(info->group_addr)) { return -EINVAL; @@ -139,6 +141,8 @@ int bt_mesh_test_update_white_list(struct bt_mesh_white_list *wl) { int err = 0; + BT_DBG("TestUpdateWhiteList"); + if (wl == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -157,7 +161,7 @@ int bt_mesh_test_update_white_list(struct bt_mesh_white_list *wl) int bt_mesh_test_start_scanning(bool wl_en) { - BT_INFO("Scan with filter policy %s", wl_en ? "enabled" : "disabled"); + BT_DBG("TestStartScanning, wl_en %u", wl_en); if (wl_en) { return bt_mesh_scan_with_wl_enable(); @@ -168,6 +172,8 @@ int bt_mesh_test_start_scanning(bool wl_en) int bt_mesh_test_stop_scanning(void) { + BT_DBG("TestStopScanning"); + return bt_mesh_scan_disable(); } #endif /* CONFIG_BLE_MESH_TEST_USE_WHITE_LIST */ @@ -181,6 +187,8 @@ void bt_mesh_test_register_net_pdu_cb(bt_mesh_test_net_pdu_cb_t cb) void bt_mesh_test_set_seq(uint32_t seq) { + BT_DBG("TestSetSeq, Seq 0x%06x", seq); + if (seq > 0xFFFFFF) { BT_ERR("Invalid SEQ 0x%08x", seq); return; diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 88a6158b89e0..204854e241c6 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -29,7 +29,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* The transport layer needs at least three buffers for itself to avoid * deadlocks. Ensure that there are a sufficient number of advertising @@ -58,24 +58,24 @@ _Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3) /* Number of retransmit attempts (after the initial transmit) per segment */ #define SEG_RETRANSMIT_ATTEMPTS 4 +/* How long to wait for available buffers before giving up */ +#define BUF_TIMEOUT K_NO_WAIT + /* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". * We use 400 since 300 is a common send duration for standard HCI, and we * need to have a timeout that's bigger than that. */ #define SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) (K_MSEC(400) + 50 * (tx)->ttl) + /* When sending to a group, the messages are not acknowledged, and there's no * reason to delay the repetitions significantly. Delaying by more than 0 ms * to avoid flooding the network. */ #define SEG_RETRANSMIT_TIMEOUT_GROUP K_MSEC(50) -#define SEG_RETRANSMIT_TIMEOUT(tx) \ - (BLE_MESH_ADDR_IS_UNICAST((tx)->dst) ? \ - SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) : \ - SEG_RETRANSMIT_TIMEOUT_GROUP) - -/* How long to wait for available buffers before giving up */ -#define BUF_TIMEOUT K_NO_WAIT +#define SEG_RETRANSMIT_TIMEOUT(tx) (BLE_MESH_ADDR_IS_UNICAST((tx)->dst) ? \ + SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) : \ + SEG_RETRANSMIT_TIMEOUT_GROUP) struct seg_info { uint8_t ctl:1; /* Control message */ @@ -160,6 +160,8 @@ static inline void bt_mesh_seg_rx_unlock(void) uint8_t bt_mesh_get_seg_rtx_num(void) { + BT_DBG("SegRTXNum %u", SEG_RETRANSMIT_ATTEMPTS); + return SEG_RETRANSMIT_ATTEMPTS; } @@ -174,75 +176,10 @@ int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) struct seg_tx tx = { .ttl = ttl, }; - return SEG_RETRANSMIT_TIMEOUT_UNICAST(&tx); -} - -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - if (bt_mesh_is_provisioned()) { -#if CONFIG_BLE_MESH_NODE - if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { - for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.app_keys[i].app_idx == app_idx) { - return &bt_mesh.app_keys[i]; - } - } - } else { - return bt_mesh_fast_prov_app_key_find(app_idx); - } -#endif - } else if (bt_mesh_is_provisioner_en()) { -#if CONFIG_BLE_MESH_PROVISIONER - for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { - if (bt_mesh.p_app_keys[i] && - bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.p_app_keys[i]->app_idx == app_idx) { - return bt_mesh.p_app_keys[i]; - } - } -#endif - } - - return NULL; -} - -int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint16_t dst) -{ - struct bt_mesh_app_key *app_key = NULL; - if (app_idx == BLE_MESH_KEY_DEV) { - *key = bt_mesh_dev_key_get(dst); - if (!*key) { - BT_ERR("DevKey of 0x%04x not found", dst); - return -EINVAL; - } - - *aid = 0U; - return 0; - } - - if (!subnet) { - BT_ERR("Invalid subnet"); - return -EINVAL; - } + BT_DBG("SegRTXTimeout, TTL %u", ttl); - app_key = bt_mesh_app_key_get(app_idx); - if (!app_key) { - BT_ERR("AppKey 0x%04x not found", app_idx); - return -ENOENT; - } - - if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { - *key = app_key->keys[1].val; - *aid = app_key->keys[1].id; - } else { - *key = app_key->keys[0].val; - *aid = app_key->keys[0].id; - } - - return 0; + return SEG_RETRANSMIT_TIMEOUT_UNICAST(&tx); } static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, @@ -252,8 +189,10 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, struct net_buf *buf = NULL; enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", - tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + BT_DBG("SendUnseg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x CtlOp 0x%02x SduLen %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, + ctl_op ? *ctl_op : 0xFF, sdu->len); #if CONFIG_BLE_MESH_EXT_ADV #if CONFIG_BLE_MESH_LONG_PACKET @@ -308,13 +247,14 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, tx->src, tx->ctx->addr, NULL, 1)) { + BT_WARN("NoSpaceInFrndQueue, SegCount 1"); + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - BT_ERR("Not enough space in Friend Queue"); + BT_ERR("NotSentToUnicast"); net_buf_unref(buf); return -ENOBUFS; } - BT_WARN("No space in Friend Queue"); goto send; } @@ -324,6 +264,8 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount 1"); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; @@ -336,19 +278,25 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, static inline uint8_t seg_len(struct seg_info *si) { + uint8_t len = 0; + if (si->ctl) { - return + len = #if CONFIG_BLE_MESH_LONG_PACKET si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : #endif BLE_MESH_CTL_SEG_SDU_MAX; - } - - return + } else { + len = #if CONFIG_BLE_MESH_LONG_PACKET - si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : #endif - BLE_MESH_APP_SEG_SDU_MAX; + BLE_MESH_APP_SEG_SDU_MAX; + } + + BT_DBG("SegLen %u", len); + + return len; } bool bt_mesh_tx_in_progress(void) @@ -357,15 +305,18 @@ bool bt_mesh_tx_in_progress(void) for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (seg_tx[i].nack_count) { + BT_DBG("SegTxInProgress"); return true; } } + BT_DBG("SegTxNotInProgress"); return false; } static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { + BT_DBG("SegTxDone, SegIdx %u", seg_idx); /* If the data is sent to itself, then last seg's ref count be equal to 3 */ if (((IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) || (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en())) && @@ -375,15 +326,17 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL); } - /** - * When cancelling a segment that is still in the adv sending queue, `tx->seg_pending` - * must else be decremented by one. More detailed information - * can be found in BLEMESH24-26. + /* When cancelling a segment that is still in the adv sending queue, + * the `tx->seg_pending` must be decremented by one. + * More details could be found in BLEMESH24-26. */ if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 1, 0)) { + BT_DBG("SegPendingDec %u", tx->seg_pending); tx->seg_pending--; } + BT_DBG("NackCountDec %u", tx->nack_count); + net_buf_unref(tx->seg[seg_idx]); tx->seg[seg_idx] = NULL; tx->nack_count--; @@ -393,6 +346,8 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; + BT_DBG("SegTxReset"); + bt_mesh_seg_tx_lock(tx); k_delayed_work_cancel(&tx->rtx_timer); @@ -417,6 +372,7 @@ static void seg_tx_reset(struct seg_tx *tx) if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { BT_DBG("Proceeding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ @@ -431,6 +387,8 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) const struct bt_mesh_send_cb *cb = tx->cb; void *cb_data = tx->cb_data; + BT_DBG("SegTxComplete, Err %d", err); + seg_tx_reset(tx); /* TODO: notify the completion of sending segmented message */ @@ -442,35 +400,43 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) static void schedule_retransmit(struct seg_tx *tx) { - bt_mesh_seg_tx_lock(tx); - /* It's possible that a segment broadcast hasn't finished, - * but the tx are already released. Only the seg_pending - * of this segment remains unprocessed. So, here, we - * determine if the tx are released by checking if the - * destination (dst) is unassigned, and then process - * the seg_pending of this segment. + /* It's possible that a segment broadcast hasn't finished, but the tx + * has already been released. Only the seg_pending of this segment + * remains unprocessed. + * So, here we determine if the tx are released by checking if the + * destination (dst) is unassigned, and then process the seg_pending + * of this segment. * See BLEMESH25-92 for details */ + + BT_DBG("ScheduleRetransmit, Dst 0x%04x", tx->dst); + + bt_mesh_seg_tx_lock(tx); + if (tx->dst == BLE_MESH_ADDR_UNASSIGNED) { + BT_DBG("SegPending %u", tx->seg_pending); + if (tx->seg_pending) { tx->seg_pending--; } - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } + BT_DBG("SegPending %u Attempts %u", tx->seg_pending, tx->attempts); + if (--tx->seg_pending) { - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } if (!BLE_MESH_ADDR_IS_UNICAST(tx->dst) && !tx->attempts) { - BT_INFO("Complete tx sdu to group"); + BT_INFO("TxSduToGroupDone"); + seg_tx_complete(tx, 0); - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } k_delayed_work_submit(&tx->rtx_timer, SEG_RETRANSMIT_TIMEOUT(tx)); + +end: bt_mesh_seg_tx_unlock(tx); } @@ -478,6 +444,8 @@ static void seg_first_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegFirstSendStart, Err %d", err); + if (tx->cb && tx->cb->start) { tx->cb->start(duration, err, tx->cb_data); } @@ -487,6 +455,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendStart, Err %d", err); + /* If there's an error in transmitting the 'sent' callback will never * be called. Make sure that we kick the retransmit timer also in this * case since otherwise we risk the transmission of becoming stale. @@ -500,6 +470,8 @@ static void seg_sent(int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSent, Err %d", err); + schedule_retransmit(tx); } @@ -517,17 +489,19 @@ static void seg_tx_send_unacked(struct seg_tx *tx) { int i, err = 0; + BT_DBG("SegTxSendUnacked, Attempts %u", tx->attempts); + bt_mesh_seg_tx_lock(tx); if (!(tx->attempts--)) { BT_WARN("Ran out of retransmit attempts"); + bt_mesh_seg_tx_unlock(tx); + seg_tx_complete(tx, -ETIMEDOUT); return; } - BT_INFO("Attempts: %u", tx->attempts); - for (i = 0; i <= tx->seg_n; i++) { struct net_buf *seg = tx->seg[i]; @@ -540,9 +514,10 @@ static void seg_tx_send_unacked(struct seg_tx *tx) continue; } - tx->seg_pending++; + BT_INFO("SegPendingInc %u", tx->seg_pending); + BT_INFO("SegResend %u/%u Cred %u", i, tx->seg_n, tx->cred); - BT_INFO("Resending %u/%u, cred 0x%02x", i, tx->seg_n, tx->cred); + tx->seg_pending++; /* TODO: * tx->new_key should be replaced with sub->kr_flag, @@ -553,8 +528,10 @@ static void seg_tx_send_unacked(struct seg_tx *tx) &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Sending segment failed"); + BT_ERR("ResendSegFailed, Err %d", err); + bt_mesh_seg_tx_unlock(tx); + seg_tx_complete(tx, -EIO); return; } @@ -567,6 +544,8 @@ static void seg_retransmit(struct k_work *work) { struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, rtx_timer); + BT_DBG("SegRetransmit"); + seg_tx_send_unacked(tx); } @@ -583,20 +562,24 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, int err = 0; int i; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + BT_DBG("SendSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x Aszmic %u SduLen %u", net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, net_tx->aszmic, sdu->len); for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { - if (!seg_tx[i].nack_count && - /* In some critical conditions, the tx might be - * reset before a segment broadcast is finished. - * If this happens, the seg_pending of the segment - * hasn't been processed. To avoid assigning this - * uncleared tx to a new message, extra checks for - * seg_pending being 0 are added. See BLEMESH25-92 - * for details.*/ - !seg_tx[i].seg_pending) { + /* In some critical conditions, the tx might be reset before + * a segment transmission is finished. + * If this happens, the seg_pending of the segment will not + * be processed. + * And to avoid assigning this uncleared tx to a new message, + * extra checks for seg_pending being 0 are added. + * See BLEMESH25-92 for details. + */ + BT_DBG("Seg%u: NackCount %u SegPending %u", + i, seg_tx[i].nack_count, seg_tx[i].seg_pending); + + if (!seg_tx[i].nack_count && !seg_tx[i].seg_pending) { tx = &seg_tx[i]; break; } @@ -652,15 +635,16 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; - BT_DBG("SeqZero 0x%04x", seq_zero); + BT_DBG("SegHdr 0x%02x SegN %u NackCount %u NewKey %u TTL %u SeqZero 0x%04x", + seg_hdr, tx->seg_n, tx->nack_count, tx->new_key, tx->ttl, seq_zero); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, tx->dst, &tx->seq_auth, tx->seg_n + 1) && BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { - BT_ERR("Not enough space in Friend Queue for %u segments", - tx->seg_n + 1); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", tx->seg_n + 1); + seg_tx_reset(tx); return -ENOBUFS; } @@ -726,6 +710,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, type = BLE_MESH_FRIEND_PDU_PARTIAL; } + BT_DBG("FrndPDUType %u", type); + if (bt_mesh_friend_enqueue_tx(net_tx, type, &tx->seq_auth, tx->seg_n + 1, @@ -734,6 +720,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount %u", tx->seg_n + 1); + net_buf_unref(seg); continue; } @@ -741,14 +729,16 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, tx->seg[seg_o] = net_buf_ref(seg); - BT_DBG("Sending %u/%u", seg_o, tx->seg_n); + BT_INFO("SegPendingInc %u", tx->seg_pending); + BT_INFO("SegSend %u/%u Cred %u", seg_o, tx->seg_n, tx->cred); + tx->seg_pending++; err = bt_mesh_net_send(net_tx, seg, seg_o ? &seg_sent_cb : &first_sent_cb, tx); if (err) { - BT_ERR("Sending segment failed (err %d)", err); + BT_ERR("SendSegFailed, Err %d", err); break; } @@ -757,6 +747,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * which will be used for retransmission later. */ if (tx->cred != net_tx->ctx->send_cred) { + BT_INFO("OldCred %u NewCred %u", tx->cred, net_tx->ctx->send_cred); tx->cred = net_tx->ctx->send_cred; } } @@ -770,7 +761,10 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* This can happen if segments only went into the Friend Queue */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) { + BT_DBG("OnlyToFrndQueue"); + seg_tx_reset(tx); + /* If there was a callback notify sending immediately since * there's no other way to track this (at least currently) * with the Friend Queue. @@ -794,6 +788,8 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; + BT_DBG("transcend"); + if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); return -EINVAL; @@ -819,9 +815,9 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, } #endif - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + tx->sub->net_idx, tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); err = bt_mesh_upper_key_get(tx->sub, tx->ctx->app_idx, &key, &aid, tx->ctx->addr); @@ -839,7 +835,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->aszmic = 1U; } - BT_INFO("%s, send_tag 0x%02x, send_szmic %d, aszmic %d", + BT_INFO("%s, Tag 0x%02x Szmic %u Aszmic %u", bt_mesh_tag_send_segmented(tx->ctx->send_tag) ? "Seg" : "Unseg", tx->ctx->send_tag, tx->ctx->send_szmic, tx->aszmic); @@ -854,7 +850,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->ctx->addr, bt_mesh.seq, BLE_MESH_NET_IVI_TX); if (err) { - BT_ERR("Encrypt failed (err %d)", err); + BT_ERR("AppEncryptFailed, Err %d", err); return err; } @@ -868,7 +864,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, static void revoke_dev_key(const uint8_t *dev_key) { if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { - BT_INFO("Revoke Device Key"); + BT_INFO("RevokeDevKey"); memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); memset(bt_mesh.dev_key_ca, 0, 16); @@ -889,8 +885,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, size_t i = 0U; int err = 0; - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("SduRecv"); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1 + APP_MIC_LEN(aszmic)) { BT_ERR("Too short SDU + MIC (len %u)", buf->len); @@ -929,7 +926,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, dev_key = bt_mesh_rx_devkey_get(i, rx->ctx.addr); if (!dev_key) { - BT_DBG("DevKey not found"); + BT_DBG("DevKeyNotFound"); continue; } @@ -940,6 +937,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, rx->ctx.recv_dst, seq, BLE_MESH_NET_IVI_RX(rx)); if (err) { + BT_DBG("DevKeyNotDecrypt"); continue; } @@ -965,6 +963,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } BT_WARN("Unable to decrypt with DevKey"); + bt_mesh_free_buf(sdu); return -ENODEV; } @@ -977,7 +976,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, key = bt_mesh_rx_appkey_get(i); if (!key) { - BT_DBG("AppKey not found"); + BT_DBG("AppKeyNotFound"); continue; } @@ -1011,8 +1010,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, bt_hex(sdu->data, sdu->len)); if (err) { - BT_DBG("Unable to decrypt with AppKey 0x%03x", - key->app_idx); + BT_DBG("AppKeyNotDecrypt, AppIdx 0x%04x", key->app_idx); continue; } @@ -1024,8 +1022,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } if (rx->local_match) { - BT_WARN("No matching AppKey"); + BT_WARN("NoMatchAppKey"); } + bt_mesh_free_buf(sdu); return 0; } @@ -1035,6 +1034,8 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add struct seg_tx *tx = NULL; int i; + BT_DBG("SegTxLookup, SeqZero 0x%04x OBO %u Addr 0x%04x", seq_zero, obo, addr); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { tx = &seg_tx[i]; @@ -1043,6 +1044,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add } if (tx->dst == addr) { + BT_DBG("SegTxFound, Dst 0x%04x", addr); return tx; } @@ -1052,6 +1054,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add * responding and therefore accept the message. */ if (obo && tx->nack_count == tx->seg_n + 1) { + BT_DBG("SegTxOboFound, Dst 0x%04x", addr); tx->dst = addr; return tx; } @@ -1064,11 +1067,13 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, struct net_buf_simple *buf, uint64_t *seq_auth) { struct seg_tx *tx = NULL; + uint16_t seq_zero = 0U; unsigned int bit = 0; uint32_t ack = 0U; - uint16_t seq_zero = 0U; uint8_t obo = 0U; + BT_DBG("TransAck"); + if (buf->len != 6) { BT_ERR("Malformed Segment Ack (len %u)", buf->len); return -EINVAL; @@ -1087,7 +1092,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, ack = net_buf_simple_pull_be32(buf); - BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + BT_DBG("OBO %u SeqZero 0x%04x Ack 0x%08lx", obo, seq_zero, ack); tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr); if (!tx) { @@ -1118,6 +1123,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { BT_INFO("Seg %u/%u acked", bit - 1, tx->seg_n); + bt_mesh_seg_tx_lock(tx); seg_tx_done(tx, bit - 1); bt_mesh_seg_tx_unlock(tx); @@ -1142,6 +1148,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, uint8_t init_ttl = 0U, hops = 0U; uint16_t feat = 0U; + BT_DBG("TransHeartbeat"); + if (buf->len != 3) { BT_ERR("Malformed heartbeat message (len %u)", buf->len); return -EINVAL; @@ -1158,9 +1166,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, hops = (init_ttl - rx->ctx.recv_ttl + 1); - BT_INFO("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); + BT_INFO("Src 0x%04x TTL %u InitTTL %u Hops %u Feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, feat); if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { bt_mesh_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); @@ -1178,7 +1185,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, { uint8_t ctl_op = TRANS_CTL_OP(&hdr); - BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + BT_DBG("CTLRecv, OpCode 0x%02x Len %u", ctl_op, buf->len); BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, @@ -1195,6 +1202,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Only acks and heartbeats may need processing without local_match */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return 0; } @@ -1209,7 +1217,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, case TRANS_CTL_OP_PATH_REQ_SOLIC: return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { switch (ctl_op) { @@ -1262,7 +1270,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, { uint8_t hdr = 0U; - BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + BT_DBG("TransUnseg, AKF %u AID 0x%02x", AKF(buf->data), AID(buf->data)); if (buf->len < 1) { BT_ERR("Too small unsegmented PDU"); @@ -1270,7 +1278,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, } if (bt_mesh_rpl_check(rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, rx->seq); return -EINVAL; } @@ -1283,6 +1291,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, /* SDUs must match a local element or an LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } @@ -1308,6 +1317,8 @@ static inline int32_t ack_timeout(struct seg_rx *rx) /* 100 ms for every not yet received segment */ to += K_MSEC(((rx->seg_n + 1) - popcount(rx->block)) * 100U); + BT_DBG("AckTimeout, TTL %u TO %ld", ttl, to); + /* Make sure we don't send more frequently than the duration for * each packet (default is 300ms). */ @@ -1320,6 +1331,8 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, { struct net_buf_simple buf = {0}; + BT_DBG("CtlSend"); + net_buf_simple_init_with_data(&buf, data, data_len); if (data_len > BLE_MESH_SDU_UNSEG_MAX) { @@ -1329,9 +1342,9 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, /* Set app_idx to unused here since CTL is only encrypted with NetKey */ tx->ctx->app_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, - tx->ctx->addr, tx->ctx->send_ttl, ctl_op); - BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL 0x%02x CTL 0x%02x", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("Len %u: %s", data_len, bt_hex(data, data_len)); if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { return send_seg(tx, &buf, cb, cb_data, &ctl_op); @@ -1363,7 +1376,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; uint8_t buf[6] = {0}; - BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + BT_DBG("SendAck, SeqZero 0x%04x Block 0x%08lx OBO %u", seq_zero, block, obo); if (bt_mesh_lpn_established()) { BT_WARN("Not sending ack when LPN is enabled"); @@ -1387,6 +1400,8 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { + BT_DBG("SegRxReset, FullReset %u", full_reset); + bt_mesh_seg_rx_lock(); k_delayed_work_cancel(&rx->ack_timer); @@ -1431,6 +1446,8 @@ static uint32_t incomplete_timeout(struct seg_rx *rx) /* The less segments being received, the shorter timeout will be used. */ timeout += K_MSEC(ttl * popcount(rx->block) * 100U); + BT_DBG("IncompleteTimeout %lu", timeout); + return MIN(timeout, K_SECONDS(60)); } @@ -1438,11 +1455,15 @@ static void seg_ack(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); + BT_DBG("SegAck, Last %lu", rx->last); + bt_mesh_seg_rx_lock(); if (k_uptime_get_32() - rx->last > incomplete_timeout(rx)) { BT_WARN("Incomplete timer expired"); + bt_mesh_seg_rx_unlock(); + seg_rx_reset(rx, false); return; } @@ -1465,6 +1486,8 @@ static void seg_ack(struct k_work *work) static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { + BT_DBG("IsSduLenOK,Len:%u,SegN:%u", seg_len, seg_n); + return ((seg_n + 1) * seg_len); } @@ -1473,6 +1496,9 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) struct seg_info si = { .ctl = ctl, }; + + BT_DBG("IsSduLenOK, CTL %u SegN %u", ctl, seg_n); + #if CONFIG_BLE_MESH_LONG_PACKET if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { si.long_pkt = 1; @@ -1489,8 +1515,13 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, { int i; + BT_DBG("SegRxFind, SeqAuth 0x%llx", *seq_auth); for (i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &rx_buf[i]; + + BT_DBG("Seg%u/%u: Src 0x%04x Dst 0x%04x SeqAuth 0x%llx", + i, rx->seg_n, rx->src, rx->dst, rx->seq_auth); + if (rx->src != net_rx->ctx.addr || rx->dst != net_rx->ctx.recv_dst) { continue; @@ -1501,9 +1532,9 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, */ #if CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH if (rx->seq_auth >= *seq_auth) { -#else +#else /* CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH */ if (rx->seq_auth == *seq_auth) { -#endif +#endif /* CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH */ return rx; } @@ -1584,6 +1615,8 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, const uint8_t *hdr, uint8_t seg_n) { + BT_DBG("IsSegRxValid"); + if (rx->hdr != *hdr || rx->seg_n != seg_n) { BT_ERR("Invalid segment for ongoing session"); return false; @@ -1624,6 +1657,8 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, } #endif + BT_DBG("SegRxAlloc, SegN %u", seg_n); + for (i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &seg_rx_buf[i]; @@ -1668,18 +1703,20 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, uint8_t seg_o = 0U; int err = 0; + BT_DBG("TransSeg"); + if (buf->len < 5) { BT_ERR("Too short segmented message (len %u)", buf->len); return -EINVAL; } if (bt_mesh_rpl_check(net_rx, &rpl)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); return -EINVAL; } - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); net_buf_simple_pull(buf, 1); @@ -1724,13 +1761,15 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, *seg_count = seg_n + 1; + BT_DBG("Src 0x%04x Dst 0x%04x SeqAuth 0x%llx SegCount %u", + net_rx->ctx.addr, net_rx->ctx.recv_dst, *seq_auth, *seg_count); + /* Look for old RX sessions */ rx = seg_rx_find(net_rx, seq_auth); if (rx) { /* Discard old SeqAuth packet */ if (rx->seq_auth > *seq_auth) { - BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", - rx->src, rx->dst); + BT_WARN("SeqAuth 0x%llx vs. 0x%llx", rx->seq_auth, *seq_auth); return -EINVAL; } @@ -1745,6 +1784,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (rx->block == BLOCK_COMPLETE(rx->seg_n)) { BT_INFO("Got segment for already complete SDU"); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1782,10 +1822,11 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, net_rx->ctx.addr, net_rx->ctx.recv_dst, seq_auth, *seg_count)) { - BT_ERR("No space in Friend Queue for %u segments", *seg_count); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, - net_rx->ctx.send_ttl, seq_auth, 0, - net_rx->friend_match); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", *seg_count); + + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, 0, net_rx->friend_match); return -ENOBUFS; } @@ -1796,7 +1837,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, * eventually be freed up and we'll be able to process * this one. */ - BT_WARN("No free slots for new incoming segmented messages, src: %04x", net_rx->ctx.addr); + BT_WARN("SegRxFull, Src %04x", net_rx->ctx.addr); return -ENOMEM; } @@ -1823,16 +1864,21 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, /* Set the expected final buffer length */ rx->buf.len = seg_n * seg_len(&si) + buf->len; + BT_DBG("Target len %u * %u + %u = %u", + seg_n, seg_len(&si), buf->len, rx->buf.len); + if ((!rx->ext && rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) #if CONFIG_BLE_MESH_LONG_PACKET || (rx->ext && rx->buf.len > BLE_MESH_EXT_RX_SDU_MAX) #endif ) { - BT_ERR("Too large SDU len"); + BT_ERR("Too large SDU len %u", rx->buf.len); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, rx->obo); + seg_rx_reset(rx, true); + return -EMSGSIZE; } } else { @@ -1860,6 +1906,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, rx->block |= BIT(seg_o); if (rx->block != BLOCK_COMPLETE(seg_n)) { + BT_DBG("FrndPDUPartial"); *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; return 0; } @@ -1880,8 +1927,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (net_rx->ctl) { err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); } else { - err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, - ASZMIC(hdr), &rx->buf); + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), + *hdr, ASZMIC(hdr), &rx->buf); } seg_rx_reset(rx, false); @@ -1891,12 +1938,14 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { - uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; struct net_buf_simple_state state = {0}; + uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; uint8_t seg_count = 0U; int err = 0; + BT_DBG("TransRecv"); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, rx->ctx.recv_dst); @@ -1904,20 +1953,21 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) rx->friend_match = false; } - BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + BT_DBG("Src 0x%04x Dst 0x%04x Seq 0x%06x FrndMatch %u", rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); /* Remove network headers */ net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + BT_DBG("PDU %u %s", buf->len, bt_hex(buf->data, buf->len)); /* If LPN mode is enabled messages are only accepted when we've * requested the Friend to send them. The messages must also * be encrypted using the Friend Credentials. */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && - bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + bt_mesh_lpn_established() && + rx->net_if == BLE_MESH_NET_IF_ADV && (!bt_mesh_lpn_waiting_update() || rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { BT_WARN("Ignoring unexpected message in Low Power mode"); @@ -1934,12 +1984,14 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) * LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); } else { seg_count = 1U; + err = trans_unseg(buf, rx, &seq_auth); } @@ -1979,6 +2031,8 @@ void bt_mesh_rx_reset(void) { int i; + BT_DBG("RxReset"); + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx_reset(&seg_rx[i], true); } @@ -1988,6 +2042,8 @@ void bt_mesh_tx_reset(void) { int i; + BT_DBG("TxReset"); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { seg_tx_reset(&seg_tx[i]); } @@ -1997,6 +2053,8 @@ void bt_mesh_rx_reset_single(uint16_t src) { int i; + BT_DBG("RxResetSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -2013,6 +2071,8 @@ void bt_mesh_tx_reset_single(uint16_t dst) { int i; + BT_DBG("TxResetSingle, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { return; } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 318b21bb0995..967b5233796b 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -160,121 +160,93 @@ static inline void bt_mesh_seg_rx_unlock(void) uint8_t bt_mesh_seg_send_interval(void) { - return (bt_mesh_get_sar_sis() + 1) * 10; + uint8_t interval = (bt_mesh_get_sar_sis() + 1) * 10; + + BT_DBG("SegSendInterval %u", interval); + + return interval; } uint8_t bt_mesh_get_seg_rtx_num(void) { - return bt_mesh_get_sar_urc(); + uint8_t num = bt_mesh_get_sar_urc(); + + BT_DBG("SegRTXNum %u", num); + + return num; } int32_t bt_mesh_seg_rtx_interval(uint16_t dst, uint8_t ttl) { + int32_t interval = 0; + if (BLE_MESH_ADDR_IS_UNICAST(dst)) { if (ttl == 0) { - return (bt_mesh_get_sar_uris() + 1) * 25; + interval = (bt_mesh_get_sar_uris() + 1) * 25; + } else { + interval = ((bt_mesh_get_sar_uris() + 1) * 25 + + (bt_mesh_get_sar_urii() + 1) * 25 * (ttl - 1)); } - - return ((bt_mesh_get_sar_uris() + 1) * 25 + - (bt_mesh_get_sar_urii() + 1) * 25 * (ttl - 1)); + } else { + interval = (bt_mesh_get_sar_mris() + 1) * 25; } - return (bt_mesh_get_sar_mris() + 1) * 25; + BT_DBG("SegRTXInterval %ld, Dst 0x%04x TTL %u", interval, dst, ttl); + + return interval; } int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) { - return bt_mesh_seg_rtx_interval(dst, ttl); + int32_t timeout = bt_mesh_seg_rtx_interval(dst, ttl); + + BT_DBG("SegRTXTimeout %ld, Dst 0x%04x TTL %u", timeout, dst, ttl); + + return timeout; } uint32_t bt_mesh_seg_discard_timeout(void) { - return K_SECONDS((bt_mesh_get_sar_dt() + 1) * 5); + uint32_t timeout = K_SECONDS((bt_mesh_get_sar_dt() + 1) * 5); + + BT_DBG("SegDiscardTimeout %lu", timeout); + + return timeout; } uint32_t bt_mesh_seg_rx_interval(void) { - return (bt_mesh_get_sar_rsis() + 1) * 10; + uint32_t interval = (bt_mesh_get_sar_rsis() + 1) * 10; + + BT_DBG("SegRxInterval %lu", interval); + + return interval; } uint32_t bt_mesh_seg_ack_timeout(uint8_t seg_n) { - float min = MIN((float)seg_n + 0.5, (float)bt_mesh_get_sar_adi() + 1.5); - return (uint32_t)(min * bt_mesh_seg_rx_interval()); -} + uint32_t timeout = 0U; + float min = 0.0; -uint32_t bt_mesh_seg_ack_period(void) -{ - float val = (float)bt_mesh_get_sar_adi() + 1.5; - return (uint32_t)(val * bt_mesh_seg_rx_interval()); -} + min = MIN((float)seg_n + 0.5, (float)bt_mesh_get_sar_adi() + 1.5); + timeout = (uint32_t)(min * bt_mesh_seg_rx_interval()); -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - if (bt_mesh_is_provisioned()) { -#if CONFIG_BLE_MESH_NODE - if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { - for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.app_keys[i].app_idx == app_idx) { - return &bt_mesh.app_keys[i]; - } - } - } else { - return bt_mesh_fast_prov_app_key_find(app_idx); - } -#endif - } else if (bt_mesh_is_provisioner_en()) { -#if CONFIG_BLE_MESH_PROVISIONER - for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { - if (bt_mesh.p_app_keys[i] && - bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.p_app_keys[i]->app_idx == app_idx) { - return bt_mesh.p_app_keys[i]; - } - } -#endif - } + BT_DBG("SegAckTimeout %lu, Min %f", timeout, min); - return NULL; + return timeout; } -int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint16_t dst) +uint32_t bt_mesh_seg_ack_period(void) { - struct bt_mesh_app_key *app_key = NULL; + uint32_t period = 0U; + float val = 0.0; - if (app_idx == BLE_MESH_KEY_DEV) { - *key = bt_mesh_dev_key_get(dst); - if (!*key) { - BT_ERR("DevKey of 0x%04x not found", dst); - return -EINVAL; - } + val = (float)bt_mesh_get_sar_adi() + 1.5; + period = (uint32_t)(val * bt_mesh_seg_rx_interval()); - *aid = 0U; - return 0; - } - - if (!subnet) { - BT_ERR("Invalid subnet"); - return -EINVAL; - } - - app_key = bt_mesh_app_key_get(app_idx); - if (!app_key) { - BT_ERR("AppKey 0x%04x not found", app_idx); - return -ENOENT; - } - - if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { - *key = app_key->keys[1].val; - *aid = app_key->keys[1].id; - } else { - *key = app_key->keys[0].val; - *aid = app_key->keys[0].id; - } + BT_DBG("SegAckPeriod %lu, Val %f", period, val); - return 0; + return period; } static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, @@ -284,8 +256,10 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, struct net_buf *buf = NULL; enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", - tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + BT_DBG("SendUnseg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x CtlOp 0x%02x SduLen %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, + ctl_op ? *ctl_op : 0xFF, sdu->len); #if CONFIG_BLE_MESH_EXT_ADV #if CONFIG_BLE_MESH_LONG_PACKET @@ -340,13 +314,14 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, tx->src, tx->ctx->addr, NULL, 1)) { + BT_WARN("NoSpaceInFrndQueue, SegCount 1"); + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - BT_ERR("Not enough space in Friend Queue"); + BT_ERR("NotSentToUnicast"); net_buf_unref(buf); return -ENOBUFS; } - BT_WARN("No space in Friend Queue"); goto send; } @@ -356,6 +331,8 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount 1"); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; @@ -368,19 +345,25 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, static inline uint8_t seg_len(struct seg_info *si) { + uint8_t len = 0; + if (si->ctl) { - return + len = #if CONFIG_BLE_MESH_LONG_PACKET si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : #endif BLE_MESH_CTL_SEG_SDU_MAX; - } - - return + } else { + len = #if CONFIG_BLE_MESH_LONG_PACKET - si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : #endif - BLE_MESH_APP_SEG_SDU_MAX; + BLE_MESH_APP_SEG_SDU_MAX; + } + + BT_DBG("SegLen %u", len); + + return len; } bool bt_mesh_tx_in_progress(void) @@ -389,20 +372,28 @@ bool bt_mesh_tx_in_progress(void) for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (seg_tx[i].nack_count) { + BT_DBG("SegTxInProgress"); return true; } } + BT_DBG("SegTxNotInProgress"); return false; } static bool seg_tx_blocks(struct seg_tx *tx, uint16_t src, uint16_t dst) { + BT_DBG("SegTxBlocks"); + BT_DBG("Src 0x%04x vs. 0x%04x", tx->src, src); + BT_DBG("Dst 0x%04x vs. 0x%04x", tx->dst, dst); + return (tx->src == src) && (tx->dst == dst); } static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { + BT_DBG("SegTxDone, SegIdx %u", seg_idx); + /* If the segments are sent from local network interface, buf->ref * should be smaller than 4. * For other network interfaces, buf->ref should be smaller than 3. @@ -412,12 +403,16 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 0); net_buf_unref(tx->seg[seg_idx]); + BT_DBG("NackCountDec %u", tx->nack_count); + tx->seg[seg_idx] = NULL; tx->nack_count--; } static void seg_tx_reset(struct seg_tx *tx) { + BT_DBG("SegTxReset"); + bt_mesh_seg_tx_lock(); k_delayed_work_free(&tx->seg_timer); @@ -449,6 +444,7 @@ static void seg_tx_reset(struct seg_tx *tx) if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { BT_DBG("Proceeding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ @@ -463,6 +459,8 @@ static void seg_tx_complete(struct seg_tx *tx, int err) const struct bt_mesh_send_cb *cb = tx->cb; void *cb_data = tx->cb_data; + BT_DBG("SegTxComplete, Err %d", err); + seg_tx_reset(tx); /* TODO: notify the completion of sending segmented message */ @@ -479,10 +477,15 @@ static bool all_seg_acked(struct seg_tx *tx, uint8_t *seg_n) if (seg_n) { *seg_n = i; } + + BT_DBG("NotAllSegAcked, SegN %u", i); + return false; } } + BT_DBG("AllSegAcked"); + return true; } @@ -506,6 +509,10 @@ static bool send_next_segment(struct seg_tx *tx, int *result) struct net_buf *seg = NULL; int err = 0; + BT_DBG("SendNextSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x LastSegN %u SegN %u LSNUpdated %u", + tx->src, tx->dst, tx->last_seg_n, tx->seg_n, tx->lsn_updated); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK (i.e. with all ack bits set) is * received before sending the next segment, which will cause the @@ -537,6 +544,8 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * not been acknowledged. */ if (tx->seg[i]) { + BT_DBG("SegFound %u", i); + tx->last_seg_n = i; seg = tx->seg[i]; break; @@ -558,16 +567,19 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * Segment Retransmission timer is expired earlier. */ if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { + BT_DBG("SegSentBusy"); return false; } - BT_INFO("Send next seg %u, cred %u", tx->last_seg_n, tx->cred); + BT_INFO("LastSegN %u Cred %u", tx->last_seg_n, tx->cred); if (tx->resend) { err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("ResendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -576,15 +588,16 @@ static bool send_next_segment(struct seg_tx *tx, int *result) net_tx.ctx->net_idx = tx->sub->net_idx; - /** - * Add one to the ref count only if the segment can be further + /* Add one to the ref count only if the segment can be further * processed by the network. */ seg = net_buf_ref(seg); err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); if (err) { - BT_ERR("Send seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("SendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -594,7 +607,9 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * which will be used for retransmission later. */ if (tx->cred != net_tx.ctx->send_cred) { - BT_ERR("Mismatch seg cred %u/%u", tx->cred, net_tx.ctx->send_cred); + BT_ERR("MismatchSegCred %u vs. %u", + tx->cred, net_tx.ctx->send_cred); + *result = -EIO; return true; } @@ -612,6 +627,8 @@ static void send_next_seg(struct k_work *work) tx_complete = send_next_segment(tx, &result); bt_mesh_seg_tx_unlock(); + BT_DBG("SendNextSeg, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, result); } @@ -623,6 +640,8 @@ static void prepare_next_seg(struct seg_tx *tx) uint8_t seg_n = 0; uint8_t xmit = 0; + BT_DBG("PrepareNextSeg"); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK (i.e. with all ack bits set) is * received before the completion of sending last segment, which @@ -633,6 +652,8 @@ static void prepare_next_seg(struct seg_tx *tx) return; } + BT_DBG("LastSegN %u SegN %u SegNGet %u", tx->last_seg_n, tx->seg_n, seg_n); + /* The last_seg_n must not be larger than the seg_n */ assert(tx->last_seg_n <= tx->seg_n && "Too large last_seg_n"); @@ -666,7 +687,7 @@ static void prepare_next_seg(struct seg_tx *tx) interval = bt_mesh_seg_send_interval(); - BT_INFO("Send next segment %u after %dms", i, interval); + BT_INFO("SendNextSeg %u, Interval %ld", i, interval); k_delayed_work_submit(&tx->seg_timer, interval); return; @@ -678,6 +699,7 @@ static void prepare_next_seg(struct seg_tx *tx) * we need to decrypt it firstly. */ if (tx->resend == 0) { + BT_DBG("TxResendMarked"); tx->resend = 1; } @@ -688,7 +710,7 @@ static void prepare_next_seg(struct seg_tx *tx) /* Start the SAR retransmission timer */ interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); - BT_INFO("All segments sent, resend after %dms", interval); + BT_INFO("AllSegsSent, SegN %u Interval %ld", seg_n, interval); k_delayed_work_submit(&tx->rtx_timer, interval); } @@ -697,6 +719,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendStart, Err %d", err); + /* If there's an error in transmitting the 'sent' callback will never * be called. Make sure that we kick the retransmit timer also in this * case since otherwise we risk the transmission of becoming stale. @@ -706,6 +730,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) return; } + BT_DBG("TxResend %u LastSegN %u", tx->resend, tx->last_seg_n); + if (tx->resend == 0 && tx->last_seg_n == 0) { /* Start sending the multi-segment message */ if (tx->cb && tx->cb->start) { @@ -722,6 +748,8 @@ static void seg_send_end(int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendEnd, Err %d", err); + if (err) { seg_tx_complete(tx, -EIO); } @@ -737,6 +765,10 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) struct net_buf *seg = NULL; int err = 0; + BT_DBG("ResendUnackedSeg"); + BT_DBG("Dst 0x%04x Surc %u Surwpc %u Smrc %u", + tx->dst, tx->surc, tx->surwpc, tx->smrc); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK(i.e. with all ack bits set) is * received before the completion of sending last segment, which @@ -806,6 +838,8 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) */ for (size_t i = tx->last_seg_n; i <= tx->seg_n; i++) { if (tx->seg[i]) { + BT_DBG("SegFound %u", i); + tx->last_seg_n = i; seg = tx->seg[i]; break; @@ -828,10 +862,11 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) * find that the "busy" flag of Segment A is 1. */ if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { + BT_DBG("SegSentBusy"); return false; } - BT_INFO("Resend seg %u, cred %u", tx->last_seg_n, tx->cred); + BT_INFO("LastSegN %u Cred %u", tx->last_seg_n, tx->cred); /* TODO: * The "tx->new_key" should be replaced with sub->kr_flag, @@ -842,7 +877,9 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("ResendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -862,6 +899,8 @@ static void seg_retransmit(struct k_work *work) tx_complete = resend_unacked_seg(tx, &err); bt_mesh_seg_tx_unlock(); + BT_DBG("SendRetransmit, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, err); } @@ -879,11 +918,14 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, int err = 0; size_t i; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + BT_DBG("SendSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x Aszmic %u SduLen %u", net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, net_tx->aszmic, sdu->len); for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + BT_DBG("Seg%u: NackCount %u", i, seg_tx[i].nack_count); + if (seg_tx[i].nack_count) { /* The lower transport layer shall not transmit segmented messages * for more than one Upper Transport PDU to the same destination @@ -898,6 +940,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (!seg_tx[i].nack_count) { + BT_DBG("SegTxFound %u", i); + tx = &seg_tx[i]; break; } @@ -990,15 +1034,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; - BT_DBG("SeqZero 0x%04x (segs: %u)", seq_zero, tx->nack_count); + BT_DBG("SegHdr 0x%02x SegN %u NackCount %u NewKey %u TTL %u", + tx->hdr, tx->seg_n, tx->nack_count, tx->new_key, tx->ttl); + BT_DBG("SeqZero 0x%04x Surc %u Surwpc %u Smrc %u", + seq_zero, tx->surc, tx->surwpc, tx->smrc); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, tx->dst, &tx->seq_auth, tx->seg_n + 1) && BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { - BT_ERR("Not enough space in Friend Queue for %u segments", - tx->seg_n + 1); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", tx->seg_n + 1); + seg_tx_reset(tx); return -ENOBUFS; } @@ -1065,6 +1112,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, type = BLE_MESH_FRIEND_PDU_PARTIAL; } + BT_DBG("FrndPDUType %u", type); + if (bt_mesh_friend_enqueue_tx(net_tx, type, &tx->seq_auth, tx->seg_n + 1, @@ -1073,39 +1122,40 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount %u", tx->seg_n + 1); + net_buf_unref(seg); continue; } } - /** - * If the net buffer allocation of the subsequent - * segments of this segment message fails, it will - * cause the ref count of the previously allocated - * successful segments to not be unref, which will - * cause the net buffer leakage to occur, so it is - * necessary to wait until all the segments have been - * allocated, and then when the segment is confirmed - * that it will be network layer for further processing, - * then ref of the net buffer should be plus one. + /* If the net buffer allocation of the subsequent segments of + * this segment message fails, it will cause the ref count of + * the previously allocated successful segments to not be unref, + * which will cause the net buffer leakage to occur, so it is + * necessary to wait until all the segments have been allocated, + * and then when the segment is confirmed that it will be network + * layer for further processing, then ref of the net buffer should + * be plus one. */ tx->seg[seg_o] = seg; - BT_DBG("Seg %u/%u prepared", seg_o, tx->seg_n); + BT_DBG("SegPrepared %u/%u", seg_o, tx->seg_n); } /* If all the segments are enqueued in the friend queue, then the * tx->seg[0] will be NULL here. */ if (tx->seg[0]) { - /** - * Add one to the ref count only if the segment can be further + /* Add one to the ref count only if the segment can be further * processed by the network. */ tx->seg[0] = net_buf_ref(tx->seg[0]); + err = bt_mesh_net_send(net_tx, tx->seg[0], &seg_sent_cb, tx); if (err) { - BT_ERR("Send 1st seg failed (err %d)", err); + BT_ERR("SendFirstSegFailed, Err %d", err); + seg_tx_reset(tx); return err; } @@ -1115,13 +1165,17 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * which will be used for retransmission later. */ if (tx->cred != net_tx->ctx->send_cred) { + BT_INFO("OldCred %u NewCred %u", tx->cred, net_tx->ctx->send_cred); tx->cred = net_tx->ctx->send_cred; } } /* This can happen if segments only went into the Friend Queue */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) { + BT_DBG("OnlyToFrndQueue"); + seg_tx_reset(tx); + /* If there was a callback notify sending immediately since * there's no other way to track this (at least currently) * with the Friend Queue. @@ -1145,6 +1199,8 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; + BT_DBG("transcend"); + if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); return -EINVAL; @@ -1170,9 +1226,9 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, } #endif - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + tx->sub->net_idx, tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); err = bt_mesh_upper_key_get(tx->sub, tx->ctx->app_idx, &key, &aid, tx->ctx->addr); @@ -1190,7 +1246,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->aszmic = 1U; } - BT_INFO("%s, send_tag 0x%02x, send_szmic %d, aszmic %d", + BT_INFO("%s, Tag 0x%02x Szmic %u Aszmic %u", bt_mesh_tag_send_segmented(tx->ctx->send_tag) ? "Seg" : "Unseg", tx->ctx->send_tag, tx->ctx->send_szmic, tx->aszmic); @@ -1205,7 +1261,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->ctx->addr, bt_mesh.seq, BLE_MESH_NET_IVI_TX); if (err) { - BT_ERR("Encrypt failed (err %d)", err); + BT_ERR("AppEncryptFailed, Err %d", err); return err; } @@ -1219,7 +1275,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, static void revoke_dev_key(const uint8_t *dev_key) { if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { - BT_INFO("Revoke Device Key"); + BT_INFO("RevokeDevKey"); memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); memset(bt_mesh.dev_key_ca, 0, 16); @@ -1240,8 +1296,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, size_t i = 0U; int err = 0; - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("SduRecv"); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1 + APP_MIC_LEN(aszmic)) { BT_ERR("Too short SDU + MIC (len %u)", buf->len); @@ -1280,7 +1337,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, dev_key = bt_mesh_rx_devkey_get(i, rx->ctx.addr); if (!dev_key) { - BT_DBG("DevKey not found"); + BT_DBG("DevKeyNotFound"); continue; } @@ -1291,6 +1348,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, rx->ctx.recv_dst, seq, BLE_MESH_NET_IVI_RX(rx)); if (err) { + BT_DBG("DevKeyNotDecrypt"); continue; } @@ -1316,6 +1374,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } BT_WARN("Unable to decrypt with DevKey"); + bt_mesh_free_buf(sdu); return -ENODEV; } @@ -1328,7 +1387,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, key = bt_mesh_rx_appkey_get(i); if (!key) { - BT_DBG("AppKey not found"); + BT_DBG("AppKeyNotFound"); continue; } @@ -1362,8 +1421,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, bt_hex(sdu->data, sdu->len)); if (err) { - BT_DBG("Unable to decrypt with AppKey 0x%03x", - key->app_idx); + BT_DBG("AppKeyNotDecrypt, AppIdx 0x%04x", key->app_idx); continue; } @@ -1375,10 +1433,10 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } if (rx->local_match) { - BT_WARN("No matching AppKey"); + BT_WARN("NoMatchAppKey"); } - bt_mesh_free_buf(sdu); + bt_mesh_free_buf(sdu); return 0; } @@ -1388,6 +1446,8 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, struct seg_tx *tx = NULL; int i; + BT_DBG("SegTxLookup, SeqZero 0x%04x OBO %u Addr 0x%04x", seq_zero, obo, addr); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { tx = &seg_tx[i]; @@ -1403,6 +1463,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, } if (tx->dst == addr) { + BT_DBG("SegTxFound, Dst 0x%04x", addr); return tx; } @@ -1412,6 +1473,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, * responding and therefore accept the message. */ if (obo && tx->nack_count == tx->seg_n + 1) { + BT_DBG("SegTxOboFound, Dst 0x%04x", addr); tx->dst = addr; return tx; } @@ -1438,6 +1500,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, *tx_complete = false; *result = 0; + BT_DBG("RecvSegAck"); + if (buf->len != 6) { BT_ERR("Malformed Segment Ack (len %u)", buf->len); return -EINVAL; @@ -1456,7 +1520,7 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, ack = net_buf_simple_pull_be32(buf); - BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + BT_DBG("OBO %u SeqZero 0x%04x Ack 0x%08lx", obo, seq_zero, ack); tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr, rx->ctx.net_idx); if (!tx) { @@ -1514,6 +1578,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return 0; } + BT_DBG("NewlyMarked"); + /* If at least one segment is newly marked as acknowledged as * a result of receiving the Segment Acknowledgment message, * the lower transport layer shall set the remaining number of @@ -1523,9 +1589,12 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, tx->surwpc = bt_mesh_get_sar_urwpc(); } + BT_DBG("Surc %u Surwpc %u", tx->surc, tx->surwpc); + if (tx->surc == 0 || tx->surwpc == 0) { BT_WARN("Ran out of retransmission to 0x%04x (%u/%u)", tx->dst, tx->surc, tx->surwpc); + *tx_complete = true; *result = -ETIMEDOUT; return 0; @@ -1533,6 +1602,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, assert(all_seg_acked(tx, &seg_n) == false && "All segments acked"); + BT_DBG("SegN %u TxResend %u", seg_n, tx->resend); + if (tx->resend == 1) { /* Only update the last_seg_n to the first unacked SegN while * the first round transmission is finished, because we need @@ -1561,7 +1632,7 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Restart the SAR Unicast Retransmission timer */ interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); - BT_INFO("Resend segments after %dms", interval); + BT_INFO("ResendSeg, Interval %ld", interval); k_delayed_work_submit(&tx->rtx_timer, interval); @@ -1580,6 +1651,8 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, err = recv_seg_ack(rx, hdr, buf, seq_auth, &tx, &tx_complete, &result); bt_mesh_seg_tx_unlock(); + BT_DBG("TransAck, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, result); } @@ -1593,6 +1666,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, uint8_t init_ttl = 0U, hops = 0U; uint16_t feat = 0U; + BT_DBG("TransHeartbeat"); + if (buf->len != 3) { BT_ERR("Malformed heartbeat message (len %u)", buf->len); return -EINVAL; @@ -1609,9 +1684,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, hops = (init_ttl - rx->ctx.recv_ttl + 1); - BT_INFO("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); + BT_INFO("Src 0x%04x TTL %u InitTTL %u Hops %u Feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, feat); if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { bt_mesh_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); @@ -1629,7 +1703,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, { uint8_t ctl_op = TRANS_CTL_OP(&hdr); - BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + BT_DBG("CTLRecv, OpCode 0x%02x Len %u", ctl_op, buf->len); BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, @@ -1646,21 +1720,22 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Only acks and heartbeats may need processing without local_match */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return 0; } - if (IS_ENABLED(CONFIG_BLE_MESH_DF_SRV)) { - switch (ctl_op) { - case TRANS_CTL_OP_PATH_REQ: - case TRANS_CTL_OP_PATH_REPLY: - case TRANS_CTL_OP_PATH_CFM: - case TRANS_CTL_OP_PATH_ECHO_REQ: - case TRANS_CTL_OP_PATH_ECHO_REPLY: - case TRANS_CTL_OP_DEP_NODE_UPDATE: - case TRANS_CTL_OP_PATH_REQ_SOLIC: - return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); - } +#if CONFIG_BLE_MESH_DF_SRV + switch (ctl_op) { + case TRANS_CTL_OP_PATH_REQ: + case TRANS_CTL_OP_PATH_REPLY: + case TRANS_CTL_OP_PATH_CFM: + case TRANS_CTL_OP_PATH_ECHO_REQ: + case TRANS_CTL_OP_PATH_ECHO_REPLY: + case TRANS_CTL_OP_DEP_NODE_UPDATE: + case TRANS_CTL_OP_PATH_REQ_SOLIC: + return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); } +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { switch (ctl_op) { @@ -1713,7 +1788,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, { uint8_t hdr = 0U; - BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + BT_DBG("TransUnseg, AKF %u AID 0x%02x", AKF(buf->data), AID(buf->data)); if (buf->len < 1) { BT_ERR("Too small unsegmented PDU"); @@ -1721,7 +1796,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, } if (bt_mesh_rpl_check(rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, rx->seq); return -EINVAL; } @@ -1734,6 +1809,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, /* SDUs must match a local element or an LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } @@ -1746,6 +1822,8 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, { struct net_buf_simple buf = {0}; + BT_DBG("CtlSend"); + net_buf_simple_init_with_data(&buf, data, data_len); if (data_len > BLE_MESH_SDU_UNSEG_MAX) { @@ -1755,9 +1833,9 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, /* Set app_idx to unused here since CTL is only encrypted with NetKey */ tx->ctx->app_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, - tx->ctx->addr, tx->ctx->send_ttl, ctl_op); - BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL 0x%02x CTL 0x%02x", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("Len %u: %s", data_len, bt_hex(data, data_len)); if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { return send_seg(tx, &buf, cb, cb_data, &ctl_op); @@ -1770,18 +1848,21 @@ static void seg_ack_send_start(uint16_t duration, int err, void *user_data) { struct seg_rx *rx = user_data; - BT_INFO("Send segment ack start (err %d)", err); + BT_INFO("SegAckSendStart, Err %d", err); if (err) { rx->last_ack = k_uptime_get_32(); + + BT_DBG("LastAck %lu", rx->last_ack); } } static void seg_ack_send_end(int err, void *user_data) { struct seg_rx *rx = user_data; + uint32_t interval = 0U; - BT_INFO("Send segment ack end"); + BT_INFO("SegAckSendEnd, InUse %u Err %d", rx->in_use, err); /* This could happen when during the Segment ACK transaction, * the seg_rx is been reset. @@ -1792,6 +1873,9 @@ static void seg_ack_send_end(int err, void *user_data) rx->last_ack = k_uptime_get_32(); + BT_DBG("LastAck %lu SegN %u Sarc %u NewSeg %u", + rx->last_ack, rx->seg_n, rx->sarc, rx->new_seg); + /* If the seg_rx is in use, we will restart the SAR ACK timer if * the SegN is greater than the SAR Segments Threshold. * Note: @@ -1809,10 +1893,12 @@ static void seg_ack_send_end(int err, void *user_data) /* Decrement the SAR ACK Retransmissions Count */ rx->sarc -= 1; - BT_INFO("Resend segment ack after %dms", bt_mesh_seg_rx_interval()); + interval = bt_mesh_seg_rx_interval(); + + BT_INFO("ResendSeg, Interval %lu", interval); /* Introduce a delay for the Segment ACK retransmission */ - k_delayed_work_submit(&rx->ack_timer, bt_mesh_seg_rx_interval()); + k_delayed_work_submit(&rx->ack_timer, interval); } } @@ -1850,7 +1936,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; uint8_t buf[6] = {0}; - BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + BT_DBG("SendAck, SeqZero 0x%04x Block 0x%08lx OBO %u", seq_zero, block, obo); if (bt_mesh_lpn_established()) { BT_WARN("Not sending ack when LPN is enabled"); @@ -1874,6 +1960,8 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { + BT_DBG("SegRxReset, FullReset %u", full_reset); + bt_mesh_seg_rx_lock(); k_delayed_work_free(&rx->dis_timer); @@ -1914,6 +2002,8 @@ static void send_seg_ack(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); + BT_DBG("SendSegAck, Sub %p", rx->sub); + bt_mesh_seg_rx_lock(); /* This could happen when the SAR ACK timer expired, and a BTC @@ -1940,6 +2030,9 @@ static void send_seg_ack(struct k_work *work) static void discard_msg(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, dis_timer); + uint32_t timeout = 0U; + + BT_DBG("DiscardMsg, InUse %u Dst 0x%04x", rx->in_use, rx->dst); /* This could happen when the SAR Discard timer expired, and a * BTC event is posted to the BTC queue. @@ -1957,16 +2050,20 @@ static void discard_msg(struct k_work *work) k_delayed_work_cancel(&rx->ack_timer); } - BT_WARN("Discard timer expired (%dms)", bt_mesh_seg_discard_timeout()); + timeout = bt_mesh_seg_discard_timeout(); + + BT_WARN("DiscardTimerExpired, timeout %lu", timeout); - /* Not fully reset the seg_rx, in case any segment of this - * message is received later. + /* Not fully reset the seg_rx, in case any segment of + * this message is received later. */ seg_rx_reset(rx, false); } static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { + BT_DBG("IsSduLenOK,Len:%u,SegN:%u", seg_len, seg_n); + return ((seg_n + 1) * seg_len); } @@ -1975,6 +2072,9 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) struct seg_info si = { .ctl = ctl, }; + + BT_DBG("IsSduLenOK, CTL %u SegN %u", ctl, seg_n); + #if CONFIG_BLE_MESH_LONG_PACKET if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { si.long_pkt = 1; @@ -1987,6 +2087,8 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) static void seg_rx_reset_pending(struct bt_mesh_net_rx *net_rx, const uint64_t *seq_auth) { + BT_DBG("SegRxResetPending, SeqAuth 0x%llx", *seq_auth); + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { struct seg_rx *rx = &seg_rx[i]; @@ -2008,9 +2110,13 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, struct seg_rx *rx_buf, uint16_t rx_buf_size ) { + BT_DBG("SegRxFind, SeqAuth 0x%llx", *seq_auth); for (size_t i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &rx_buf[i]; + BT_DBG("Seg%u/%u: Src 0x%04x Dst 0x%04x SeqAuth 0x%llx", + i,rx->seg_n, rx->src, rx->dst, rx->seq_auth); + if (rx->src == net_rx->ctx.addr && rx->dst == net_rx->ctx.recv_dst) { if (rx->seq_auth >= *seq_auth) { @@ -2093,6 +2199,8 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, const uint8_t *hdr, uint8_t seg_n) { + BT_DBG("IsSegRxValid"); + if (rx->hdr != *hdr || rx->seg_n != seg_n) { BT_ERR("Invalid segment for ongoing session"); return false; @@ -2132,6 +2240,8 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, for (size_t i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &seg_rx_buf[i]; + BT_DBG("SegRxAlloc, SegN %u", seg_n); + if (rx->in_use) { continue; } @@ -2146,7 +2256,7 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, err = k_delayed_work_init(&rx->ack_timer, send_seg_ack); if (err) { BT_ERR("No free ack_timer for new incoming segmented message"); - k_delayed_work_free(&rx->dis_timer); /* Must do */ + k_delayed_work_free(&rx->dis_timer); return NULL; } } @@ -2174,7 +2284,6 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, return rx; } - BT_WARN("No free slots for new incoming segmented messages"); return NULL; } @@ -2190,18 +2299,20 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, uint8_t seg_o = 0U; int err = 0; + BT_DBG("TransSeg"); + if (buf->len < 5) { BT_ERR("Too short segmented message (len %u)", buf->len); return -EINVAL; } if (bt_mesh_rpl_check(net_rx, &rpl)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); return -EINVAL; } - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); net_buf_simple_pull(buf, 1); @@ -2228,6 +2339,9 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, *seg_count = seg_n + 1; + BT_DBG("Src 0x%04x Dst 0x%04x SeqAuth 0x%llx SegCount %u", + net_rx->ctx.addr, net_rx->ctx.recv_dst, *seq_auth, *seg_count); + /* If this is the first segment, check if any pending reassembly * exists. If yes, we need to discard the pending reassembly. * Note: @@ -2241,8 +2355,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (rx) { /* Processing result is SeqAuth Error, ignore the segment */ if (rx->seq_auth > *seq_auth) { - BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", - rx->src, rx->dst); + BT_WARN("SeqAuth 0x%llx vs. 0x%llx", rx->seq_auth, *seq_auth); return -EINVAL; } @@ -2307,7 +2420,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, net_rx->ctx.addr, net_rx->ctx.recv_dst, seq_auth, *seg_count)) { - BT_ERR("No space in Friend Queue for %u segments", *seg_count); + BT_ERR("NoSpaceInFrndQueue, SegCount %u", *seg_count); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, net_rx->friend_match, NULL); @@ -2317,6 +2431,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, /* Look for free slot for a new RX session */ rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); if (!rx) { + BT_WARN("SegRxFull, Src %04x", net_rx->ctx.addr); + /* Processing result is Message Rejected, respond with a Segment * ACK with the AckedSegments field set to 0x00000000. */ @@ -2372,6 +2488,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, rx->obo, NULL); + seg_rx_reset(rx, true); return -EMSGSIZE; @@ -2419,6 +2536,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, rx->block |= BIT(seg_o); if (rx->block != BLOCK_COMPLETE(seg_n)) { + BT_DBG("FrndPDUPartial"); *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; return 0; } @@ -2442,8 +2560,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (net_rx->ctl) { err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); } else { - err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, - ASZMIC(hdr), &rx->buf); + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), + *hdr, ASZMIC(hdr), &rx->buf); } seg_rx_reset(rx, false); @@ -2453,12 +2571,14 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { - uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; struct net_buf_simple_state state = {0}; + uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; uint8_t seg_count = 0U; int err = 0; + BT_DBG("TransRecv"); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, rx->ctx.recv_dst); @@ -2466,20 +2586,21 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) rx->friend_match = false; } - BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + BT_DBG("Src 0x%04x Dst 0x%04x Seq 0x%06x FrndMatch %u", rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); /* Remove network headers */ net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + BT_DBG("PDU %s", bt_hex(buf->data, buf->len)); /* If LPN mode is enabled messages are only accepted when we've * requested the Friend to send them. The messages must also * be encrypted using the Friend Credentials. */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && - bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + bt_mesh_lpn_established() && + rx->net_if == BLE_MESH_NET_IF_ADV && (!bt_mesh_lpn_waiting_update() || rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { BT_WARN("Ignoring unexpected message in Low Power mode"); @@ -2496,12 +2617,14 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) * LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); } else { seg_count = 1U; + err = trans_unseg(buf, rx, &seq_auth); } @@ -2539,6 +2662,8 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) void bt_mesh_rx_reset(void) { + BT_DBG("RxReset"); + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx_reset(&seg_rx[i], true); } @@ -2546,6 +2671,8 @@ void bt_mesh_rx_reset(void) void bt_mesh_tx_reset(void) { + BT_DBG("TxReset"); + for (size_t i = 0; i < ARRAY_SIZE(seg_tx); i++) { seg_tx_reset(&seg_tx[i]); } @@ -2553,6 +2680,8 @@ void bt_mesh_tx_reset(void) void bt_mesh_rx_reset_single(uint16_t src) { + BT_DBG("RxResetSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -2567,6 +2696,8 @@ void bt_mesh_rx_reset_single(uint16_t src) void bt_mesh_tx_reset_single(uint16_t dst) { + BT_DBG("TxResetSingle, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { return; } diff --git a/components/bt/esp_ble_mesh/core/transport.h b/components/bt/esp_ble_mesh/core/transport.h index d8d32f81b6c0..e4487fa9fd35 100644 --- a/components/bt/esp_ble_mesh/core/transport.h +++ b/components/bt/esp_ble_mesh/core/transport.h @@ -11,6 +11,7 @@ #define _TRANSPORT_H_ #include "net.h" +#include "access.h" #ifdef __cplusplus extern "C" { diff --git a/components/bt/esp_ble_mesh/models/client/client_common.c b/components/bt/esp_ble_mesh/models/client/client_common.c index 5917b69cdf7e..e87c68f62c73 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -16,18 +16,22 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */ -static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16_t tx_dst) +static bt_mesh_client_node_t *client_pick_node(sys_slist_t *list, uint16_t tx_dst) { bt_mesh_client_node_t *node = NULL; sys_snode_t *cur = NULL; + BT_DBG("ClientPickNode, Dst 0x%04x", tx_dst); + bt_mesh_list_lock(); + if (sys_slist_is_empty(list)) { bt_mesh_list_unlock(); + BT_DBG("ListEmpty"); return NULL; } @@ -36,22 +40,28 @@ static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16 node = (bt_mesh_client_node_t *)cur; if (node->ctx.addr == tx_dst) { bt_mesh_list_unlock(); + BT_DBG("ListNodeFound"); return node; } } bt_mesh_list_unlock(); + + BT_DBG("ListNodeNotFound"); return NULL; } bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, bool need_pub) + struct net_buf_simple *buf, + bool need_pub) { bt_mesh_client_internal_data_t *data = NULL; bt_mesh_client_user_data_t *cli = NULL; bt_mesh_client_node_t *node = NULL; + BT_DBG("ClientRecvPublishMsg"); + if (!model || !ctx || !buf) { BT_ERR("%s, Invalid parameter", __func__); return NULL; @@ -63,22 +73,25 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return NULL; } - /** If the received message address is not a unicast address, - * the address may be a group/virtual address, and we push - * this message to the application layer. + BT_DBG("Src 0x%04x Dst 0x%04x RecvOp 0x%08lx", + ctx->addr, ctx->recv_dst, ctx->recv_op); + + /* If the received message address is not a unicast address, + * the address may be a group/virtual address, and we push + * this message to the application layer. */ if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgToNonUnicastDst"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } return NULL; } - /** If the source address of the received status message is - * different with the destination address of the sending - * message, then the message is from another element and - * push it to application layer. + /* If the source address of the received status message is + * different with the destination address of the sending + * message, then the message is from another element and + * push it to application layer. */ data = (bt_mesh_client_internal_data_t *)cli->internal_data; if (!data) { @@ -86,8 +99,8 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return NULL; } - if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + if ((node = client_pick_node(&data->queue, ctx->addr)) == NULL) { + BT_DBG("MsgFromUnknownSrc"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -95,7 +108,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * } if (node->op_pending != ctx->recv_op) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgWithUnknownOp"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -103,7 +116,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * } if (k_delayed_work_remaining_get(&node->timer) == 0) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgWithTimerExpired"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -113,33 +126,12 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return node; } -static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst) +static uint32_t client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, + int size, uint32_t opcode) { - bt_mesh_client_node_t *node = NULL; - sys_snode_t *cur = NULL; + BT_DBG("ClientGetStatusOp"); + BT_DBG("OpPair %p Size %u OpCode 0x%08lx", op_pair, size, opcode); - bt_mesh_list_lock(); - if (sys_slist_is_empty(list)) { - bt_mesh_list_unlock(); - return false; - } - - for (cur = sys_slist_peek_head(list); - cur != NULL; cur = sys_slist_peek_next(cur)) { - node = (bt_mesh_client_node_t *)cur; - if (node->ctx.addr == tx_dst) { - bt_mesh_list_unlock(); - return true; - } - } - - bt_mesh_list_unlock(); - return false; -} - -static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, - int size, uint32_t opcode) -{ if (!op_pair || size == 0) { return 0; } @@ -147,15 +139,18 @@ static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_ const bt_mesh_client_op_pair_t *op = op_pair; for (int i = 0; i < size; i++) { if (op->cli_op == opcode) { + BT_DBG("OpCodeFound"); return op->status_op; } + op++; } + BT_DBG("OpCodeNotFound"); return 0; } -static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) +static int32_t client_get_adv_duration(struct bt_mesh_msg_ctx *ctx) { uint16_t duration = 0, adv_int = 0; uint8_t xmit = 0; @@ -163,23 +158,28 @@ static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) /* Initialize with network transmission */ xmit = bt_mesh_net_transmit_get(); + BT_DBG("ClientGetAdvDuration, Xmit 0x%02x", xmit); + if (bt_mesh_tag_immutable_cred(ctx->send_tag)) { #if CONFIG_BLE_MESH_DF_SRV if (ctx->send_cred == BLE_MESH_DIRECTED_CRED) { xmit = bt_mesh_direct_net_transmit_get(); /* Directed network transmission */ + BT_DBG("UseDFXmit 0x%02x", xmit); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } adv_int = BLE_MESH_TRANSMIT_INT(xmit); duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + BT_DBG("Duration %ld", (int32_t)duration); + return (int32_t)duration; } -static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *msg, - uint32_t opcode, int32_t timeout) +static int32_t client_calc_timeout(struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + uint32_t opcode, int32_t timeout) { int32_t seg_rtx_to = 0, duration = 0, time = 0; uint8_t seg_count = 0, seg_rtx_num = 0; @@ -211,6 +211,8 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ? BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT; + BT_DBG("NeedSeg %u MicSize %u", need_seg, mic_size); + if (need_seg) { /* Based on the message length, calculate how many segments are needed. * All the messages sent from here are access messages. @@ -228,7 +230,7 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, seg_count = (msg->len + mic_size - 1) / 12U + 1U; } - duration = bt_mesh_get_adv_duration(ctx); + duration = client_get_adv_duration(ctx); /* Currently only consider the time consumption of the same segmented * messages, but if there are other messages between any two retrans- @@ -267,7 +269,7 @@ static void msg_send_start(uint16_t duration, int err, void *cb_data) { bt_mesh_client_node_t *node = cb_data; - BT_DBG("%s, duration %ums", __func__, duration); + BT_DBG("MsgSendStart, Duration %u Err %d", duration, err); if (err) { if (!k_delayed_work_free(&node->timer)) { @@ -293,6 +295,8 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, bt_mesh_client_node_t *node = NULL; int err = 0; + BT_DBG("ClientSendMsg, NeedAck %u", need_ack); + if (!param || !param->model || !msg) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -334,7 +338,7 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, return -EINVAL; } - if (bt_mesh_client_check_node_in_list(&internal->queue, param->ctx.addr)) { + if (client_pick_node(&internal->queue, param->ctx.addr)) { BT_ERR("Busy sending message to DST 0x%04x", param->ctx.addr); return -EBUSY; } @@ -349,14 +353,15 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, memcpy(&node->ctx, ¶m->ctx, sizeof(struct bt_mesh_msg_ctx)); node->model = param->model; node->opcode = param->opcode; - node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); + node->op_pending = client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); if (node->op_pending == 0U) { BT_ERR("Status opcode not found in op_pair list, opcode 0x%08x", param->opcode); bt_mesh_free(node); return -EINVAL; } - node->timeout = bt_mesh_client_calc_timeout(¶m->ctx, msg, param->opcode, - param->msg_timeout ? param->msg_timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT); + node->timeout = client_calc_timeout(¶m->ctx, msg, param->opcode, + (param->msg_timeout ? param->msg_timeout : + CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT)); if (k_delayed_work_init(&node->timer, timer_handler)) { BT_ERR("Failed to create a timer"); @@ -399,6 +404,8 @@ int bt_mesh_client_init(struct bt_mesh_model *model) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientInit"); + if (!model || !model->op) { BT_ERR("Invalid vendor client model"); return -EINVAL; @@ -436,6 +443,8 @@ int bt_mesh_client_deinit(struct bt_mesh_model *model) { bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientDeinit"); + if (!model) { BT_ERR("Invalid vendor client model"); return -EINVAL; @@ -467,6 +476,8 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientFreeNode"); + if (!node || !node->model) { BT_ERR("Invalid client list item"); return -EINVAL; @@ -484,12 +495,10 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) return -EINVAL; } - // Release the client node from the queue bt_mesh_list_lock(); sys_slist_find_and_remove(&internal->queue, &node->client_node); bt_mesh_list_unlock(); - // Free the node bt_mesh_free(node); return 0; @@ -500,6 +509,8 @@ int bt_mesh_client_clear_list(void *data) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_node_t *node = NULL; + BT_DBG("ClientClearList"); + if (!data) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -508,11 +519,13 @@ int bt_mesh_client_clear_list(void *data) internal = (bt_mesh_client_internal_data_t *)data; bt_mesh_list_lock(); + while (!sys_slist_is_empty(&internal->queue)) { node = (void *)sys_slist_get_not_empty(&internal->queue); k_delayed_work_free(&node->timer); bt_mesh_free(node); } + bt_mesh_list_unlock(); return 0; diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c new file mode 100644 index 000000000000..84110f8ade4a --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c @@ -0,0 +1,249 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_dfu_model.h" +#include "esp_ble_mesh_dfu_model_api.h" + +#if CONFIG_BLE_MESH_DFU_CLI + +static bool is_get_param_needed(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get) +{ + btc_ble_mesh_dfu_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (is_get_param_needed(params->opcode) && get == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE; + + arg.dfu_get.params = params; + arg.dfu_get.get = get; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t), + btc_ble_mesh_dfu_client_arg_deep_copy, + btc_ble_mesh_dfu_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_blob_cli_inputs_t *inputs, + esp_ble_mesh_blob_io_t *io, + esp_ble_mesh_dfu_cli_xfer_t *xfer) +{ + btc_ble_mesh_dfu_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (cli == NULL || inputs == NULL || + io == NULL || xfer == NULL) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND; + + arg.send_arg.cli = cli; + arg.send_arg.inputs = inputs; + arg.send_arg.io = io; + arg.send_arg.xfer = xfer; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t), + NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli) +{ + if (!cli) { + return 0; + } + return btc_ble_mesh_dfu_cli_progress(cli); +} + +esp_err_t esp_ble_mesh_register_dfu_client_callback(esp_ble_mesh_dfu_client_cb_t callback) +{ + return (btc_profile_cb_set(BTC_PID_DFU_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +void esp_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_verified(srv); +} + +void esp_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_rejected(srv); +} + +void esp_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_cancel(srv); +} + +void esp_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_applied(srv); +} + +bool esp_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return false; + } + + return btc_ble_mesh_dfu_srv_is_busy(srv); +} + +uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return 0; + } + + return btc_ble_mesh_dfu_srv_progress(srv); +} +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI + +esp_err_t esp_ble_mesh_register_dfd_cli_callback(esp_ble_mesh_dfd_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_DFD_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool dfd_client_opcode_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) + { + /* Get opcode */ + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + /* Set opcode */ + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + case ESP_BLE_MESH_DFD_OP_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_dfd_cli_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get_param) +{ + btc_ble_mesh_dfd_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (dfd_client_opcode_need_param(params->opcode) && get_param == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = ESP_BLE_MESH_ACT_DFD_CLIENT_GET; + arg.dfd_client_get.params = params; + arg.dfd_client_get.get = get_param; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfd_client_args_t), btc_ble_mesh_dfd_client_arg_deep_copy, + btc_ble_mesh_dfd_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_dfd_cli_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set_param) +{ + btc_ble_mesh_dfd_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (dfd_client_opcode_need_param(params->opcode) && set_param == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (set_param->receivers_add.receivers_cnt == 0) { + return ESP_ERR_INVALID_ARG; + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (set_param->dist_upload_start.fw_size == 0) { + return ESP_ERR_INVALID_ARG; + } + if (set_param->dist_upload_start.fwid == NULL) { + return ESP_ERR_INVALID_ARG; + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (set_param->dist_upload_oob_start.url == NULL) { + return ESP_ERR_INVALID_ARG; + } + break; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = ESP_BLE_MESH_ACT_DFD_CLIENT_SET; + arg.dfd_client_set.params = params; + arg.dfd_client_set.set = set_param; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfd_client_args_t), btc_ble_mesh_dfd_client_arg_deep_copy, + btc_ble_mesh_dfd_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_DFD_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c new file mode 100644 index 000000000000..8cc17d28fa9d --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_ble_mesh_dfu_slot_api.h" +#include "btc_ble_mesh_dfu_slot.h" + +int esp_ble_mesh_dfu_slot_count(void) +{ + return btc_ble_mesh_dfu_slot_count(); +} + +esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_reserve(void) +{ + return btc_ble_mesh_dfu_slot_reserve(); +} + +int esp_ble_mesh_dfu_slot_info_set(esp_ble_mesh_dfu_slot_t *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + if (!dfu_slot || !metadata || + metadata_len == 0 || + metadata_len > CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_info_set(dfu_slot, size, + metadata, metadata_len); +} + +int esp_ble_mesh_dfu_slot_fwid_set(esp_ble_mesh_dfu_slot_t *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + if (!dfu_slot || !fwid || fwid_len == 0 || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_fwid_set(dfu_slot, fwid, + fwid_len); +} + +int esp_ble_mesh_dfu_slot_commit(esp_ble_mesh_dfu_slot_t *dfu_slot) +{ + if (!dfu_slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_commit(dfu_slot); +} + +void esp_ble_mesh_dfu_slot_release(const esp_ble_mesh_dfu_slot_t *dfu_slot) +{ + if (!dfu_slot) { + return; + } + + btc_ble_mesh_dfu_slot_release(dfu_slot); +} + +int esp_ble_mesh_dfu_slot_del(const esp_ble_mesh_dfu_slot_t *slot) +{ + if (!slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_del(slot); +} + +void esp_ble_mesh_dfu_slot_del_all(void) +{ + btc_ble_mesh_dfu_slot_del_all(); +} + +const esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_at(uint16_t img_idx) +{ + return btc_ble_mesh_dfu_slot_at(img_idx); +} + +int esp_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, esp_ble_mesh_dfu_slot_t **slot) +{ + if (!fwid || fwid_len == 0 || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN || + !slot || !*slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_get(fwid, fwid_len, slot); +} + +int esp_ble_mesh_dfu_slot_img_idx_get(const esp_ble_mesh_dfu_slot_t *slot) +{ + if (!slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_img_idx_get(slot); +} diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c index e5aed197aefb..70763ba2ec17 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,20 +20,20 @@ extern int bt_mesh_get_transfer_progress(void *model, uint16_t unicast_addr, uint8_t *block_percent, uint8_t *chunk_percent); extern int bt_mesh_get_blob_reception_progress(void *model, uint8_t *reception_progress); -esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) +esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) __attribute__((deprecated)) { ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); return (btc_profile_cb_set(BTC_PID_MBT_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -51,14 +51,14 @@ esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_ca == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL) || - input->blob_data == NULL) { + (input->unicast_addr_count && input->unicast_addr == NULL) || + input->blob_data == NULL) { return ESP_ERR_INVALID_ARG; } @@ -76,7 +76,7 @@ esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *in == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -97,7 +97,7 @@ esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -118,7 +118,7 @@ esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -139,13 +139,13 @@ esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_ == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -163,13 +163,13 @@ esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determi == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -188,13 +188,13 @@ esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t } const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, - uint16_t unicast_addr) + uint16_t unicast_addr) __attribute__((deprecated)) { return (const esp_ble_mesh_blob_receiver_t *)bt_mesh_get_blob_receiver((struct bt_mesh_model *)model, unicast_addr); } -const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { return (const esp_ble_mesh_blob_receiver_t **)bt_mesh_get_active_blob_receiver((struct bt_mesh_model *)model); } @@ -202,14 +202,14 @@ const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_rec esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, uint16_t unicast_addr, uint8_t *block_percent, - uint8_t *chunk_percent) + uint8_t *chunk_percent) __attribute__((deprecated)) { return (bt_mesh_get_transfer_progress((struct bt_mesh_model *)model, unicast_addr, block_percent, chunk_percent) == 0 ? ESP_OK : ESP_FAIL); } esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, - uint8_t transfer_ttl) + uint8_t transfer_ttl) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -231,7 +231,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -253,7 +253,7 @@ esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model } esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, - uint16_t app_idx) + uint16_t app_idx) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -275,7 +275,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -297,7 +297,7 @@ esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) } esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, - uint16_t multicast_addr) + uint16_t multicast_addr) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -319,7 +319,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -342,14 +342,14 @@ esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *mod #endif /* CONFIG_BLE_MESH_MBT_CLI */ #if CONFIG_BLE_MESH_MBT_SRV -esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) __attribute__((deprecated)) { ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); return (btc_profile_cb_set(BTC_PID_MBT_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -370,7 +370,7 @@ esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initializ == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -391,7 +391,7 @@ esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_r == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -413,7 +413,7 @@ esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_ca } esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, - uint8_t *reception_progress) + uint8_t *reception_progress) __attribute__((deprecated)) { return (bt_mesh_get_blob_reception_progress((struct bt_mesh_model *)model, reception_progress) == 0 ? ESP_OK : ESP_FAIL); diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h new file mode 100644 index 000000000000..165450ed56af --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h @@ -0,0 +1,696 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_BLOB_MODEL_API_H_ +#define _ESP_BLE_MESH_BLOB_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_blob_model_api.h" + +#if CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_BLOB_ID_SIZE 8 + +/** @def ESP_BLE_MESH_MODEL_BLOB_CLI + * + * @brief Define a new BLOB Transfer Client model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Client model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New BLOB Transfer Client model instance. + */ +#define ESP_BLE_MESH_MODEL_BLOB_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BLOB_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_BLOB_SRV + * + * @brief Define a new BLOB Transfer Server model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Server model. + * + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * + * @return New BLOB Transfer Server model instance. + */ +#define ESP_BLE_MESH_MODEL_BLOB_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BLOB_SRV, \ + NULL, srv_pub, srv_data) + + +/** BLOB stream. */ +typedef struct esp_ble_mesh_blob_io esp_ble_mesh_blob_io_t; + +/** @brief BLOB Transfer Server instance. */ +typedef struct esp_ble_mesh_blob_srv esp_ble_mesh_blob_srv_t; + +/** @brief BLOB Transfer Server model event handlers. */ +typedef struct esp_ble_mesh_blob_srv_cb esp_ble_mesh_blob_srv_cb_t; + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +typedef struct esp_ble_mesh_blob_target_pull esp_ble_mesh_blob_target_pull_t; + +/** BLOB Transfer Client Target node. */ +typedef struct esp_ble_mesh_blob_target esp_ble_mesh_blob_target_t; + +/** BLOB transfer information. */ +typedef struct esp_ble_mesh_blob_xfer_info esp_ble_mesh_blob_xfer_info_t; + +/** BLOB Transfer Client transfer inputs. */ +typedef struct esp_ble_mesh_blob_cli_inputs esp_ble_mesh_blob_cli_inputs_t; + +/** Transfer capabilities of a Target node. */ +typedef struct esp_ble_mesh_blob_cli_caps esp_ble_mesh_blob_cli_caps_t; + +/** + * @brief BLOB Transfer Client model instance. + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_blob_cli esp_ble_mesh_blob_cli_t; + +/** Event handler callbacks for the BLOB Transfer Client model. */ +typedef struct esp_ble_mesh_blob_cli_cb esp_ble_mesh_blob_cli_cb_t; + +/** BLOB transfer. */ +typedef struct esp_ble_mesh_blob_xfer esp_ble_mesh_blob_xfer_t; + +/** BLOB transfer data block. */ +typedef struct esp_ble_mesh_blob_block esp_ble_mesh_blob_block_t; + +/** BLOB data chunk. */ +typedef struct esp_ble_mesh_blob_chunk esp_ble_mesh_blob_chunk_t; + +/** Transfer phase. */ +typedef enum esp_ble_mesh_blob_xfer_phase { + ESP_BLE_MESH_BLOB_XFER_PHASE_INACTIVE, /*!< The BLOB Transfer Server is awaiting configuration. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, /*!< The BLOB Transfer Server is ready to receive a BLOB transfer. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, /*!< The BLOB Transfer Server is waiting for the next block of data. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, /*!< The BLOB Transfer Server is waiting for the next chunk of data. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_COMPLETE, /*!< The BLOB was transferred successfully. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_SUSPENDED, /*!< The BLOB transfer is paused. */ +} esp_ble_mesh_blob_xfer_phase_t; + +/** BLOB transfer mode. */ +typedef enum esp_ble_mesh_blob_xfer_mode { + ESP_BLE_MESH_BLOB_XFER_MODE_NONE, /*!< No valid transfer mode. */ + ESP_BLE_MESH_BLOB_XFER_MODE_PUSH, /*!< Push mode (Push BLOB Transfer Mode). */ + ESP_BLE_MESH_BLOB_XFER_MODE_PULL, /*!< Pull mode (Pull BLOB Transfer Mode). */ + ESP_BLE_MESH_BLOB_XFER_MODE_ALL, /*!< Both modes are valid. */ +} esp_ble_mesh_blob_xfer_mode_t; + +/** BLOB model status codes. */ +typedef enum esp_ble_mesh_blob_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_BLOB_SUCCESS, + /** The Block Number field value is not within the range of blocks being + * transferred. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_BLOCK_NUM, + /** The block size is smaller than the size indicated by the Min Block + * Size Log state or is larger than the size indicated by the Max Block + * Size Log state. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, + /** The chunk size exceeds the size indicated by the Max Chunk Size + * state, or the number of chunks exceeds the number specified by the + * Max Total Chunks state. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, + /** The operation cannot be performed while the server is in the current + * phase. + */ + ESP_BLE_MESH_BLOB_ERR_WRONG_PHASE, + /** A parameter value in the message cannot be accepted. */ + ESP_BLE_MESH_BLOB_ERR_INVALID_PARAM, + /** The message contains a BLOB ID value that is not expected. */ + ESP_BLE_MESH_BLOB_ERR_WRONG_BLOB_ID, + /** There is not enough space available in memory to receive the BLOB. + */ + ESP_BLE_MESH_BLOB_ERR_BLOB_TOO_LARGE, + /** The transfer mode is not supported by the BLOB Transfer Server + * model. + */ + ESP_BLE_MESH_BLOB_ERR_UNSUPPORTED_MODE, + /** An internal error occurred on the node. */ + ESP_BLE_MESH_BLOB_ERR_INTERNAL, + /** The requested information cannot be provided while the server is in + * the current phase. + */ + ESP_BLE_MESH_BLOB_ERR_INFO_UNAVAILABLE, +} esp_ble_mesh_blob_status_t; + +/** BLOB Transfer Client state. */ +typedef enum esp_ble_mesh_blob_cli_state { + ESP_BLE_MESH_BLOB_CLI_STATE_NONE, /*!< No transfer is active. */ + ESP_BLE_MESH_BLOB_CLI_STATE_CAPS_GET, /*!< Retrieving transfer capabilities. */ + ESP_BLE_MESH_BLOB_CLI_STATE_START, /*!< Sending transfer start. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_START, /*!< Sending block start. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_SEND, /*!< Sending block chunks. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_CHECK, /*!< Checking block status. */ + ESP_BLE_MESH_BLOB_CLI_STATE_XFER_CHECK, /*!< Checking transfer status. */ + ESP_BLE_MESH_BLOB_CLI_STATE_CANCEL, /*!< Cancelling transfer. */ + ESP_BLE_MESH_BLOB_CLI_STATE_SUSPENDED, /*!< Transfer is suspended. */ + ESP_BLE_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, /*!< Checking transfer progress. */ +} esp_ble_mesh_blob_cli_state_t; + +/** BLOB stream interaction mode. */ +typedef enum esp_ble_mesh_blob_io_mode { + ESP_BLE_MESH_BLOB_READ, /*!< Read data from the stream. */ + ESP_BLE_MESH_BLOB_WRITE, /*!< Write data to the stream. */ +} esp_ble_mesh_blob_io_mode_t; + +/** BLOB transfer. */ +struct esp_ble_mesh_blob_xfer { + uint64_t id; /*!< BLOB ID. */ + size_t size; /*!< Total BLOB size in bytes. */ + esp_ble_mesh_blob_xfer_mode_t mode; /*!< BLOB transfer mode. */ + uint8_t block_size_log; /*!< Logarithmic representation of the block size. */ + uint16_t chunk_size; /*!< Base chunk size. May be smaller for the last chunk. */ +}; + +/** BLOB transfer data block. */ +struct esp_ble_mesh_blob_block { + size_t size; /*!< Block size in bytes */ + off_t offset; /*!< Offset in bytes from the start of the BLOB. */ + uint16_t number; /*!< Block number */ + uint16_t chunk_count; /*!< Number of chunks in block. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, + 8)]; /*!< Bitmap of missing chunks. */ +}; + +/** BLOB data chunk. */ +struct esp_ble_mesh_blob_chunk { + off_t offset; /*!< Offset of the chunk data from the start of the block. */ + size_t size; /*!< Chunk data size. */ + uint8_t *data; /*!< Chunk data. */ +}; + +/** BLOB stream. */ +struct esp_ble_mesh_blob_io { + /** @brief Open callback. + * + * Called when the reader is opened for reading. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param mode Direction of the stream (read/write). + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*open)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + esp_ble_mesh_blob_io_mode_t mode); + + /** @brief Close callback. + * + * Called when the reader is closed. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + */ + void (*close)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer); + + /** @brief Block start callback. + * + * Called when a new block is opened for sending. Each block is only + * sent once, and are always sent in increasing order. The data chunks + * inside a single block may be requested out of order and multiple + * times. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that was started. + */ + int (*block_start)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block); + + /** @brief Block end callback. + * + * Called when the current block has been transmitted in full. + * No data from this block will be requested again, and the application + * data associated with this block may be discarded. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that finished sending. + */ + void (*block_end)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block); + + /** @brief Chunk data write callback. + * + * Used by the BLOB Transfer Server on incoming data. + * + * Each block is divided into chunks of data. This callback is called + * when a new chunk of data is received. Chunks may be received in + * any order within their block. + * + * If the callback returns successfully, this chunk will be marked as + * received, and will not be received again unless the block is + * restarted due to a transfer suspension. If the callback returns a + * non-zero value, the chunk remains unreceived, and the BLOB Transfer + * Client will attempt to resend it later. + * + * Note that the Client will only perform a limited number of attempts + * at delivering a chunk before dropping a Target node from the transfer. + * The number of retries performed by the Client is implementation + * specific. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Received chunk. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*write)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block, + const esp_ble_mesh_blob_chunk_t *chunk); + + /** @brief Chunk data read callback. + * + * Used by the BLOB Transfer Client to fetch outgoing data. + * + * The Client calls the chunk data request callback to populate a chunk + * message going out to the Target nodes. The data request callback + * may be called out of order and multiple times for each offset, and + * cannot be used as an indication of progress. + * + * Returning a non-zero status code on the chunk data request callback + * results in termination of the transfer. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Chunk to get the data of. The buffer pointer to by the + * @c data member should be filled by the callback. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*read)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block, + const esp_ble_mesh_blob_chunk_t *chunk); +}; + +/** @brief BLOB Transfer Server model event handlers. + * + * All callbacks are optional. + */ +struct esp_ble_mesh_blob_srv_cb { + /** @brief Transfer start callback. + * + * Called when the transfer has started with the prepared BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param ctx Message context for the incoming start message. The + * entire transfer will be sent from the same source + * address. + * @param xfer Transfer parameters. + * + * @return 0 on success, or (negative) error code to reject the + * transfer. + */ + int (*start)(esp_ble_mesh_blob_srv_t *srv, esp_ble_mesh_msg_ctx_t *ctx, + esp_ble_mesh_blob_xfer_t *xfer); + + /** @brief Transfer end callback. + * + * Called when the transfer ends, either because it was cancelled, or + * because it finished successfully. A new transfer may be prepared. + * + * @note The transfer may end before it's started if the start + * parameters are invalid. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID of the cancelled transfer. + * @param success Whether the transfer was successful. + */ + void (*end)(esp_ble_mesh_blob_srv_t *srv, uint64_t id, bool success); + + /** @brief Transfer suspended callback. + * + * Called if the Server timed out while waiting for a transfer packet. + * A suspended transfer may resume later from the start of the current + * block. Any received chunks in the current block should be discarded, + * they will be received again if the transfer resumes. + * + * The transfer will call @c resumed again when resuming. + * + * @note The BLOB Transfer Server does not run a timer in the suspended state, + * and it's up to the application to determine whether the + * transfer should be permanently cancelled. Without interaction, + * the transfer will be suspended indefinitely, and the BLOB Transfer + * Server will not accept any new transfers. + * + * @param srv BLOB Transfer Server instance. + */ + void (*suspend)(esp_ble_mesh_blob_srv_t *srv); + + /** @brief Transfer resume callback. + * + * Called if the transfer is resumed after being suspended. + * + * @param srv BLOB Transfer Server instance. + */ + void (*resume)(esp_ble_mesh_blob_srv_t *srv); + + /** @brief Transfer recovery callback. + * + * Called when the Bluetooth mesh subsystem is started if the device is rebooted + * in the middle of a transfer. + * + * Transfers will not be resumed after a reboot if this callback is not + * defined. + * + * @param srv BLOB Transfer Server instance. + * @param xfer Transfer to resume. + * @param io BLOB stream return parameter. Must be set to a valid + * BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(esp_ble_mesh_blob_srv_t *srv, + esp_ble_mesh_blob_xfer_t *xfer, + esp_ble_mesh_blob_io_t **io); +}; + +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define ESP_BLE_MESH_BLOB_BLOCKS_MAX \ + (DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_SIZE_MAX, \ + CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN)) +#else +#define ESP_BLE_MESH_BLOB_BLOCKS_MAX 1 +#endif + +/** @brief BLOB Transfer Server instance. */ +struct esp_ble_mesh_blob_srv { + /** Event handler callbacks. */ + esp_ble_mesh_blob_srv_cb_t *cb; + + /** Runtime state: */ + esp_ble_mesh_blob_io_t *io; + struct k_delayed_work rx_timeout; + esp_ble_mesh_blob_block_t block; + esp_ble_mesh_model_t *mod; + esp_ble_mesh_blob_xfer_phase_t phase; + + /** State of blob serber. */ + struct esp_ble_mesh_blob_srv_state { + esp_ble_mesh_blob_xfer_t xfer; + uint16_t cli; + uint16_t app_idx; + uint16_t timeout_base; + uint16_t mtu_size; + uint8_t ttl; + + /* Bitfield of pending blocks. */ + BLE_MESH_ATOMIC_DEFINE(blocks, ESP_BLE_MESH_BLOB_BLOCKS_MAX); + } state; + + /* Pull mode (Pull BLOB Transfer Mode) behavior. */ + struct { + uint16_t chunk_idx; + struct k_delayed_work report; + } pull; +}; + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +struct esp_ble_mesh_blob_target_pull { + int64_t block_report_timestamp; /*!< Timestamp when the Block Report Timeout Timer expires for this Target node. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; /*!< Missing chunks reported by this Target node. */ +}; + +/** BLOB Transfer Client Target node. */ +struct esp_ble_mesh_blob_target { + sys_snode_t n; /*!< Linked list node */ + + uint16_t addr; /*!< Target node address. */ + + /** Target node's Pull mode context. + * Needs to be initialized when sending a BLOB in Pull mode. + */ + esp_ble_mesh_blob_target_pull_t *pull; + + uint8_t status; /*!< BLOB transfer status, see esp_ble_mesh_blob_status. */ + + uint8_t procedure_complete: 1, /*!< Procedure has been completed. */ + acked: 1, /*!< Message has been acknowledged. Not used when sending. */ + timedout: 1, /*!< Target node didn't respond after specified timeout. */ + skip: 1; /*!< Skip Target node from broadcast. */ +}; + + +/** BLOB transfer information. */ +struct esp_ble_mesh_blob_xfer_info { + esp_ble_mesh_blob_status_t status; /*!< BLOB transfer status. */ + esp_ble_mesh_blob_xfer_mode_t mode; /*!< BLOB transfer mode. */ + esp_ble_mesh_blob_xfer_phase_t phase; /*!< BLOB transfer phase. */ + uint64_t id; /*!< BLOB ID. */ + uint32_t size; /*!< BLOB size in octets. */ + uint8_t block_size_log; /*!< Logarithmic representation of the block size. */ + uint16_t mtu_size; /*!< MTU size in octets. */ + const uint8_t *missing_blocks; /*!< Bit field indicating blocks that were not received. */ +}; + + +/** BLOB Transfer Client transfer inputs. */ +struct esp_ble_mesh_blob_cli_inputs { + /** Linked list of Target nodes. Each node should point to + * esp_ble_mesh_blob_target_t::n. + */ + sys_slist_t targets; + + /** AppKey index to send with. */ + uint16_t app_idx; + + /** Group address destination for the BLOB transfer, or + * ESP_BLE_MESH_ADDR_UNASSIGNED to send every message to each Target + * node individually. + */ + uint16_t group; + + /** Time to live value of BLOB transfer messages. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** Transfer capabilities of a Target node. */ +struct esp_ble_mesh_blob_cli_caps { + size_t max_size; /*!< Max BLOB size. */ + uint8_t min_block_size_log; /*!< Logarithmic representation of the minimum block size. */ + uint8_t max_block_size_log; /*!< Logarithmic representation of the maximum block size. */ + uint16_t max_chunks; /*!< Max number of chunks per block. */ + uint16_t max_chunk_size; /*!< Max chunk size. */ + uint16_t mtu_size; /*!< Max MTU size. */ + esp_ble_mesh_blob_xfer_mode_t modes; /*!< Supported transfer modes. */ +}; + +/** Event handler callbacks for the BLOB Transfer Client model. + * + * All handlers are optional. + */ +struct esp_ble_mesh_blob_cli_cb { + /** @brief Capabilities retrieval completion callback. + * + * Called when the capabilities retrieval procedure completes, indicating that + * a common set of acceptable transfer parameters have been established + * for the given list of Target nodes. All compatible Target nodes have + * status code ESP_BLE_MESH_BLOB_SUCCESS. + * + * @param cli BLOB Transfer Client instance. + * @param caps Safe transfer capabilities if the transfer capabilities + * of at least one Target node has satisfied the Client, or NULL otherwise. + */ + void (*caps)(esp_ble_mesh_blob_cli_t *cli, + const esp_ble_mesh_blob_cli_caps_t *caps); + + /** @brief Target node loss callback. + * + * Called whenever a Target node has been lost due to some error in the + * transfer. Losing a Target node is not considered a fatal error for + * the Client until all Target nodes have been lost. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that was lost. + * @param reason Reason for the Target node loss. + */ + void (*lost_target)(esp_ble_mesh_blob_cli_t *cli, + esp_ble_mesh_blob_target_t *target, + esp_ble_mesh_blob_status_t reason); + + /** @brief Transfer is suspended. + * + * Called when the transfer is suspended due to response timeout from all Target nodes. + * + * @param cli BLOB Transfer Client instance. + */ + void (*suspend)(esp_ble_mesh_blob_cli_t *cli); + + /** @brief Transfer end callback. + * + * Called when the transfer ends. + * + * @param cli BLOB Transfer Client instance. + * @param xfer Completed transfer. + * @param success Status of the transfer. + * Is @c true if at least one Target + * node received the whole transfer. + */ + void (*end)(esp_ble_mesh_blob_cli_t *cli, + const esp_ble_mesh_blob_xfer_t *xfer, bool success); + + /** @brief Transfer progress callback + * + * The content of @c info is invalidated upon exit from the callback. + * Therefore it needs to be copied if it is planned to be used later. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that responded to the request. + * @param info BLOB transfer information. + */ + void (*xfer_progress)(esp_ble_mesh_blob_cli_t *cli, + esp_ble_mesh_blob_target_t *target, + const esp_ble_mesh_blob_xfer_info_t *info); + + /** @brief End of Get Transfer Progress procedure. + * + * Called when all Target nodes have responded or the procedure timed-out. + * + * @param cli BLOB Transfer Client instance. + */ + void (*xfer_progress_complete)(esp_ble_mesh_blob_cli_t *cli); +}; + +/** @cond INTERNAL_HIDDEN */ +typedef struct { + /** Called for every Target node in unicast mode, or once in case of multicast mode. */ + void (*send)(esp_ble_mesh_blob_cli_t *cli, uint16_t dst); + /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ + void (*send_complete)(esp_ble_mesh_blob_cli_t *cli, uint16_t dst); + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ + void (*next)(esp_ble_mesh_blob_cli_t *cli); + /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before + * @ref blob_cli_broadcast_ctx::next is called. + */ + bool acked; + /** If true, the message is always sent in a unicast way. */ + bool force_unicast; + /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ + bool optional; + /** Set to true by the BLOB Transfer Client between blob_cli_broadcast + * and broadcast_complete calls. + */ + bool is_inited; + /* Defines a time in ms by which the broadcast API postpones sending the message to a next + * target or completing the broadcast. + */ + uint32_t post_send_delay_ms; +} esp_blob_cli_broadcast_ctx_t; +/** INTERNAL_HIDDEN @endcond */ + +/** + * @brief BLOB Transfer Client model instance. + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_blob_cli { + /** Event handler callbacks */ + const esp_ble_mesh_blob_cli_cb_t *cb; + + /** Runtime state */ + const esp_ble_mesh_model_t *mod; + + /** Firmware transfer information */ + struct { + esp_ble_mesh_blob_target_t *target; + esp_blob_cli_broadcast_ctx_t ctx; + struct k_delayed_work retry; + /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ + int64_t cli_timestamp; + struct k_work complete; + uint16_t pending; + uint8_t retries; + uint8_t sending : 1, + cancelled : 1; + } tx; + + /** Firmware IO operation callbacks */ + const esp_ble_mesh_blob_io_t *io; + + /** BLOB Transfer Client transfer inputs. */ + const esp_ble_mesh_blob_cli_inputs_t *inputs; + + /** BLOB transfer. */ + const esp_ble_mesh_blob_xfer_t *xfer; + + /** Interval between chunk transmissions, in milliseconds. */ + uint32_t chunk_interval_ms; + + /** BLOCK count */ + uint16_t block_count; + + /** CHUNK index */ + uint16_t chunk_idx; + + /** Max Transfer Unit Size of BLOB Transfer */ + uint16_t mtu_size; + + /** State of blob client mode transfer */ + esp_ble_mesh_blob_cli_state_t state; + + /** BLOB transfer data block. */ + esp_ble_mesh_blob_block_t block; + + /** Transfer capabilities of a Target node. */ + esp_ble_mesh_blob_cli_caps_t caps; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_BLOB_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h new file mode 100644 index 000000000000..6ef42d3dd817 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h @@ -0,0 +1,1988 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_DFU_MODEL_API_H_ +#define _ESP_BLE_MESH_DFU_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_blob_model_api.h" +#include "esp_ble_mesh_dfu_slot_api.h" + +#if CONFIG_BLE_MESH_DFU_CLI || CONFIG_BLE_MESH_DFU_SRV +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_DFU_CLI || CONFIG_BLE_MESH_DFU_SRV */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x08) +#define ESP_BLE_MESH_DFU_OP_UPDATE_INFO_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x09) + +#define ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0a) +#define ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0b) + +#define ESP_BLE_MESH_DFU_OP_UPDATE_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0c) +#define ESP_BLE_MESH_DFU_OP_UPDATE_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0d) +#define ESP_BLE_MESH_DFU_OP_UPDATE_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0e) +#define ESP_BLE_MESH_DFU_OP_UPDATE_APPLY ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0f) +#define ESP_BLE_MESH_DFU_OP_UPDATE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x10) + +/* Distribution Receivers Management Operations (Section 4.3.1) */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD ESP_BLE_MESH_MODEL_OP_2(0x83, 0x11) /*!< Add receivers to the distribution list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x12) /*!< Delete all receivers from the distribution list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x13) /*!< Status of receivers add/delete operations. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x14) /*!< Get the distribution receivers list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_LIST ESP_BLE_MESH_MODEL_OP_2(0x83, 0x15) /*!< List of distribution receivers. */ + +/* Distribution Capabilities Operations (Section 4.3.2) */ +#define ESP_BLE_MESH_DFD_OP_CAPABILITIES_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x16) /*!< Get distribution capabilities of the node. */ +#define ESP_BLE_MESH_DFD_OP_CAPABILITIES_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x17) /*!< Distribution capabilities status. */ + +/* Firmware Distribution Control Operations (Section 4.3.3) */ +#define ESP_BLE_MESH_DFD_OP_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x18) /*!< Get current firmware distribution status. */ +#define ESP_BLE_MESH_DFD_OP_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x19) /*!< Start firmware distribution to receivers. */ +#define ESP_BLE_MESH_DFD_OP_SUSPEND ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1a) /*!< Suspend ongoing firmware distribution. */ +#define ESP_BLE_MESH_DFD_OP_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1b) /*!< Cancel firmware distribution. */ +#define ESP_BLE_MESH_DFD_OP_APPLY ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1c) /*!< Apply distributed firmware on target nodes. */ +#define ESP_BLE_MESH_DFD_OP_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1d) /*!< Firmware distribution status. */ + +/* Firmware Upload Management Operations (Section 4.3.4) */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1e) /*!< Get firmware upload status and progress. */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1f) /*!< Start firmware upload (in-band transfer). */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB ESP_BLE_MESH_MODEL_OP_2(0x83, 0x20) /*!< Start firmware upload (out-of-band transfer). */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x21) /*!< Cancel firmware upload. */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x22) /*!< Firmware upload status and progress. */ + +/* Firmware Image Management Operations (Section 4.3.5) */ +#define ESP_BLE_MESH_DFD_OP_FW_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x23) /*!< Get firmware image information by FW ID. */ +#define ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX ESP_BLE_MESH_MODEL_OP_2(0x83, 0x24) /*!< Get firmware image information by index. */ +#define ESP_BLE_MESH_DFD_OP_FW_DELETE ESP_BLE_MESH_MODEL_OP_2(0x83, 0x25) /*!< Delete specific firmware image. */ +#define ESP_BLE_MESH_DFD_OP_FW_DELETE_ALL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x26) /*!< Delete all firmware images. */ +#define ESP_BLE_MESH_DFD_OP_FW_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x27) /*!< Firmware image management status. */ + +/* Device Firmware Distribution Constants and Status Codes */ +#define ESP_BLE_MESH_DFD_UPLOAD_PROGRESS_UNSET 101 /*!< Upload progress is not set/available. */ +#define ESP_BLE_MESH_DFD_UPLOAD_TYPE_INBAND 0 /*!< In-band firmware upload type. */ +#define ESP_BLE_MESH_DFD_UPLOAD_TYPE_OOB BIT0 /*!< Out-of-band firmware upload type. */ + +#if CONFIG_BLE_MESH_DFU_CLI +/** + * @brief Define a new DFU Client model. + * + * @note This API needs to be called for each element on which + * the application needs to have a DFU Client model. + * + * @param cli_pub Pointer to the unique `esp_ble_mesh_model_pub_t`. + * @param cli_data Pointer to the unique `esp_ble_mesh_client_t`. + * + * @return New DFU Client model instance. + */ +#define ESP_BLE_MESH_MODEL_DFU_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_MODEL_BLOB_CLI(NULL, &(cli_data)->blob), \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFU_CLI, \ + NULL, cli_pub, cli_data) + + +/** + * @brief Initialize a DFU Client model instance. + * + * @note This macro initializes the DFU Client model and sets callback handlers. + * + * @param _handlers Pointer to the callback handler structure `esp_ble_mesh_dfu_cli_cb_t`. + * + * @return An initialized DFU Client model instance. + */ +#define ESP_BLE_MESH_DFU_CLI_INIT(_handlers) \ +{ \ + .cb = _handlers, \ +} +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** + * @brief Define a new DFU Server model. + * + * @note This API needs to be called for each element on which + * the application needs to have a DFU Server model. + * + * @param srv_pub Pointer to the unique `esp_ble_mesh_model_pub_t`. + * @param srv_data Pointer to the unique `esp_ble_mesh_dfu_trans_srv_t`. + * + * @return New DFU Server model instance. + */ +#define ESP_BLE_MESH_MODEL_DFU_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_MODEL_BLOB_SRV(NULL, &(srv_data)->blob), \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFU_SRV, \ + NULL, srv_pub, srv_data) + + +/** + * @brief Initialize a DFU Server model instance. + * + * @note This macro initializes the DFU Server model and sets callback handlers + * and image information. + * + * @param _handlers Pointer to the callback handler structure `esp_ble_mesh_dfu_srv_cb_t`. + * @param _imgs Pointer to the array of DFU images `esp_ble_mesh_dfu_img_t`. + * @param _img_count Number of DFU images in the array. + * + * @return An initialized DFU Server model instance. + */ +#define ESP_BLE_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ + { \ + .cb = _handlers, \ + .imgs = _imgs, .img_count = _img_count, \ + } +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +/** + * @def ESP_BLE_MESH_MODEL_DFD_CLI + * + * @brief Define a new Device Firmware Distribution Client model. + * + * Define a DFD Client model for managing firmware distribution operations, + * including receiver lists, upload control, progress monitoring, and + * firmware transfers. + * + * @param cli_pub Pointer to the unique `esp_ble_mesh_model_pub_t` for publish messages. + * @param cli_data Pointer to the unique `esp_ble_mesh_client_t` containing client data. + * + * @return New DFD Client model instance. + */ +#define ESP_BLE_MESH_MODEL_DFD_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFD_CLI, \ + NULL, cli_pub, cli_data) +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @def ESP_BLE_MESH_MODEL_DFD_SRV + * + * @brief Define a new Device Firmware Distribution Server model. + * + * Define a DFD Server model that stores firmware, distributes to targets, + * handles uploads, manages receiver lists, and controls distribution phases. + * Contains internal DFU Client for updates and BLOB Server for transfers. + * + * @param srv_pub Pointer to the unique `esp_ble_mesh_model_pub_t` for publish messages. + * @param srv_data Pointer to the unique `esp_ble_dfd_trans_srv_t` containing server data. + * + * @return New DFD Server model instance. + */ +#define ESP_BLE_MESH_MODEL_DFD_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_MODEL_DFU_CLI(NULL, &(srv_data)->dfu), \ + ESP_BLE_MESH_MODEL_BLOB_SRV(NULL, &((srv_data)->upload.blob)),\ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFD_SRV, \ + NULL, srv_pub, srv_data) + +/* Internal callback structures for DFD Server implementation */ +extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb; /*!< Internal DFU Client callbacks for DFD Server. */ +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb; /*!< Internal BLOB Server callbacks for DFD Server. */ + +/** + * @def ESP_BLE_MESH_DFD_SRV_INIT + * + * @brief Initialize a Device Firmware Distribution Server. + * + * Initialize a DFD Server instance with the provided callback structure + * and set up the internal DFU Client and BLOB Server components. + * + * @param _cb Pointer to a `bt_mesh_dfd_srv_cb` instance containing the server callbacks. + * + * @return Initialized DFD Server structure with internal components configured. + */ +#define ESP_BLE_MESH_DFD_SRV_INIT(_cb) \ + { \ + .cb = _cb, \ + .dfu = ESP_BLE_MESH_DFU_CLI_INIT((struct esp_ble_mesh_dfu_cli_cb *) \ + &_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = (esp_ble_mesh_blob_srv_cb_t *) \ + &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + } +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + +/** @brief DFU image structure. **/ +typedef struct esp_ble_mesh_dfu_img esp_ble_mesh_dfu_img_t; + +#if CONFIG_BLE_MESH_DFU_CLI +/** @brief DFU Client model instance structure. + * + * This structure represents a DFU (Device Firmware Update) Client model instance. + * It contains the necessary fields for managing DFU operations as a client. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_cli esp_ble_mesh_dfu_cli_t; + +/** @brief DFU iteration action enumeration. + * + * This enumeration defines the possible actions that can be taken + * during DFU iteration callbacks. It controls whether to continue + * or stop iterating through DFU images. + */ +typedef enum esp_ble_mesh_dfu_iter esp_ble_mesh_dfu_iter_t; + +/** @brief DFU image callback. + * + * The image callback is called for every DFU image on the Target node when + * calling bt_mesh_dfu_cli_imgs_get. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context of the received message. + * @param idx Image index. + * @param total Total number of images on the Target node. + * @param img Image information for the given image index. + * @param cb_data Callback data. + * + * @retval ESP_BLE_MESH_DFU_ITER_STOP Stop iterating through the image list and + * return from bt_mesh_dfu_cli_imgs_get. + * @retval ESP_BLE_MESH_DFU_ITER_CONTINUE Continue iterating through the image list + * if any images remain. + */ +typedef esp_ble_mesh_dfu_iter_t (*esp_ble_mesh_dfu_img_cb_t)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t idx, + uint8_t total, const esp_ble_mesh_dfu_img_t *img, + void *cb_data); +/** @brief DFU image slot structure. + * + * This structure represents a DFU image slot used for DFU distribution. + * It contains information about the firmware image including size, + * firmware ID, metadata, and their respective lengths. + */ +typedef struct esp_ble_mesh_dfu_slot esp_ble_mesh_dfu_slot_t; + +/** @brief DFU Target node structure. + * + * This structure represents a DFU Target node in the mesh network. + * It contains information about the target's BLOB transfer status, + * image index, expected DFU effect, current status, and phase. + */ +typedef struct esp_ble_mesh_dfu_target esp_ble_mesh_dfu_target_t; + +/** @brief DFU Client callback structure. + * + * This structure contains callback function pointers for DFU Client events + * such as transfer suspension, completion, application, confirmation, + * and target node loss. + */ +typedef struct esp_ble_mesh_dfu_cli_cb esp_ble_mesh_dfu_cli_cb_t; + +/** @brief DFU Client model instance structure. + * + * This structure represents a DFU (Device Firmware Update) Client model instance. + * It contains the necessary fields for managing DFU operations as a client. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_cli esp_ble_mesh_dfu_cli_t; + +/** @brief DFU Client BLOB transfer parameters structure. + * + * This structure contains parameters for BLOB transfer during DFU operations, + * including block size logarithmic representation and base chunk size. + */ +typedef struct esp_ble_mesh_dfu_cli_xfer_blob_params esp_ble_mesh_dfu_cli_xfer_blob_params_t; + +/** @brief DFU Client transfer parameters structure. + * + * This structure contains parameters for DFU transfer operations, + * including BLOB ID, image slot, transfer mode, and BLOB parameters. + */ +typedef struct esp_ble_mesh_dfu_cli_xfer esp_ble_mesh_dfu_cli_xfer_t; + +/** @brief Device Firmware Update Info Get parameters structure. + * + * This structure contains parameters for the Firmware Update Information Get message, + * including the first index and entries limit for requesting firmware information. + */ +typedef struct esp_ble_mesh_device_firmware_update_info_get esp_ble_mesh_device_firmware_update_info_get_t; + +/** @brief Device Firmware Update Metadata Check parameters structure. + * + * This structure contains parameters for the Firmware Update Metadata Check message, + * including the update firmware index and vendor-specific metadata. + */ +typedef struct esp_ble_mesh_device_firmware_update_metadata_check esp_ble_mesh_device_firmware_update_metadata_check_t; + +/** @brief DFU Client get message union. + * + * This union contains different parameter structures for various DFU Client + * get messages, allowing type-safe access to message-specific parameters. + */ +typedef union esp_ble_mesh_dfu_client_get esp_ble_mesh_dfu_client_get_t; + +/** @brief DFU Client send arguments structure. + * + * This structure contains arguments for sending firmware via DFU Client, + * including the client instance, transfer inputs, BLOB stream, and transfer parameters. + */ +typedef struct esp_ble_mesh_dfu_cli_send_arg esp_ble_mesh_dfu_cli_send_arg_t; + +/** @brief Firmware information structure. + * + * This structure contains information about firmware including firmware ID + * and update URI for retrieving new firmware. + */ +typedef struct esp_ble_mesh_firmware_info esp_ble_mesh_firmware_info_t; + +/** @brief Device Firmware Update Info Status response structure. + * + * This structure contains the response parameters for Firmware Update Information + * Status message, including firmware information list count and details. + */ +typedef struct esp_ble_mesh_device_firmware_update_info_status esp_ble_mesh_device_firmware_update_info_status_t; + +/** @brief Device Firmware Update Metadata Check Status response structure. + * + * This structure contains the response parameters for Firmware Update Metadata + * Check Status message, including status code and additional information. + */ +typedef struct esp_ble_mesh_device_firmware_metadata_check_status esp_ble_mesh_device_firmware_metadata_check_status_t; + +/** @brief Device Firmware Update Status response structure. + * + * This structure contains the response parameters for various Firmware Update + * Status messages (Get, Start, Cancel, Apply), including status, phase, + * TTL, timeout base, BLOB ID, and firmware image index. + */ +typedef struct esp_ble_mesh_device_firmware_update_status esp_ble_mesh_device_firmware_update_status_t; + +/** @brief DFU Client send callback structure. + * + * This structure contains the result of sending DFU Client messages, + * including error code indicating success or failure. + */ +typedef struct esp_ble_mesh_dfu_client_send_cb esp_ble_mesh_dfu_client_send_cb_t; + +/** @brief DFU Client receive callback union. + * + * This union contains different response structures for various DFU Client + * received status messages, allowing type-safe access to message-specific responses. + */ +typedef union esp_ble_mesh_dfu_client_recv_cb esp_ble_mesh_dfu_client_recv_cb_t; + +/** @brief DFU Client callback parameters structure. + * + * This structure contains parameters for DFU Client callbacks, including + * common client parameters and a union of send/receive callback data. + */ +typedef struct esp_ble_mesh_dfu_client_cb_param esp_ble_mesh_dfu_client_cb_param_t; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** @brief Firmware Update Server instance structure. + * + * This structure represents a DFU (Device Firmware Update) Server model instance. + * It contains the necessary fields for managing DFU operations as a server. + * Should be initialized with ESP_BLE_MESH_DFU_SRV_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_srv esp_ble_mesh_dfu_srv_t; + +/** @brief Firmware Update Server callback structure. + * + * This structure contains callback function pointers for DFU Server events + * such as transfer check, start, end, recovery, and apply. + */ +typedef struct esp_ble_mesh_dfu_srv_cb esp_ble_mesh_dfu_srv_cb_t; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +/* DFD Client Forward Declarations */ +typedef enum esp_ble_mesh_dfd_client_act esp_ble_mesh_dfd_client_act_t; /*!< DFD Client action enumeration. */ +typedef enum esp_ble_mesh_dfd_client_cb_evt esp_ble_mesh_dfd_client_cb_evt_t; /*!< DFD Client callback event enumeration. */ +typedef struct esp_ble_mesh_dfd_cli_receiver_entry esp_ble_mesh_dfd_cli_receiver_entry_t; /*!< DFD Client receiver entry structure. */ + +/* DFD Client Receiver Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_receivers_add esp_ble_mesh_dfd_cli_receivers_add_t; /*!< Parameters for adding receivers to distribution list. */ +typedef struct esp_ble_mesh_dfd_receiver_status esp_ble_mesh_dfd_receiver_status_t; /*!< Status response for receiver operations. */ + +typedef struct esp_ble_mesh_dfd_receivers_get esp_ble_mesh_dfd_receivers_get_t; /*!< Parameters for getting distribution receivers list. */ +typedef struct esp_ble_mesh_dfd_target_node_entry esp_ble_mesh_dfd_target_node_entry_t; /*!< Target node entry information. */ +typedef struct esp_ble_mesh_dfd_receiver_list esp_ble_mesh_dfd_receiver_list_t; /*!< Distribution receivers list response. */ + +/* DFD Client Distribution Control Structures */ +typedef struct esp_ble_mesh_dfd_dist_caps esp_ble_mesh_dfd_dist_caps_t; /*!< Distribution capabilities of the DFD Server. */ + +typedef struct esp_ble_mesh_dfd_cli_dist_start esp_ble_mesh_dfd_cli_dist_start_t; /*!< Parameters for starting firmware distribution. */ +typedef struct esp_ble_mesh_dfd_dist_status esp_ble_mesh_dfd_dist_status_t; /*!< Firmware distribution status response. */ + +/* DFD Client Upload Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_dist_upload_start esp_ble_mesh_dfd_cli_dist_upload_start_t; /*!< Parameters for starting in-band firmware upload. */ +typedef struct esp_ble_mesh_dfd_cli_dist_upload_oob_start esp_ble_mesh_dfd_cli_dist_upload_oob_start_t; /*!< Parameters for starting out-of-band firmware upload. */ +typedef struct esp_ble_mesh_dfd_upload_status esp_ble_mesh_dfd_upload_status_t; /*!< Firmware upload status and progress. */ + +/* DFD Client Firmware Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_get esp_ble_mesh_dfd_cli_dist_fw_get_t; /*!< Parameters for getting firmware by FW ID. */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_get_by_idx esp_ble_mesh_dfd_cli_dist_fw_get_by_idx_t; /*!< Parameters for getting firmware by index. */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_del esp_ble_mesh_dfd_cli_dist_fw_del_t; /*!< Parameters for deleting firmware. */ +typedef struct esp_ble_mesh_dfd_firmware_status esp_ble_mesh_dfd_firmware_status_t; /*!< Firmware management status response. */ + +/* DFD Client Callback Structures */ +typedef struct esp_ble_mesh_dfd_client_cb_param esp_ble_mesh_dfd_client_cb_param_t; /*!< DFD Client callback parameters. */ +typedef union esp_ble_mesh_dfd_client_common_cb_param esp_ble_mesh_dfd_client_common_cb_param_t; /*!< Common callback parameter union. */ + +/* DFD Client Callback Function Type */ +typedef void (*esp_ble_mesh_dfd_client_cb_t)(esp_ble_mesh_dfd_client_cb_evt_t event, /*!< DFD Client callback function type. */ + esp_ble_mesh_dfd_client_cb_param_t *param); +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @brief Firmware Distribution status enumeration. + * + * This enumeration defines the status codes used in DFD operations + * according to the Bluetooth Mesh Model Specification v1.0. These + * status codes indicate success, failure, and error conditions + * for various firmware distribution operations. + */ +typedef enum esp_ble_mesh_dfd_status esp_ble_mesh_dfd_status_t; + +/** + * @brief Firmware distribution phases enumeration. + * + * This enumeration defines the different phases of a firmware distribution + * operation as specified in the Bluetooth Mesh Model Specification v1.0. + * The phases track the state of firmware distribution from idle through + * transfer, verification, application, and completion states. + */ +typedef enum esp_ble_mesh_dfd_phase esp_ble_mesh_dfd_phase_t; + +/** + * @brief Firmware upload phases enumeration. + * + * This enumeration defines the phases of firmware upload operations + * on the DFD Server. It tracks the state of firmware storage procedures + * including in-band and out-of-band upload methods. + */ +typedef enum esp_ble_mesh_dfd_upload_phase esp_ble_mesh_dfd_upload_phase_t; + +/** + * @brief Firmware Distribution Server callback structure. + * + * This structure contains callback function pointers that allow the + * application to handle various DFD Server events including firmware + * reception, distribution control, and phase changes. + */ +typedef struct esp_ble_mesh_dfd_srv_cb esp_ble_mesh_dfd_srv_cb_t; + +/** + * @brief Firmware Distribution Server instance structure. + * + * This structure represents a DFD Server model instance that manages + * firmware distribution operations. It contains state information for + * ongoing distributions, firmware storage, and target node management. + */ +typedef struct esp_ble_mesh_dfd_srv esp_ble_mesh_dfd_srv_t; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + +/** DFU transfer phase. */ +typedef enum esp_ble_mesh_dfu_phase { + /** Ready to start a Receive Firmware procedure. */ + ESP_BLE_MESH_DFU_PHASE_IDLE, + + /** The Transfer BLOB procedure failed. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_ERR, + + /** The Receive Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE, + + /** The Verify Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY, + + /** The Verify Firmware procedure completed successfully. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY_OK, + + /** The Verify Firmware procedure failed. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY_FAIL, + + /** The Apply New Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_APPLYING, + + /** Firmware transfer has been canceled. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_CANCELED, + + /** Firmware applying succeeded. */ + ESP_BLE_MESH_DFU_PHASE_APPLY_SUCCESS, + + /** Firmware applying failed. */ + ESP_BLE_MESH_DFU_PHASE_APPLY_FAIL, + + /** Phase of a node was not yet retrieved. */ + ESP_BLE_MESH_DFU_PHASE_UNKNOWN, +} esp_ble_mesh_dfu_phase_t; + +/** Expected effect of a DFU transfer. */ +typedef enum esp_ble_mesh_dfu_effect { + /** No changes to node Composition Data. */ + ESP_BLE_MESH_DFU_EFFECT_NONE, + + /** Node Composition Data changed and the node does not support remote + * provisioning. + */ + ESP_BLE_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, + + /** Node Composition Data changed, and remote provisioning is supported. + * The node supports remote provisioning and Composition Data Page + * 0x80. Page 0x80 contains different Composition Data than Page 0x0. + */ + ESP_BLE_MESH_DFU_EFFECT_COMP_CHANGE, + + /** Node will be unprovisioned after the update. */ + ESP_BLE_MESH_DFU_EFFECT_UNPROV, +} esp_ble_mesh_dfu_effect_t; + +/** DFU status. */ +typedef enum esp_ble_mesh_dfu_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_DFU_SUCCESS, + + /** Insufficient resources on the node */ + ESP_BLE_MESH_DFU_ERR_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + ESP_BLE_MESH_DFU_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + ESP_BLE_MESH_DFU_ERR_INTERNAL, + + /** The message contains a firmware index value that is not expected. */ + ESP_BLE_MESH_DFU_ERR_FW_IDX, + + /** The metadata check failed. */ + ESP_BLE_MESH_DFU_ERR_METADATA, + + /** The Server cannot start a firmware update. */ + ESP_BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, + + /** Another BLOB transfer is in progress. */ + ESP_BLE_MESH_DFU_ERR_BLOB_XFER_BUSY, +} esp_ble_mesh_dfu_status_t; + +#if CONFIG_BLE_MESH_DFU_CLI +/** Action for DFU iteration callbacks. */ +enum esp_ble_mesh_dfu_iter { + /** Stop iterating. */ + ESP_BLE_MESH_DFU_ITER_STOP, + + /** Continue iterating. */ + ESP_BLE_MESH_DFU_ITER_CONTINUE, +}; + +/** @brief DFU transfer states + * + * This enumeration defines the various states of a DFU (Device Firmware Update) transfer. + * These states track the progress of firmware distribution from idle state through + * transfer, verification, application, and confirmation phases. + */ +typedef enum esp_ble_mesh_dfu_xfer_state { + /** Idle state - No DFU transfer is in progress. */ + ESP_BLE_MESH_DFU_XFER_IDLE, + + /** Transfer state - Firmware data is being transferred to target nodes. */ + ESP_BLE_MESH_DFU_XFER_TRANSFER, + + /** Refresh state - Transfer is paused or being refreshed. */ + ESP_BLE_MESH_DFU_XFER_REFRESH, + + /** Verified state - Firmware has been successfully verified on target nodes. */ + ESP_BLE_MESH_DFU_XFER_VERIFIED, + + /** Apply state - Firmware is being applied on target nodes. */ + ESP_BLE_MESH_DFU_XFER_APPLY, + + /** Applied state - Firmware has been successfully applied on target nodes. */ + ESP_BLE_MESH_DFU_XFER_APPLIED, + + /** Confirm state - Waiting for confirmation from target nodes. */ + ESP_BLE_MESH_DFU_XFER_CONFIRM, + + /** Cancel state - DFU transfer has been cancelled. */ + ESP_BLE_MESH_DFU_XFER_CANCEL, + + /** Suspended state - DFU transfer has been suspended. */ + ESP_BLE_MESH_DFU_XFER_SUSPENDED, +} esp_ble_mesh_dfu_xfer_state_t; + +/** @brief Callback events of Device Firmware Update Client Model + * + * This enumeration defines the various callback events that can be generated + * by the DFU (Device Firmware Update) Client model. These events are used + * to notify the application about different stages and states of the DFU process, + * including message sending, timeouts, response reception, and image transfer completion. + */ +typedef enum { + /** DFU Client message sending completed event. + * This event is triggered when a DFU Client message has been successfully sent. + */ + ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT, + + /** DFU Client timeout event. + * This event is triggered when a DFU Client operation times out waiting for a response. + */ + ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT, + + /** DFU Client received Get response event. + * This event is triggered when the DFU Client receives a response to a Get message. + */ + ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT, + + /** DFU Client image send completed event. + * This event is triggered when the DFU Client has completed sending a firmware image. + */ + ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT, + + /** Maximum DFU Client event value (used for bounds checking). */ + ESP_BLE_MESH_DFU_CLIENT_EVT_MAX, +} esp_ble_mesh_dfu_client_cb_event_t; + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +/** DFU image instance. + * + * Each DFU image represents a single updatable firmware image. + */ +struct esp_ble_mesh_dfu_img { + /** Firmware ID. */ + const void *fwid; + + /** Length of the firmware ID. */ + size_t fwid_len; + + /** Update URI, or NULL. */ + const char *uri; +}; + +#if CONFIG_BLE_MESH_DFU_CLI +/** DFU image slot for DFU distribution. */ +struct esp_ble_mesh_dfu_slot { + /** Size of the firmware in bytes. */ + size_t size; + /** Length of the firmware ID. */ + size_t fwid_len; + /** Length of the metadata. */ + size_t metadata_len; + /** Firmware ID. */ + uint8_t fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + /** Metadata. */ + uint8_t metadata[CONFIG_BLE_MESH_DFU_METADATA_MAXLEN]; +}; + +/** DFU Target node. */ +struct esp_ble_mesh_dfu_target { + /** BLOB Target node */ + esp_ble_mesh_blob_target_t blob; + /** Image index on the Target node */ + uint8_t img_idx; + /** Expected DFU effect, see bt_mesh_dfu_effect. */ + uint8_t effect; + /** Current DFU status, see bt_mesh_dfu_status. */ + uint8_t status; + /** Current DFU phase, see bt_mesh_dfu_phase. */ + uint8_t phase; +}; + +/** Firmware Update Client event callbacks. */ +struct esp_ble_mesh_dfu_cli_cb { + /** @brief BLOB transfer is suspended. + * + * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. + * + * @param cli Firmware Update Client model instance. + */ + void (*suspended)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU ended. + * + * Called when the DFU transfer ends, either because all Target nodes were + * lost or because the transfer was completed successfully. + * + * @param cli Firmware Update Client model instance. + * @param reason Reason for ending. + */ + void (*ended)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_dfu_status_t reason); + + /** @brief DFU transfer applied on all active Target nodes. + * + * Called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + */ + void (*applied)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU transfer confirmed on all active Target nodes. + * + * Called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + */ + void (*confirmed)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU Target node was lost. + * + * A DFU Target node was dropped from the receivers list. The Target node's + * @c status is set to reflect the reason for the failure. + * + * @param cli Firmware Update Client model instance. + * @param target DFU Target node that was lost. + */ + void (*lost_target)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_dfu_target_t *target); +}; + +/** Firmware Update Client model instance. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_dfu_cli { + /** Callback structure. */ + const esp_ble_mesh_dfu_cli_cb_t *cb; + /** Underlying BLOB Transfer Client. */ + esp_ble_mesh_blob_cli_t blob; + + /** runtime state */ + uint32_t op; + + /** ble mesh model instance. */ + esp_ble_mesh_model_t *mod; + + /** BLOB Transfer information */ + struct { + const esp_ble_mesh_dfu_slot_t *slot; + const esp_ble_mesh_blob_io_t *io; + esp_ble_mesh_blob_xfer_t blob; + uint8_t state; + uint8_t flags; + } xfer; + + /** Current request */ + void *req; +}; + +/** BLOB parameters for Firmware Update Client transfer */ +struct esp_ble_mesh_dfu_cli_xfer_blob_params { + /** Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** Firmware Update Client transfer parameters */ +struct esp_ble_mesh_dfu_cli_xfer { + /** BLOB ID to use for this transfer, or 0 to set it randomly. */ + uint64_t blob_id; + /** DFU image slot to transfer. */ + const esp_ble_mesh_dfu_slot_t *slot; + /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ + enum esp_ble_mesh_blob_xfer_mode mode; + /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' + * capabilities before sending a firmware. + */ + const esp_ble_mesh_dfu_cli_xfer_blob_params_t *blob_params; +}; + +/** + * @brief Parameters of Device Firmware Update Info Get. + */ +struct esp_ble_mesh_device_firmware_update_info_get { + uint8_t first_index; /*!< Index of the first requested entry from the Firmware Information List state */ + uint8_t entries_limit; /*!< Maximum number of entries that the server includes in a Firmware Update Information Status message */ + esp_ble_mesh_dfu_img_cb_t img_cb; /*!< Added by Espressif, callback function used to walkthrough received images */ +}; + +/** + * @brief Parameters of Device Firmware Update Firmware Metadata Check. + */ +struct esp_ble_mesh_device_firmware_update_metadata_check { + uint8_t update_firmware_index; /*!< Index of the firmware image in the Firmware Information List state to check */ + struct net_buf_simple *metadata; /*!< Vendor-specific metadata */ +}; + +/** + * @brief Device Firmware Update Client model get message union. + * For ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET + * ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK + * ESP_BLE_MESH_DFU_OP_UPDATE_START + * the get_state parameter in the `esp_ble_mesh_dfu_client_get_state` function should not be set to NULL. + */ +union esp_ble_mesh_dfu_client_get { + esp_ble_mesh_device_firmware_update_info_get_t dfu_update_info_get; /*!< For ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET */ + esp_ble_mesh_device_firmware_update_metadata_check_t dfu_metadata_check; /*!< For ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK */ +}; + +/** + * @brief Parameters of Device Firmware Update Client + * model to send Firmware. + */ +struct esp_ble_mesh_dfu_cli_send_arg { + esp_ble_mesh_dfu_cli_t *cli; /*!< Device Firmware Update Client model instance */ + esp_ble_mesh_blob_cli_inputs_t *inputs; /*!< BLOB Transfer Client transfer inputs. */ + esp_ble_mesh_blob_io_t *io; /*!< BLOB stream. */ + esp_ble_mesh_dfu_cli_xfer_t *xfer; /*!< Firmware Update Client transfer parameters */ +}; + +/** + * @brief Struct of firmware information. + */ +struct esp_ble_mesh_firmware_info { + struct net_buf_simple *fw_id; /*!< Firmware ID */ + struct net_buf_simple *update_uri; /*!< URI used to retrieve a new firmware */ +}; + +/** + * @brief Response of Firmware Update Information Get Message + */ +struct esp_ble_mesh_device_firmware_update_info_status { + uint8_t fw_info_list_cnt; /*!< The number of entries in the Firmware Information List */ + uint8_t first_index; /*!< Index of the first requested entry from the Firmware Information List */ + esp_ble_mesh_firmware_info_t *fw_info_list; /*!< List of firmware information entries */ +}; + +/** + * @brief Response of Firmware Update Firmware Metadata Check Message + */ +struct esp_ble_mesh_device_firmware_metadata_check_status { + uint8_t status : 3; /*!< Status Code from the firmware metadata check */ + uint8_t additional_info : 5; /*!< The Firmware Update Additional Information state from the Firmware Update Server (see Section 4.1.3)*/ + uint8_t update_firmware_image_index; /*!< Index of the firmware image in the Firmware Information List state that was checked*/ +}; + +/** + * @brief Response of Firmware Update Get Message, + * Firmware Update Start Message, + * Firmware Update Cancel Message, + * Firmware Update Apply Message. + */ +struct esp_ble_mesh_device_firmware_update_status { + uint8_t status : 3; /*!< Status Code for the requesting message */ + uint8_t update_phase : 3; /*!< The Update Phase state of the Firmware Update Server */ + uint8_t update_ttl; /*!< TTL value to use during firmware image transfer */ + uint8_t additional_info : 5; /*!< The Firmware Update Additional Information state from the Firmware Update Server (see Section 4.1.3)*/ + uint16_t update_timeout_base; /*!< Used to compute the timeout of the firmware image transfer */ + uint64_t update_blob_id; /*!< BLOB identifier for the firmware image */ + uint8_t update_fw_img_idx; /*!< The index of the firmware image in the Firmware Information List state being updated*/ +}; + +/** Result of sending Device Firmware Update Client messages */ +struct esp_ble_mesh_dfu_client_send_cb { + int err_code; /*!< Result of sending a message */ +}; + +/** + * @brief Device Firmware Update Client model received message union + */ +union esp_ble_mesh_dfu_client_recv_cb { + esp_ble_mesh_device_firmware_update_info_status_t dfu_update_info_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_STATUS */ + esp_ble_mesh_device_firmware_metadata_check_status_t dfu_metadata_check_status; /*!< ESP_BLE_MESH_MODEL_OP_PATH_METRIC_STATUS */ + esp_ble_mesh_device_firmware_update_status_t dfu_firmware_update_status; /*!< ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_STATUS */ +}; + +/** Device Firmware Update Client model callback parameters */ +struct esp_ble_mesh_dfu_client_cb_param { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of DF Client callback */ + union { + esp_ble_mesh_dfu_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_dfu_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +}; + +/** + * @brief Bluetooth Mesh Device Firmware Update client and server model functions. + */ + +/** + * @brief Device Firmware Update Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_dfu_client_cb_t)(esp_ble_mesh_dfu_client_cb_event_t event, + esp_ble_mesh_dfu_client_cb_param_t *param); + +/** + * @brief Device Firmware Update Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_dfu_server_cb_t)(esp_ble_mesh_dfu_client_cb_event_t event, + esp_ble_mesh_dfu_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Device Firmware Update Client model callback. + * + * @param callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_dfu_client_callback(esp_ble_mesh_dfu_client_cb_t callback); + +/** + * @brief Get the value of Device Firmware Server model state with the corresponding get message. + * + * @param params: Pointer to BLE Mesh common client parameters. + * @param get: Pointer to a union, each kind of opcode corresponds to one structure inside. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get); + +/** @brief Start distributing a DFU. + * + * Starts distribution of the firmware in the given slot to the list of DFU + * Target nodes in @c ctx. The transfer runs in the background, and its end is + * signalled through the bt_mesh_dfu_cli_cb::ended callback. + * + * @note The BLOB Transfer Client transfer inputs @c targets list must point to a list of + * bt_mesh_dfu_target nodes. The contents of `inputs`, `io`, `xfer` must not be changed or + * released from the beginning to the end of the transmission. + * + * @param cli Firmware Update Client model instance. + * @param inputs BLOB Transfer Client transfer inputs. + * @param io BLOB stream to read BLOB from. + * @param xfer Firmware Update Client transfer parameters. + * + * @return 0 on success, or (negative) error code otherwise. + */ +esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_blob_cli_inputs_t *inputs, + esp_ble_mesh_blob_io_t *io, + esp_ble_mesh_dfu_cli_xfer_t *xfer); + +/** @brief Get progress as a percentage of completion. + * + * @param cli Firmware Update Client model instance. + * + * @return The progress of the current transfer in percent, or 0 if no + * transfer is active. + */ +uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli); +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** @brief Firmware Update Server event callbacks. */ +struct esp_ble_mesh_dfu_srv_cb { + /** @brief Transfer check callback. + * + * The transfer check can be used to validate the incoming transfer + * before it starts. The contents of the metadata is implementation + * specific, and should contain all the information the application + * needs to determine whether this image should be accepted, and what + * the effect of the transfer would be. + * + * If applying the image will have an effect on the provisioning state + * of the mesh stack, this can be communicated through the @c effect + * return parameter. + * + * The metadata check can be performed both as part of starting a new + * transfer and as a separate procedure. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image the metadata check is performed on. + * @param metadata Image metadata. + * @param effect Return parameter for the image effect on the + * provisioning state of the mesh stack. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*check)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + struct net_buf_simple *metadata, + esp_ble_mesh_dfu_effect_t *effect); + + /** @brief Transfer start callback. + * + * Called when the Firmware Update Server is ready to start a new DFU transfer. + * The application must provide an initialized BLOB stream to be used + * during the DFU transfer. + * + * The following error codes are treated specially, and should be used + * to communicate these issues: + * - @c -ENOMEM: The device cannot fit this image. + * - @c -EBUSY: The application is temporarily unable to accept the + * transfer. + * - @c -EALREADY: The device has already received and verified this + * image, and there's no need to transfer it again. The Firmware Update model + * will skip the transfer phase, and mark the image as verified. + * + * This handler is mandatory. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param metadata Image metadata. + * @param io BLOB stream return parameter. Must be set to a + * valid BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code otherwise. Return + * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to + * the updater, other error codes are reported as internal + * errors. + */ + int (*start)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + struct net_buf_simple *metadata, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Transfer end callback. + * + * This handler is optional. + * + * If the transfer is successful, the application should verify the + * firmware image, and call either bt_mesh_dfu_srv_verified or + * bt_mesh_dfu_srv_rejected depending on the outcome. + * + * If the transfer fails, the Firmware Update Server will be available for new + * transfers immediately after this function returns. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that failed the update. + * @param success Whether the DFU transfer was successful. + */ + void (*end)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, bool success); + + /** @brief Transfer recovery callback. + * + * If the device reboots in the middle of a transfer, the Firmware Update Server + * calls this function when the Bluetooth mesh subsystem is started. + * + * This callback is optional, but transfers will not be recovered after + * a reboot without it. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param io BLOB stream return parameter. Must be set to a valid BLOB + * stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Transfer apply callback. + * + * Called after a transfer has been validated, and the updater sends an + * apply message to the Target nodes. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that should be applied. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*apply)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img); +}; + +/** @brief Firmware Update Server instance. + * + * Should be initialized with ESP_BLE_MESH_DFU_SRV_INIT. + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_dfu_srv { + /** Underlying BLOB Transfer Server. */ + esp_ble_mesh_blob_srv_t blob; + /** Callback structure. */ + const esp_ble_mesh_dfu_srv_cb_t *cb; + /** List of updatable images. */ + const esp_ble_mesh_dfu_img_t *imgs; + /** Number of updatable images. */ + size_t img_count; + + /** Runtime state */ + esp_ble_mesh_model_t *mod; + /** Update information */ + struct { + /* Effect of transfer, @see bt_mesh_dfu_effect. */ + uint8_t effect; + /* Current phase, @see bt_mesh_dfu_phase. */ + uint8_t phase; + uint8_t ttl; + uint8_t idx; + uint16_t timeout_base; + uint16_t meta; + } update; +}; + +/** @brief Accept the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if the image is ready to be applied. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Reject the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if one of the checks fail. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Cancel the ongoing DFU transfer. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Confirm that the received DFU transfer was applied. + * + * Should be called as a result of the `bt_mesh_dfu_srv_cb.apply` callback. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Check if the Firmware Update Server is busy processing a transfer. + * + * @param srv Firmware Update Server instance. + * + * @return true if a DFU procedure is in progress, false otherwise. + */ +bool esp_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Get the progress of the current DFU procedure, in percent. + * + * @param srv Firmware Update Server instance. + * + * @return The current transfer progress in percent. + */ +uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +/** + * @brief DFD Client receiver entry structure. + * + * This structure represents a single receiver node that will be added + * to the distribution list for firmware updates. Each entry contains + * the target node's address and the specific firmware image index + * that should be distributed to that node. + * + * @note This is used with the DFD Receivers Add message to build + * the distribution receiver list. + */ +struct esp_ble_mesh_dfd_cli_receiver_entry { + /** The unicast address of the target node to receive firmware updates */ + uint16_t addr; + /** Index of the firmware image that should be distributed to this target node */ + uint8_t fw_idx; +}; + +/** + * @brief DFD Client receivers add parameters. + * + * This structure contains the parameters for the DFD Receivers Add + * message. It is used to add multiple target nodes to the distribution + * receiver list. + * + * @note The receivers array should contain valid unicast addresses + * and corresponding firmware image indices. + */ +struct esp_ble_mesh_dfd_cli_receivers_add { + /** Pointer to array of receiver entries to add to the distribution list */ + esp_ble_mesh_dfd_cli_receiver_entry_t *receivers; + /** Number of receiver entries in the receivers array */ + uint16_t receivers_cnt; +}; + +/** + * @brief DFD receiver status response structure. + * + * This structure contains the response parameters for the DFD + * Receivers Add/Delete operations. + * + * The status indicates whether the receiver list modification + * was successful, and the receiver_list_cnt provides the current + * size of the distribution receiver list. + */ +struct esp_ble_mesh_dfd_receiver_status { + /** Status code for the receiver add/delete operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current number of entries in the Distribution Receivers List state */ + uint16_t receiver_list_cnt; +}; + +/** + * @brief DFD receivers get parameters. + * + * This structure contains the parameters for the DFD Receivers Get + * message. It is used to retrieve a portion of the distribution + * receiver list. + * + * @note This supports pagination of large receiver lists by allowing + * the client to request specific ranges of entries. + */ +struct esp_ble_mesh_dfd_receivers_get { + /** Index of the first entry in the Distribution Receivers List to return */ + uint16_t first_index; + /** Maximum number of entries to include in the response */ + uint16_t entries_limit; +}; + +/** + * @brief DFD target node entry structure. + * + * This structure represents the status of a single target node + * in the distribution receiver list. It contains detailed information + * about the target's current update phase, transfer status, and progress. + * + * This is returned in the DFD Receivers List message. + */ +struct esp_ble_mesh_dfd_target_node_entry { + /** Unicast address of the target node (15 bits) */ + uint32_t addr:15, + /** Retrieved update phase of the target node (4 bits, see esp_ble_mesh_dfu_phase) */ + retrieved_update_phase:4, + /** Update status of the target node (3 bits, see esp_ble_mesh_dfu_status) */ + update_status:3, + /** Transfer status of the target node (4 bits) */ + transfer_status:4, + /** Transfer progress percentage of the target node (6 bits, in 2 percent increments) */ + transfer_progress:6; + /** Index of the firmware image being updated on the target node */ + uint8_t update_fw_idx; +}; + +/** + * @brief DFD receiver list response structure. + * + * This structure contains the response parameters for the DFD Receivers Get + * message. It provides a list of target nodes in the distribution receiver + * list along with their current status. + */ +struct esp_ble_mesh_dfd_receiver_list { + /** Number of entries included in this response */ + uint16_t entries_cnt; + /** Index of the first entry in the Distribution Receivers List returned */ + uint16_t first_index; + /** Pointer to array of target node entries containing receiver status information */ + esp_ble_mesh_dfd_target_node_entry_t *entries; +}; + +/** + * @brief DFD distribution capabilities structure. + * + * This structure contains the capabilities of a DFD Server as + * returned by the DFD Capabilities Get message. + * + * It provides information about the server's capacity for handling + * firmware distribution operations, storage limits, and supported + * out-of-band retrieval methods. + */ +struct esp_ble_mesh_dfd_dist_caps { + /** Maximum number of receivers that can be stored in the Distribution Receivers List */ + uint16_t max_receiver_list_sz; + /** Maximum number of firmware images that can be stored in the Firmware Information List */ + uint16_t max_fw_list_sz; + /** Maximum size of a single firmware image that can be stored (in bytes) */ + uint32_t max_fw_sz; + /** Maximum upload space available for storing firmware images (in bytes) */ + uint32_t max_upload_space; + /** Remaining upload space available after current stored firmware (in bytes) */ + uint32_t remaining_upload_space; + /** Bit field indicating supported out-of-band retrieval methods (0 = none supported) */ + uint8_t oob_retrieval_supported; + /** Pointer to buffer containing supported URL scheme names (UTF-8, null-terminated) */ + struct net_buf_simple *supported_url_scheme_names; +}; + +/** + * @brief DFD Client distribution start parameters. + * + * This structure contains the parameters for the DFD Start message. + * It initiates the firmware distribution process to all target nodes + * in the Distribution Receivers List. + */ +struct esp_ble_mesh_dfd_cli_dist_start { + /** TTL value to be used for all messages sent during firmware distribution */ + uint8_t ttl; + /** Transfer mode: 0x00 = Push BLOB Transfer Mode, 0x01 = Pull BLOB Transfer Mode (2 bits) */ + uint8_t trans_mode : 2, + /** Update policy: 0x00 = Single Target Node, 0x01 = All Target Nodes (1 bit) */ + update_policy : 1, + /** Reserved for Future Use (5 bits) */ + RFU : 5; + /** Application Key Index to be used for securing firmware distribution messages */ + uint16_t app_idx; + /** Base time value used to calculate transfer timeout (in 100ms units) */ + uint16_t timeout_base; + /** Index of the firmware image in the Firmware Information List to distribute */ + uint16_t fw_idx; + /** Flag indicating whether the target address is a virtual address (true) or group address (false) */ + bool is_va; + /** Target address for firmware distribution (group address or virtual label UUID) */ + union { + /** Group address for firmware distribution (used when is_va is false) */ + uint16_t group_addr; + /** Virtual Label UUID for firmware distribution (used when is_va is true) */ + uint8_t label_uuid[16]; + }; +}; + +/** + * @brief DFD distribution status structure. + * + * This structure contains the response parameters for the DFD Get and + * DFD Start messages. It provides the current status and configuration + * of the firmware distribution operation. + */ +struct esp_ble_mesh_dfd_dist_status { + /** Status code for the distribution operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current firmware distribution phase (see esp_ble_mesh_dfd_phase) */ + uint8_t dist_phase; + /** Multicast address used for the firmware distribution (group address or virtual label) */ + uint16_t multicast_address; + /** Application Key Index being used for securing firmware distribution messages */ + uint16_t appkey_idx; + /** TTL value being used for firmware distribution messages */ + uint8_t ttl; + /** Base time value used to calculate transfer timeout (in 100ms units) */ + uint16_t timeout_base; + /** Transfer mode: 0x00 = Push BLOB Transfer Mode, 0x01 = Pull BLOB Transfer Mode (2 bits) */ + uint8_t trans_mode:2, + /** Update policy: 0x00 = Single Target Node, 0x01 = All Target Nodes (1 bit) */ + update_policy:1, + /** Reserved for Future Use (5 bits) */ + RFU:5; + /** Index of the firmware image currently being distributed */ + uint16_t firmware_image_index; +}; + +/** + * @brief DFD Client upload start parameters. + * + * This structure contains the parameters for the DFD Upload Start + * message. It initiates an in-band firmware + * upload to the DFD Server using BLOB Transfer. + * + * @note This is used for in-band firmware transfers where the firmware + * data is transferred through the mesh network. + */ +struct esp_ble_mesh_dfd_cli_dist_upload_start { + /** TTL value to be used for all messages during the upload */ + uint8_t ttl; + /** Base time value used to calculate upload timeout (in 100ms units) */ + uint16_t timeout_base; + /** Total size of the firmware image to be uploaded (in bytes) */ + uint32_t fw_size; + /** BLOB identifier that will be used for the firmware transfer */ + uint64_t blob_id; + /** Pointer to buffer containing the firmware ID of the image to upload */ + struct net_buf_simple *fwid; + /** Pointer to buffer containing the firmware metadata for the upload */ + struct net_buf_simple *fw_metadata; +}; + +/** + * @brief DFD Client out-of-band upload start parameters. + * + * This structure contains the parameters for the DFD Upload Start OOB + * message. It initiates an out-of-band firmware + * upload where the firmware is retrieved from an external source. + * + * @note This is used for out-of-band firmware transfers where the firmware + * is obtained from a URI or external source. + */ +struct esp_ble_mesh_dfd_cli_dist_upload_oob_start { + /** Pointer to buffer containing the current firmware ID to check against */ + struct net_buf_simple *fwid; + /** Pointer to buffer containing the URI for firmware retrieval (UTF-8 string) */ + struct net_buf_simple *url; +}; + +/** + * @brief DFD upload status structure. + * + * This structure contains the response parameters for the DFD Upload Get, + * DFD Upload Start, and DFD Upload Start OOB messages. + * + * It provides the current status and progress of an ongoing or completed + * firmware upload operation on the DFD Server. + */ +struct esp_ble_mesh_dfd_upload_status { + /** Status code for the upload operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current upload phase (see esp_ble_mesh_dfd_upload_phase) */ + uint8_t upload_phase; + /** Upload progress percentage (0-100%, only valid when progress != 101) */ + uint8_t upload_progress:7, + /** Upload type: 0x00 = In-band upload, 0x01 = Out-of-band upload */ + upload_type:1; + /** Union containing firmware ID information based on upload type */ + union { + /** Firmware ID for in-band upload operations */ + struct net_buf_simple *fwid; + /** Firmware ID for out-of-band upload operations */ + struct net_buf_simple *oob_fwid; + }; +}; + +/** + * @brief DFD Client firmware get parameters. + * + * This structure contains the parameters for the DFD Firmware Get + * message. It requests information about a specific + * firmware image identified by its firmware ID. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_get { + /** Pointer to buffer containing the firmware ID to query */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD Client firmware get by index parameters. + * + * This structure contains the parameters for the DFD Firmware Get By Index + * message. It requests information about a specific firmware image identified + * by its index in the Firmware Information List. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_get_by_idx { + /** Index of the firmware image in the Firmware Information List */ + uint16_t dist_fw_idx; +}; + +/** + * @brief DFD Client firmware delete parameters. + * + * This structure contains the parameters for the DFD Firmware Delete + * message. It requests deletion of a specific firmware image from the + * DFD Server. + * + * @note Deleting a firmware image that is currently being distributed will + * cause the distribution to fail. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_del { + /** Pointer to buffer containing the firmware ID of the image to delete */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD firmware status structure. + * + * This structure contains the response parameters for the DFD Firmware Get + * and DFD Firmware Get By Index messages. + * + * It provides detailed information about a specific firmware image stored + * on the DFD Server. + */ +struct esp_ble_mesh_dfd_firmware_status { + /** Status code for the firmware query operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Total number of entries in the Firmware Information List */ + uint16_t entry_cnt; + /** Index of the firmware image in the Firmware Information List */ + uint16_t fw_idx; + /** Pointer to buffer containing the firmware ID of the queried image */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD Client action enumeration. + * + * This enumeration defines the different types of actions that can be performed + * by the DFD Client model. These actions are used internally to + * distinguish between different DFD message types when processing + * client requests. + */ +enum esp_ble_mesh_dfd_client_act { + /** DFD Client Get action - retrieving information from DFD Server */ + ESP_BLE_MESH_ACT_DFD_CLIENT_GET, + /** DFD Client Set action - sending commands/configuration to DFD Server */ + ESP_BLE_MESH_ACT_DFD_CLIENT_SET, + /** Maximum value for DFD Client action enumeration (bounds checking) */ + ESP_BLE_MESH_ACT_DFD_CLIENT_MAX, +}; + +/** + * @brief DFD Client callback event enumeration. + * + * This enumeration defines the different callback events that can be generated + * by the DFD Client model. These events notify the application + * about the status of DFD operations, message responses, timeouts, + * and completion of various procedures. + * + * Application should handle these events to properly manage firmware + * distribution operations and provide user feedback. + */ +enum esp_ble_mesh_dfd_client_cb_evt { + /** DFD Client timeout event - operation timed out waiting for response */ + ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, + /** DFD Client receive response event - received a response from DFD Server */ + ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP, + /** DFD Client send complete event - message transmission completed */ + ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP, + /** Maximum value for DFD Client callback event enumeration (bounds checking) */ + ESP_BLE_MESH_EVT_DFD_CLIENT_MAX, +}; + +/** + * @brief DFD Client get parameters union. + * + * This union contains different parameter structures for various DFD Client + * Get messages. The specific structure used depends on the type of + * get operation being performed. + * + * This allows type-safe access to message-specific parameters while + * using a single parameter type in the API. + */ +typedef union { + /** Parameters for DFD Receivers Get operation */ + esp_ble_mesh_dfd_receivers_get_t receivers_get; + /** Parameters for DFD Firmware Get operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_t dist_fw_get; + /** Parameters for DFD Firmware Get By Index operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_by_idx_t dist_fw_get_by_idx; +} esp_ble_mesh_dfd_client_get_param_t; + +/** + * @brief DFD Client set parameters union. + * + * This union contains different parameter structures for various DFD Client + * Set messages. The specific structure used depends on the type of + * set operation being performed. + * + * This allows type-safe access to message-specific parameters while + * using a single parameter type in the API. + */ +typedef union { + /** Parameters for DFD Receivers Add operation */ + esp_ble_mesh_dfd_cli_receivers_add_t receivers_add; + /** Parameters for DFD Start operation */ + esp_ble_mesh_dfd_cli_dist_start_t dist_start; + /** Parameters for DFD Upload Start operation */ + esp_ble_mesh_dfd_cli_dist_upload_start_t dist_upload_start; + /** Parameters for DFD Upload Start OOB operation */ + esp_ble_mesh_dfd_cli_dist_upload_oob_start_t dist_upload_oob_start; + /** Parameters for DFD Firmware Get operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_t dist_fw_get; + /** Parameters for DFD Firmware Delete operation */ + esp_ble_mesh_dfd_cli_dist_fw_del_t dist_fw_del; +} esp_ble_mesh_dfd_client_set_param_t; + +/** + * @brief DFD Client common callback parameters union. + * + * This union contains different response structures for various DFD Client + * received messages. The specific structure used depends on the type of + * message that triggered the callback. + * + * This allows type-safe access to message-specific response data + * while using a single callback parameter type. + */ +union esp_ble_mesh_dfd_client_common_cb_param { + /** Response parameters for DFD Receivers Add/Delete operations */ + esp_ble_mesh_dfd_receiver_status_t receiver_status; + /** Response parameters for DFD Receivers Get operation */ + esp_ble_mesh_dfd_receiver_list_t receiver_list; + /** Response parameters for DFD Capabilities Get operation */ + esp_ble_mesh_dfd_dist_caps_t dist_caps; + /** Response parameters for DFD Get/Start operations */ + esp_ble_mesh_dfd_dist_status_t dist_status; + /** Response parameters for DFD Upload Get/Start operations */ + esp_ble_mesh_dfd_upload_status_t upload_status; + /** Response parameters for DFD Firmware Get operations */ + esp_ble_mesh_dfd_firmware_status_t firmware_status; +}; + +/** + * @brief DFD Client callback parameters structure. + * + * This structure contains the parameters passed to the DFD Client + * callback function for various events. It provides information about + * the operation status, error codes, and event-specific data. + * + * Applications should examine the err_code field first to determine + * whether the operation was successful, then check the appropriate + * field in the status_cb union for operation-specific data. + */ +struct esp_ble_mesh_dfd_client_cb_param { + /** Error code indicating success (0) or failure (negative) of the operation */ + int err_code; + /** Common client parameters including source address, destination, etc. */ + esp_ble_mesh_client_common_param_t *params; + /** Union containing event-specific response data */ + esp_ble_mesh_dfd_client_common_cb_param_t status_cb; +}; + +/** + * @brief Register DFD Client callback function. + * + * This function registers a callback function that will be called when + * DFD Client events occur, such as message timeouts, responses, + * or operation completions. + * + * @param callback Pointer to the callback function to register. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note Only one callback can be registered at a time. Calling this + * function with a NULL callback will deregister the current callback. + */ +esp_err_t esp_ble_mesh_register_dfd_cli_callback(esp_ble_mesh_dfd_client_cb_t callback); + +/** + * @brief Send DFD Client Get message. + * + * This function sends a DFD Get message to retrieve information + * from the DFD Server. The specific type of information requested + * depends on the get_param structure provided. + * + * @param params Common client parameters including destination address, TTL, etc. + * @param get_param Union containing the specific get message parameters. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note The response will be delivered through the registered callback + * function with the ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP event. + */ +esp_err_t esp_ble_mesh_dfd_cli_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get_param); + +/** + * @brief Send DFD Client Set message. + * + * This function sends a DFD Set message to perform various operations + * on the DFD Server, such as starting firmware distribution, + * uploading firmware, or managing the receiver list. + * + * @param params Common client parameters including destination address, TTL, etc. + * @param set_param Union containing the specific set message parameters. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note The response will be delivered through the registered callback + * function with the ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP event. + */ +esp_err_t esp_ble_mesh_dfd_cli_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set_param); + +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @brief Firmware Distribution status enumeration. + * + * This enumeration defines the status codes used in DFD operations. + * These status codes indicate success, failure, and error conditions + * for various firmware distribution operations. + */ +enum esp_ble_mesh_dfd_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_DFD_SUCCESS, + + /** Insufficient resources on the node. */ + ESP_BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + + /** The operation cannot be performed while the Server is in the current phase. */ + ESP_BLE_MESH_DFD_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + ESP_BLE_MESH_DFD_ERR_INTERNAL, + + /** The requested firmware image is not stored on the Distributor. */ + ESP_BLE_MESH_DFD_ERR_FW_NOT_FOUND, + + /** The AppKey identified by the AppKey Index is not known to the node. */ + ESP_BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + + /** There are no Target nodes in the Distribution Receivers List state. */ + ESP_BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + + /** Another firmware image distribution is in progress. */ + ESP_BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + + /** Another upload is in progress. */ + ESP_BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + + /** The URI scheme name indicated by the Update URI is not supported. */ + ESP_BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED, + + /** The format of the Update URI is invalid. */ + ESP_BLE_MESH_DFD_ERR_URI_MALFORMED, + + /** The URI is currently unreachable. */ + ESP_BLE_MESH_DFD_ERR_URI_UNREACHABLE, + + /** The Check Firmware OOB procedure did not find any new firmware. */ + ESP_BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + + /** The suspension of the Distribute Firmware procedure failed. */ + ESP_BLE_MESH_DFD_ERR_SUSPEND_FAILED, +}; + +/** + * @brief Firmware distribution phases enumeration. + * + * This enumeration defines the different phases of a firmware distribution + * operation. The phases track the state of firmware distribution from + * idle through transfer, verification, application, and completion states. + */ +enum esp_ble_mesh_dfd_phase { + /** No firmware distribution is in progress. */ + ESP_BLE_MESH_DFD_PHASE_IDLE, + + /** Firmware distribution is in progress. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE, + + /** The Transfer BLOB procedure has completed successfully. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS, + + /** The Apply Firmware on Target Nodes procedure is being executed. */ + ESP_BLE_MESH_DFD_PHASE_APPLYING_UPDATE, + + /** The Distribute Firmware procedure has completed successfully. */ + ESP_BLE_MESH_DFD_PHASE_COMPLETED, + + /** The Distribute Firmware procedure has failed. */ + ESP_BLE_MESH_DFD_PHASE_FAILED, + + /** The Cancel Firmware Update procedure is being executed. */ + ESP_BLE_MESH_DFD_PHASE_CANCELING_UPDATE, + + /** The Transfer BLOB procedure is suspended. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED, +}; + +/** + * @brief Firmware upload phases enumeration. + * + * This enumeration defines the phases of firmware upload operations + * on the DFD Server. It tracks the state of firmware storage procedures + * including both in-band and out-of-band upload methods. + */ +enum esp_ble_mesh_dfd_upload_phase { + /** No firmware upload is in progress. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_IDLE, + + /** The Store Firmware procedure is being executed. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + + /** The Store Firmware procedure or Store Firmware OOB procedure failed. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + + /** The Store Firmware procedure or the Store Firmware OOB procedure completed successfully. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, +}; + +#if 0 +/** + * @brief Flash partition + * + * This structure represents a fixed-size partition on a flash device. + * Each partition contains one or more flash sectors. + */ +struct flash_area { + /** ID number */ + uint8_t fa_id; + uint16_t pad16; + /** Start offset from the beginning of the flash device */ + off_t fa_off; + /** Total size */ + size_t fa_size; + /** Backing flash device */ + const struct device *fa_dev; +#if CONFIG_FLASH_MAP_LABELS + /** Partition label if defined in DTS. Otherwise nullptr; */ + const char *fa_label; +#endif +}; +#endif + +/** Firmware Distribution Server callbacks: */ +struct esp_ble_mesh_dfd_srv_cb { + + /** @brief Slot receive callback. + * + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*recv)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const esp_ble_mesh_blob_io_t **io); + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + /** @brief Firmware upload OOB start callback. + * + * Called at the start of an OOB firmware upload. The application must + * start a firmware check using an OOB mechanism, and then call + * bt_mesh_dfd_srv_oob_check_complete. Depending on the return + * value of this function, the application must then start storing the + * firmware image using an OOB mechanism, and call + * bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory + * to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot Slot to be used for the upload. + * @param uri Pointer to buffer containing the URI used to + * check for new firmware. + * @param uri_len Length of the URI buffer. + * @param fwid Pointer to buffer containing the current + * firmware ID to be used when checking for + * availability of new firmware. + * @param fwid_len Length of the current firmware ID. Must be set + * to the length of the new firmware ID if it is + * available, or to 0 if new firmware is not + * available. + * + * @return ESP_BLE_MESH_DFD_SUCCESS on success, or error code otherwise. + */ + int (*start_oob_upload)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const uint8_t *uri, uint8_t uri_len, + const uint8_t *fwid, uint16_t fwid_len); + + /** @brief Cancel store OOB callback + * + * Called when an OOB store is cancelled. The application must stop + * any ongoing OOB image transfer. This callback is mandatory to + * support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to cancel + */ + void (*cancel_oob_upload)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); + + /** @brief Get the progress of an ongoing OOB store + * + * Called by the Firmware Distribution Server model when it needs to + * get the current progress of an ongoing OOB store from the + * application. This callback is mandatory to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to get progress for. + * + * @return The current progress of the ongoing OOB store, in percent. + */ + uint8_t (*oob_progress_get)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + + /** @brief Slot delete callback. + * + * Called when the Firmware Distribution Server is about to delete a DFU image slot. + * All allocated data associated with the firmware slot should be + * deleted. + * + * @param srv Firmware Update Server instance. + * @param slot DFU image slot being deleted. + */ + void (*del)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); + + /** @brief Slot send callback. + * + * Called at the start of a distribution procedure. The callback must + * fill @c io with a pointer to a readable BLOB stream for the Firmware + * Distribution Server to read the firmware image from. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being sent. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*send)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Phase change callback (Optional). + * + * Called whenever the phase of the Firmware Distribution Server changes. + * + * @param srv Firmware Distribution Server model instance. + * @param phase New Firmware Distribution phase. + */ + void (*phase)(esp_ble_mesh_dfd_srv_t *srv, esp_ble_mesh_dfd_phase_t phase); +}; + +/** Firmware Distribution Server instance. */ +struct esp_ble_mesh_dfd_srv { + const esp_ble_mesh_dfd_srv_cb_t *cb; + esp_ble_mesh_model_t *mod; + esp_ble_mesh_dfu_cli_t dfu; + esp_ble_mesh_dfu_target_t targets[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + esp_ble_mesh_blob_target_pull_t pull_ctxs[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + const esp_ble_mesh_blob_io_t *io; + uint16_t target_cnt; + uint16_t slot_idx; + bool apply; + esp_ble_mesh_dfd_phase_t phase; + esp_ble_mesh_blob_cli_inputs_t inputs; + + struct { + esp_ble_mesh_dfd_upload_phase_t phase; + esp_ble_mesh_dfu_slot_t *slot; +#if 0 + const struct flash_area *area; +#endif + esp_ble_mesh_blob_srv_t blob; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + bool is_oob; + bool is_pending_oob_check; + struct { + uint8_t uri_len; + uint8_t uri[CONFIG_BLE_MESH_DFU_URI_MAXLEN]; + uint16_t current_fwid_len; + uint8_t current_fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + esp_ble_mesh_msg_ctx_t ctx; + } oob; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + } upload; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct { + const uint8_t *schemes; + const uint8_t count; + } oob_schemes; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +}; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_DFU_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h new file mode 100644 index 000000000000..0332e0a0b599 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_DFU_SLOT_API_H_ +#define _ESP_BLE_MESH_DFU_SLOT_API_H_ + +#include "esp_ble_mesh_dfu_model_api.h" + +#if CONFIG_BLE_MESH_DFU_SLOTS +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ + +typedef struct esp_ble_mesh_dfu_slot esp_ble_mesh_dfu_slot_t; + +typedef enum esp_ble_mesh_dfu_iter + (*esp_ble_mesh_dfu_slot_cb_t) (const esp_ble_mesh_dfu_slot_t *slot, void *user_data); + +/** @brief Get the number of slots committed to the firmware list. + * + * @return Number of committed slots. + */ +int esp_ble_mesh_dfu_slot_count(void); + +/** @brief Reserve a new DFU image slot for a distributable image. + * + * A DFU image slot represents a single distributable DFU image with all its + * metadata. The slot data must be set using esp_ble_mesh_dfu_slot_info_set and + * esp_ble_mesh_dfu_slot_fwid_set, and the slot committed using + * esp_ble_mesh_dfu_slot_commit for the slot to be considered part of the slot + * list. + * + * @return + * - slot : A pointer to the reserved slot + * - @c NULL : Slot allocation failed + */ +esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_reserve(void); + +/** @brief Set the size and metadata for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the + * metadata. + * @param size The size of the image. + * @param metadata Metadata or NULL. + * @param metadata_len Length of the metadata, at most @c + * CONFIG_BLE_MESH_DFU_METADATA_MAXLEN. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or invalid metadata parameter + * - @c ESP_ERR_INVALID_SIZE : metadata length is zero or exceeds @c CONFIG_BLE_MESH_DFU_METADATA_MAXLEN + */ +int esp_ble_mesh_dfu_slot_info_set(esp_ble_mesh_dfu_slot_t *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +/** @brief Set the new fwid for the incoming image for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the fwid. + * @param fwid Fwid to set. + * @param fwid_len Length of the fwid, at most @c + * CONFIG_BLE_MESH_DFU_FWID_MAXLEN. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or invalid fwid parameter + * - @c ESP_ERR_INVALID_SIZE : fwid length is zero or exceeds @c CONFIG_BLE_MESH_DFU_FWID_MAXLEN + */ +int esp_ble_mesh_dfu_slot_fwid_set(esp_ble_mesh_dfu_slot_t *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +/** @brief Commit the reserved slot to the list of slots, and store it + * persistently. + * + * If the commit fails for any reason, the slot will still be in the reserved + * state after this call. + * + * @param dfu_slot Pointer to the reserved slot. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or slot has been committed + * - @c ESP_ERR_INVALID_SIZE : slot size is zero + */ +int esp_ble_mesh_dfu_slot_commit(esp_ble_mesh_dfu_slot_t *dfu_slot); + +/** @brief Release a reserved slot so that it can be reserved again. + * + * @param dfu_slot Pointer to the reserved slot. + */ +void esp_ble_mesh_dfu_slot_release(const esp_ble_mesh_dfu_slot_t *dfu_slot); + +/** @brief Delete a committed DFU image slot. + * + * @param slot Slot to delete. Must be a valid pointer acquired from this + * module. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter + */ +int esp_ble_mesh_dfu_slot_del(const esp_ble_mesh_dfu_slot_t *slot); + +/** @brief Delete all DFU image slots. + */ +void esp_ble_mesh_dfu_slot_del_all(void); + +/** @brief Get the DFU image slot at the given firmware image list index. + * + * @param img_idx DFU image slot index. + * + * @return + * - slot : A pointer to the reserved slot + * - @c NULL : No slot exists with the given index + */ +const esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_at(uint16_t img_idx); + +/** @brief Get the committed DFU image slot for the image with the given + * firmware ID. + * + * @param fwid Firmware ID. + * @param fwid_len Firmware ID length. + * @param slot Slot pointer to fill. + * + * @return + * - index : Slot index + * - @c ESP_ERR_INVALID_ARG : invalid fwid parameter or invalid slot parameter + * - @c ESP_ERR_INVALID_SIZE : fwid length is zero + * - @c ESP_ERR_NOT_FOUND : no slot exists with the given firmware id + */ +int esp_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, esp_ble_mesh_dfu_slot_t **slot); + +/** @brief Get the index in the firmware image list for the given slot. + * + * @param slot Slot to find. + * + * @return + * - index : Slot index + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter + * - @c ESP_ERR_NOT_FOUND : The slot does not exist + */ +int esp_ble_mesh_dfu_slot_img_idx_get(const esp_ble_mesh_dfu_slot_t *slot); + +#endif /* _ESP_BLE_MESH_FW_SLOT_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h index 90e948b7d913..54b4f20aa892 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,51 +9,86 @@ #include "esp_ble_mesh_defs.h" +#if CONFIG_BLE_MESH_MBT_SRV || CONFIG_BLE_MESH_MBT_CLI +#ifndef _BLE_MESH_MBT_DEPRECATE_WARN +#define _BLE_MESH_MBT_DEPRECATE_WARN +#warning "warning: 'All content in this document, including data structures and APIs, will be deprecated." +#endif +#endif /* CONFIG_BLE_MESH_MBT_SRV || CONFIG_BLE_MESH_MBT_CLI */ + #ifdef __cplusplus extern "C" { #endif +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +/** @cond */ +#if (CONFIG_BLE_MESH_MBT_SRV && CONFIG_BLE_MESH_BLOB_SRV) || \ + (CONFIG_BLE_MESH_MBT_CLI && CONFIG_BLE_MESH_BLOB_CLI) +#error "BLOB Transfer Model and BLOB Model cannot be enabled at the same time" +#endif +/** @endcond */ + +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x00) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x01) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x02) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x03) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x05) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x04) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_PARTIAL_BLOCK_REPORT ESP_BLE_MESH_MODEL_OP_1(0x65) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_STATUS ESP_BLE_MESH_MODEL_OP_1(0x67) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_CHUNK_TRANSFER ESP_BLE_MESH_MODEL_OP_1(0x66) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x06) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x07) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_BLOB_ID_SIZE 8 -/** @def ESP_BLE_MESH_MODEL_MBT_CLI +/** @def ESP_BLE_MESH_MODEL_MBT_CLI + * + * @brief Define a new BLOB Transfer Client model. * - * @brief Define a new BLOB Transfer Client model. + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Client model. * - * @note This API needs to be called for each element on which - * the application needs to have a BLOB Transfer Client model. + * @deprecated This macro will be deprecated in future versions. * - * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * @param cli_pub Pointer to unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to unique struct esp_ble_mesh_client_t. * - * @return New BLOB Transfer Client model instance. + * @return New BLOB Transfer Client model instance. */ #define ESP_BLE_MESH_MODEL_MBT_CLI(cli_pub, cli_data) \ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_CLI, \ NULL, cli_pub, cli_data) -/** @def ESP_BLE_MESH_MODEL_MBT_SRV +/** @def ESP_BLE_MESH_MODEL_MBT_SRV * - * @brief Define a new BLOB Transfer Server model. + * @brief Define a new BLOB Transfer Server model. * - * @note This API needs to be called for each element on which - * the application needs to have a BLOB Transfer Server model. + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Server model. * - * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * @deprecated This macro will be deprecated in future versions. * - * @return New BLOB Transfer Server model instance. + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * + * @return New BLOB Transfer Server model instance. */ #define ESP_BLE_MESH_MODEL_MBT_SRV(srv_pub, srv_data) \ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_SRV, \ @@ -61,125 +96,125 @@ extern "C" { /** BLOB Transfer Server model context */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ -} esp_ble_mesh_mbt_srv_t; + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ +} esp_ble_mesh_mbt_srv_t __attribute__((deprecated)); /** Parameters of BLOB receiver */ typedef struct { - uint16_t unicast_addr; /*!< Unicast address of the server */ - uint8_t retrieved_transfer_phase; /*!< Retrieved transfer phase of the server */ - uint8_t status:4; /*!< Status of the last operation */ - uint16_t blocks_not_received_len; /*!< Indicates the length which blocks were not received by the server. */ - uint8_t *blocks_not_received; /*!< Indicates which blocks were not received by the server. */ - uint16_t missing_chunks_len; /*!< Indicates which chunks were not received in the current block */ - uint8_t *missing_chunks; /*!< Indicates which chunks were not received by the server in the current block */ -/* The followings are the additional information contained in status messages. */ - uint8_t transfer_mode:2; /*!< BLOB transfer mode */ - uint8_t expected_blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< Expected BLOB identifier list */ - uint32_t blob_size; /*!< BLOB size in octets */ - uint8_t block_size_log; /*!< Indicates the block size */ - uint16_t transfer_mtu_size; /*!< MTU size in octets */ - bool block_status_recv; /*!< Indicate if Blob Block Status is received as a response. */ -} esp_ble_mesh_blob_receiver_t; /*!< Structure of BLOB receiver */ + uint16_t unicast_addr; /*!< Unicast address of the server */ + uint8_t retrieved_transfer_phase; /*!< Retrieved transfer phase of the server */ + uint8_t status: 4; /*!< Status of the last operation */ + uint16_t blocks_not_received_len; /*!< Indicates the length which blocks were not received by the server. */ + uint8_t *blocks_not_received; /*!< Indicates which blocks were not received by the server. */ + uint16_t missing_chunks_len; /*!< Indicates which chunks were not received in the current block */ + uint8_t *missing_chunks; /*!< Indicates which chunks were not received by the server in the current block */ + /* The following are the additional information contained in status messages. */ + uint8_t transfer_mode: 2; /*!< BLOB transfer mode */ + uint8_t expected_blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< Expected BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t block_size_log; /*!< Indicates the block size */ + uint16_t transfer_mtu_size; /*!< MTU size in octets */ + bool block_status_recv; /*!< Indicate if Blob Block Status is received as a response. */ +} esp_ble_mesh_blob_receiver_t __attribute__((deprecated)); /*!< Structure of BLOB receiver */ /** Parameters of BLOB Information Status */ typedef struct { - uint8_t min_block_size_log; /*!< Min Block Size Log */ - uint8_t max_block_size_log; /*!< Max Block Size Log */ - uint16_t max_total_chunks; /*!< Max Total Chunks */ - uint16_t max_chunk_size; /*!< Max Chunk Size */ - uint32_t max_blob_size; /*!< Max BLOB Size */ - uint16_t server_mtu_size; /*!< Server MTU size */ - uint8_t supported_transfer_mode; /*!< Supported Transfer Mode */ -} esp_ble_mesh_blob_capabilities_t; /*!< Parameters of BLOB Information Status */ + uint8_t min_block_size_log; /*!< Min Block Size Log */ + uint8_t max_block_size_log; /*!< Max Block Size Log */ + uint16_t max_total_chunks; /*!< Max Total Chunks */ + uint16_t max_chunk_size; /*!< Max Chunk Size */ + uint32_t max_blob_size; /*!< Max BLOB Size */ + uint16_t server_mtu_size; /*!< Server MTU size */ + uint8_t supported_transfer_mode; /*!< Supported Transfer Mode */ +} esp_ble_mesh_blob_capabilities_t __attribute__((deprecated)); /*!< Parameters of BLOB Information Status */ /** Parameters of BLOB retrieve capabilities */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ -} esp_ble_mesh_retrieve_capabilities_t; /*!< Parameters of BLOB retrieve capabilities */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ +} esp_ble_mesh_retrieve_capabilities_t __attribute__((deprecated)); /*!< Parameters of BLOB retrieve capabilities */ /** Parameters of BLOB transfer */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ - uint32_t blob_size; /*!< BLOB size in octets */ - uint8_t *blob_data; /*!< BLOB data */ - uint8_t transfer_mode; /*!< BLOB transfer mode */ - uint16_t client_timeout_base; /*!< Time wait for messages from the serve */ -} esp_ble_mesh_transfer_blob_t; /*!< Parameters of BLOB transfer */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t *blob_data; /*!< BLOB data */ + uint8_t transfer_mode; /*!< BLOB transfer mode */ + uint16_t client_timeout_base; /*!< Time wait for messages from the serve */ +} esp_ble_mesh_transfer_blob_t __attribute__((deprecated)); /*!< Parameters of BLOB transfer */ /** Parameters of BLOB Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint16_t block_number; /*!< Block number of the current block */ - uint16_t chunk_size; /*!< Chunk Size (in octets) for the current block */ -} esp_ble_mesh_send_block_t; /*!< BLOB Block Status message structure */ + uint16_t block_number; /*!< Block number of the current block */ + uint16_t chunk_size; /*!< Chunk Size (in octets) for the current block */ +} esp_ble_mesh_send_block_t __attribute__((deprecated)); /*!< BLOB Block Status message structure */ /** Parameters of BLOB send message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_send_data_t; /*!< Parameters of BLOB send message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_send_data_t __attribute__((deprecated)); /*!< Parameters of BLOB send message */ /** Parameters of determine Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_determine_block_status_t; /*!< Parameters of determine Block Status message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_determine_block_status_t __attribute__((deprecated)); /*!< Parameters of determine Block Status message */ /** Parameters of determine Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ -} esp_ble_mesh_determine_transfer_status_t; /*!< Parameters of determine Block Status message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ +} esp_ble_mesh_determine_transfer_status_t __attribute__((deprecated)); /*!< Parameters of determine Block Status message */ /** Parameters of cancel transfer message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ -} esp_ble_mesh_cancel_transfer_t; /*!< Parameters of cancel transfer message */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ +} esp_ble_mesh_cancel_transfer_t __attribute__((deprecated)); /*!< Parameters of cancel transfer message */ /** * @brief BLOB Transfer Client model procedure result @@ -193,113 +228,113 @@ typedef struct { typedef union { /** Retrieve capabilities status */ struct { - int error_code; /*!< Result of starting Retrieve Capabilities procedure */ - esp_ble_mesh_retrieve_capabilities_t input; /*!< Input of starting Retrieve Capabilities procedure */ - } retrieve_capabilities_status; /*!< Retrieve capabilities status */ + int error_code; /*!< Result of starting Retrieve Capabilities procedure */ + esp_ble_mesh_retrieve_capabilities_t input; /*!< Input of starting Retrieve Capabilities procedure */ + } retrieve_capabilities_status; /*!< Retrieve capabilities status */ /** Transfer BLOB status */ struct { - int error_code; /*!< Result of starting Transfer BLOB procedure */ - esp_ble_mesh_transfer_blob_t input; /*!< Input of starting Transfer BLOB procedure */ - } transfer_blob_status; /*!< Transfer BLOB status */ + int error_code; /*!< Result of starting Transfer BLOB procedure */ + esp_ble_mesh_transfer_blob_t input; /*!< Input of starting Transfer BLOB procedure */ + } transfer_blob_status; /*!< Transfer BLOB status */ /** Send block status */ struct { - int error_code; /*!< Result of starting Send Block sub-procedure */ - esp_ble_mesh_send_block_t input; /*!< Input of starting Send Block sub-procedure */ - } send_block_status; /*!< Send block status */ + int error_code; /*!< Result of starting Send Block sub-procedure */ + esp_ble_mesh_send_block_t input; /*!< Input of starting Send Block sub-procedure */ + } send_block_status; /*!< Send block status */ /** Send data status */ struct { - int error_code; /*!< Result of starting Send Data sub-procedure */ - esp_ble_mesh_send_data_t input; /*!< Input of starting Send Data sub-procedure */ - } send_data_status; /*!< Send data status */ + int error_code; /*!< Result of starting Send Data sub-procedure */ + esp_ble_mesh_send_data_t input; /*!< Input of starting Send Data sub-procedure */ + } send_data_status; /*!< Send data status */ /** Determine block status */ struct { - int error_code; /*!< Result of starting Determine Block Status sub-procedure */ - esp_ble_mesh_determine_block_status_t input; /*!< Input of starting Determine Block Status sub-procedure */ - } determine_block_status_status; /*!< Determine block status */ + int error_code; /*!< Result of starting Determine Block Status sub-procedure */ + esp_ble_mesh_determine_block_status_t input; /*!< Input of starting Determine Block Status sub-procedure */ + } determine_block_status_status; /*!< Determine block status */ /** Determine transfer status */ struct { - int error_code; /*!< Result of starting Determine Transfer Status procedure */ - esp_ble_mesh_determine_transfer_status_t input; /*!< Input of starting Determine Transfer Status procedure */ - } determine_transfer_status_status; /*!< Determine transfer status */ + int error_code; /*!< Result of starting Determine Transfer Status procedure */ + esp_ble_mesh_determine_transfer_status_t input; /*!< Input of starting Determine Transfer Status procedure */ + } determine_transfer_status_status; /*!< Determine transfer status */ /** Cancel transfer status */ struct { - int error_code; /*!< Result of starting Cancel Transfer procedure */ - esp_ble_mesh_cancel_transfer_t input; /*!< Input of starting Cancel Transfer procedure */ - } cancel_transfer_status; /*!< Cancel transfer status */ + int error_code; /*!< Result of starting Cancel Transfer procedure */ + esp_ble_mesh_cancel_transfer_t input; /*!< Input of starting Cancel Transfer procedure */ + } cancel_transfer_status; /*!< Cancel transfer status */ /** Retrieve capabilities complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Retrieve Capabilities procedure */ - } retrieve_capabilities_comp; /*!< Retrieve capabilities complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Retrieve Capabilities procedure */ + } retrieve_capabilities_comp; /*!< Retrieve capabilities complete */ /** Transfer BLOB complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Transfer BLOB procedure */ - } transfer_blob_comp; /*!< Transfer BLOB complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Transfer BLOB procedure */ + } transfer_blob_comp; /*!< Transfer BLOB complete */ /** Send block complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Send Block sub-procedure */ - } send_block_comp; /*!< Send block complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Block sub-procedure */ + } send_block_comp; /*!< Send block complete */ /** Send data complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Send Data sub-procedure */ - } send_data_comp; /*!< Send data complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Data sub-procedure */ + } send_data_comp; /*!< Send data complete */ /** Determine block status complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Determine Block Status sub-procedure */ - } determine_block_status_comp; /*!< Determine block status complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Block Status sub-procedure */ + } determine_block_status_comp; /*!< Determine block status complete */ /** Determine transfer status complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Determine Transfer Status procedure */ - } determine_transfer_status_comp; /*!< Determine transfer status complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Transfer Status procedure */ + } determine_transfer_status_comp; /*!< Determine transfer status complete */ /** Cancel transfer complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Cancel Transfer procedure */ - } cancel_transfer_comp; /*!< Cancel transfer complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Cancel Transfer procedure */ + } cancel_transfer_comp; /*!< Cancel transfer complete */ /** Set transfer TTL */ struct { - int error_code; /*!< Result of setting Transfer TTL state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - } set_transfer_ttl; /*!< Set transfer TTL */ + int error_code; /*!< Result of setting Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + } set_transfer_ttl; /*!< Set transfer TTL */ /** Clear transfer TTL */ struct { - int error_code; /*!< Result of clearing Transfer TTL state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_transfer_ttl; /*!< Clear transfer TTL */ + int error_code; /*!< Result of clearing Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_transfer_ttl; /*!< Clear transfer TTL */ /** Set application index */ struct { - int error_code; /*!< Result of setting AppKey Index state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint16_t app_idx; /*!< AppKey Index state */ - } set_app_idx; /*!< Set application index */ + int error_code; /*!< Result of setting AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t app_idx; /*!< AppKey Index state */ + } set_app_idx; /*!< Set application index */ /** Clear application index */ struct { - int error_code; /*!< Result of clearing AppKey Index state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_app_idx; /*!< Clear application index */ + int error_code; /*!< Result of clearing AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_app_idx; /*!< Clear application index */ /** Set multicast address */ struct { - int error_code; /*!< Result of setting Multicast Address state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint16_t multicast_addr; /*!< Multicast Address state */ - } set_multicast_addr; /*!< Set multicast address */ + int error_code; /*!< Result of setting Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t multicast_addr; /*!< Multicast Address state */ + } set_multicast_addr; /*!< Set multicast address */ /** Clear multicast address */ struct { - int error_code; /*!< Result of clearing Multicast Address state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_multicast_addr; /*!< Clear multicast address */ -} esp_ble_mesh_mbt_client_cb_value_t; /*!< BLOB Transfer Client model callback values union */ + int error_code; /*!< Result of clearing Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_multicast_addr; /*!< Clear multicast address */ +} esp_ble_mesh_mbt_client_cb_value_t; /*!< BLOB Transfer Client model callback values union */ /** BLOB Transfer Client model callback parameters */ typedef struct { - esp_ble_mesh_mbt_client_cb_value_t value; /*!< BLOB Transfer Client model callback values */ -} esp_ble_mesh_mbt_client_cb_param_t; /*!< BLOB Transfer Client model callback parameters */ + esp_ble_mesh_mbt_client_cb_value_t value; /*!< BLOB Transfer Client model callback values */ +} esp_ble_mesh_mbt_client_cb_param_t __attribute__((deprecated)); /*!< BLOB Transfer Client model callback parameters */ /** * This enum value is the event of BLOB Transfer Client model. @@ -327,30 +362,30 @@ typedef enum { ESP_BLE_MESH_MBT_CLIENT_SET_MULTICAST_ADDR_COMP_EVT, ESP_BLE_MESH_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP_EVT, ESP_BLE_MESH_MBT_CLIENT_EVT_MAX, -} esp_ble_mesh_mbt_client_cb_event_t; +} esp_ble_mesh_mbt_client_cb_event_t __attribute__((deprecated)); /** Parameters of initialize BLOB receive */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ - uint16_t timeout; /*!< Timeout */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_initialize_blob_receive_t; /*!< Structure of initialize BLOB receive */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint16_t timeout; /*!< Timeout */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_initialize_blob_receive_t __attribute__((deprecated)); /*!< Structure of initialize BLOB receive */ /** Parameters of cancel BLOB receive */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ -} esp_ble_mesh_cancel_blob_receive_t;/*!< */ +} esp_ble_mesh_cancel_blob_receive_t __attribute__((deprecated));/*!< */ /** Parameters of cancel BLOB receive */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ esp_ble_mesh_blob_capabilities_t caps; /*!< Parameters of BLOB Information Status */ -} esp_ble_mesh_set_blob_capabilities_t;/*!< */ +} esp_ble_mesh_set_blob_capabilities_t __attribute__((deprecated)); /** * @brief BLOB Transfer Server model callback value union @@ -358,61 +393,61 @@ typedef struct { typedef union { /** Initialize BLOB receive complete */ struct { - int error_code; /*!< Result of initializing BLOB receive */ - esp_ble_mesh_initialize_blob_receive_t input; /*!< Input of initializing BLOB receive */ - } initialize_blob_receive_comp; /*!< Initialize BLOB receive complete */ + int error_code; /*!< Result of initializing BLOB receive */ + esp_ble_mesh_initialize_blob_receive_t input; /*!< Input of initializing BLOB receive */ + } initialize_blob_receive_comp; /*!< Initialize BLOB receive complete */ /** Cancel BLOB receive complete */ struct { - int error_code; /*!< Result of canceling BLOB receive */ - esp_ble_mesh_cancel_blob_receive_t input; /*!< Input of canceling BLOB receive */ - } cancel_blob_receive_comp; /*!< Cancel BLOB receive complete */ + int error_code; /*!< Result of canceling BLOB receive */ + esp_ble_mesh_cancel_blob_receive_t input; /*!< Input of canceling BLOB receive */ + } cancel_blob_receive_comp; /*!< Cancel BLOB receive complete */ /** Set BLOB capabilities complete */ struct { - int error_code; /*!< Result of setting BLOB capabilities */ - esp_ble_mesh_set_blob_capabilities_t input; /*!< Input of setting BLOB capabilities */ - } set_blob_capabilities_comp; /*!< Set BLOB capabilities complete */ + int error_code; /*!< Result of setting BLOB capabilities */ + esp_ble_mesh_set_blob_capabilities_t input; /*!< Input of setting BLOB capabilities */ + } set_blob_capabilities_comp; /*!< Set BLOB capabilities complete */ /** BLOB transfer get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Get message context */ - } blob_transfer_get; /*!< BLOB transfer get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Get message context */ + } blob_transfer_get; /*!< BLOB transfer get */ /** BLOB transfer start */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Start message context */ - } blob_transfer_start; /*!< BLOB transfer start */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Start message context */ + } blob_transfer_start; /*!< BLOB transfer start */ /** BLOB transfer cancel */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Cancel message context */ - } blob_transfer_cancel; /*!< BLOB transfer cancel */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Cancel message context */ + } blob_transfer_cancel; /*!< BLOB transfer cancel */ /** BLOB block get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Get message context */ - } blob_block_get; /*!< BLOB block get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Get message context */ + } blob_block_get; /*!< BLOB block get */ /** BLOB block start */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Start message context */ - } blob_block_start; /*!< BLOB block start */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Start message context */ + } blob_block_start; /*!< BLOB block start */ /** BLOB chunk transfer */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Chunk Transfer message context */ - } blob_chunk_transfer; /*!< BLOB chunk transfer */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Chunk Transfer message context */ + } blob_chunk_transfer; /*!< BLOB chunk transfer */ /** BLOB information get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Information Get message context */ - } blob_information_get; /*!< BLOB information get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Information Get message context */ + } blob_information_get; /*!< BLOB information get */ /** Block receive complete */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB block completely */ - } block_receive_comp; /*!< Block receive complete */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB block completely */ + } block_receive_comp; /*!< Block receive complete */ /** BLOB receive complete */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB completely */ - } blob_receive_comp; /*!< BLOB receive complete */ -} esp_ble_mesh_mbt_server_cb_value_t; /*!< BLOB Transfer Server model callback value union */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB completely */ + } blob_receive_comp; /*!< BLOB receive complete */ +} esp_ble_mesh_mbt_server_cb_value_t __attribute__((deprecated)); /*!< BLOB Transfer Server model callback value union */ /** BLOB Transfer Server model callback parameters */ typedef struct { - esp_ble_mesh_mbt_server_cb_value_t value; /*!< Value of the received blob transfer messages */ -} esp_ble_mesh_mbt_server_cb_param_t; /*!< BLOB Transfer Server model callback parameters */ + esp_ble_mesh_mbt_server_cb_value_t value; /*!< Value of the received blob transfer messages */ +} esp_ble_mesh_mbt_server_cb_param_t __attribute__((deprecated)); /*!< BLOB Transfer Server model callback parameters */ /** This enum value is the event of BLOB Transfer Server model */ typedef enum { @@ -430,7 +465,7 @@ typedef enum { ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_COMP_EVT, ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_TIMEOUT_EVT, ESP_BLE_MESH_MBT_SERVER_EVT_MAX, -} esp_ble_mesh_mbt_server_cb_event_t; +} esp_ble_mesh_mbt_server_cb_event_t __attribute__((deprecated)); /** * @brief BLOB Transfer Client model callback function type @@ -453,96 +488,116 @@ typedef void (* esp_ble_mesh_mbt_server_cb_t)(esp_ble_mesh_mbt_server_cb_event_t /** * @brief Register BLE Mesh BLOB Transfer Client model callback. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] callback: Pointer to the callback function. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback); +esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) __attribute__((deprecated)); /** * @brief Register BLE Mesh BLOB Transfer Server model callback. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] callback: Pointer to the callback function. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback); +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Retrieve Capabilities procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Retrieve Capabilities procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input); +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Transfer BLOB procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Transfer BLOB procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input); +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Send Block sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Send Block sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input); +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Send Data sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Send Data sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input); +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Determine Block Status sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Determine Block Status sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input); +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Determine Transfer Status procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Determine Transfer Status procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input); +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Cancel Transfer procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Cancel Transfer procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input); +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets BLOB receiver. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] unicast_addr: Unicast address of the BLOB receiver. * @@ -550,21 +605,25 @@ esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t * */ const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, - uint16_t unicast_addr); + uint16_t unicast_addr) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets active BLOB receiver list. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return Active BLOB receiver list on success or NULL on failure. * */ -const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model); +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets BLOB transfer progress. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] unicast_addr: Unicast address of the BLOB receiver. * @param[in] block_percent: Block reception percent to be updated. @@ -576,11 +635,13 @@ const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_rec esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, uint16_t unicast_addr, uint8_t *block_percent, - uint8_t *chunk_percent); + uint8_t *chunk_percent) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets Transfer TTL state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] transfer_ttl: Transfer TTL state value. * @@ -588,21 +649,25 @@ esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *mo * */ esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, - uint8_t transfer_ttl); + uint8_t transfer_ttl) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear Transfer TTL state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets AppKey Index state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] app_idx: AppKey Index state value. * @@ -610,21 +675,25 @@ esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model * */ esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, - uint16_t app_idx); + uint16_t app_idx) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear AppKey Index state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets Multicast Address state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] multicast_addr: Multicast Address state value. * @@ -632,51 +701,61 @@ esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model); * */ esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, - uint16_t multicast_addr); + uint16_t multicast_addr) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear Multicast Address state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Server initializes BLOB receive. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of initializing BLOB receive. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input); +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server cancels BLOB receive. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of cancelling BLOB receive. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input); +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server sets BLOB capabilities. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of setting BLOB capabilities. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input); +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server gets current BLOB reception progress. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Server model. * @param[in] reception_progress: Reception progress to be updated. * @@ -684,7 +763,11 @@ esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_ca * */ esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, - uint8_t *reception_progress); + uint8_t *reception_progress) __attribute__((deprecated)); + +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic pop +#endif #ifdef __cplusplus } diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c new file mode 100644 index 000000000000..d60df283f145 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c @@ -0,0 +1,1216 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_dfu_model.h" +#include "esp_ble_mesh_dfu_model_api.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/dfu/dfu_srv.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfd_cli.h" +#include "mesh_v1.1/dfu/dfd_srv.h" + +#if CONFIG_BLE_MESH_DFU_CLI +/* Device Firmware Update Client model related functions */ + +static inline void btc_ble_mesh_dfu_client_cb_to_app(btc_ble_mesh_dfu_client_cb_evt_t event, + esp_ble_mesh_dfu_client_cb_param_t *param) +{ + esp_ble_mesh_dfu_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_DFU_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_dfu_client_args_t *dst = p_dest; + btc_ble_mesh_dfu_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: { + dst->dfu_get.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfu_get.params) { + memcpy(dst->dfu_get.params, src->dfu_get.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->dfu_get.get) { + dst->dfu_get.get = bt_mesh_calloc(sizeof(esp_ble_mesh_dfu_client_get_t)); + if (dst->dfu_get.get) { + memcpy(dst->dfu_get.get, src->dfu_get.get, + sizeof(esp_ble_mesh_dfu_client_get_t)); + if (src->dfu_get.params->opcode == ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK) { + if (src->dfu_get.get->dfu_metadata_check.metadata) { + dst->dfu_get.get->dfu_metadata_check.metadata = bt_mesh_alloc_buf(src->dfu_get.get->dfu_metadata_check.metadata->len); + if (dst->dfu_get.get->dfu_metadata_check.metadata) { + net_buf_simple_add_mem(dst->dfu_get.get->dfu_metadata_check.metadata, + src->dfu_get.get->dfu_metadata_check.metadata->data, + src->dfu_get.get->dfu_metadata_check.metadata->len); + } else { + bt_mesh_free(dst->dfu_get.get); + bt_mesh_free(dst->dfu_get.params); + BT_ERR("Out of memory for metadata"); + return; + } + } else { + bt_mesh_free(dst->dfu_get.get); + bt_mesh_free(dst->dfu_get.params); + BT_ERR("Metadata should be exists"); + return; + } + } + } else { + bt_mesh_free(dst->dfu_get.params); + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + } + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_dfu_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_dfu_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_dfu_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: + if (arg->dfu_get.get) { + switch (arg->dfu_get.params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + if (arg->dfu_get.get->dfu_metadata_check.metadata) { + bt_mesh_free_buf(arg->dfu_get.get->dfu_metadata_check.metadata); + } + break; + default: + break; + } + bt_mesh_free(arg->dfu_get.get); + } + if (arg->dfu_get.params) { + bt_mesh_free(arg->dfu_get.params); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_dfu_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_dfu_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_dfu_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + if (p_src_data->recv.dfu_update_info_status.fw_info_list_cnt) { + length = p_src_data->recv.dfu_update_info_status.fw_info_list_cnt * sizeof(esp_ble_mesh_firmware_info_t); + p_dest_data->recv.dfu_update_info_status.fw_info_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.dfu_update_info_status.fw_info_list) { + bt_mesh_free(p_dest_data->params); + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + memcpy(p_dest_data->recv.dfu_update_info_status.fw_info_list, + p_src_data->recv.dfu_update_info_status.fw_info_list, + length); + } else { + p_dest_data->recv.dfu_update_info_status.fw_info_list = NULL; + } + break; + default: + break; + } + } + case ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT: + case ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_dfu_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (msg->act >= ESP_BLE_MESH_DFU_CLIENT_EVT_MAX) { + BT_ERR("%s, Invalid event %d", __func, msg->act); + return; + } + + arg = (esp_ble_mesh_dfu_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + bt_mesh_free(arg->recv.dfu_update_info_status.fw_info_list); + break; + default: + break; + } + } + case ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT: + case ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT: + break; + default: + BT_WARN("Unprocessed event %d", msg->act); + break; + } + + if (arg->params) { + bt_mesh_free(arg->params); + } + + return; +} + +static void btc_ble_mesh_dfu_client_cb(esp_ble_mesh_dfu_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DFU_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_dfu_client_cb_param_t), + btc_ble_mesh_dfu_client_copy_req_data, + btc_ble_mesh_dfu_client_free_req_data); +} + +void bt_mesh_dfu_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_dfu_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT: + act = ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP: + act = ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_DFU_CLIENT_IMG_SEND_CMP: + act = ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT; + break; + default: + BT_ERR("Unknown Device Firmware Update client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_dfu_client_cb(&cb_params, act); +} + +static int btc_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get) +{ + bt_mesh_client_common_param_t param = {0}; + struct bt_mesh_dfu_cli *dfu_cli = NULL; + + if (params == NULL || + params->model == NULL || + params->model->user_data == NULL) { + BT_ERR("%s, Invalid parameter %d %p %p", __func__, params == NULL, params->model, params->model->user_data); + return -EINVAL; + } + + dfu_cli = (struct bt_mesh_dfu_cli *)params->model->user_data; + + switch (params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + if (get == NULL) { + BT_ERR("Invalid Device Firmware Update Get"); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (param.opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + return bt_mesh_dfu_cli_imgs_get(dfu_cli, ¶m.ctx, (bt_mesh_dfu_img_cb_t) get->dfu_update_info_get.img_cb, + NULL, get->dfu_update_info_get.first_index, + get->dfu_update_info_get.entries_limit); + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + return bt_mesh_dfu_cli_metadata_check(dfu_cli, ¶m.ctx, get->dfu_metadata_check.update_firmware_index, + get->dfu_metadata_check.metadata); + case ESP_BLE_MESH_DFU_OP_UPDATE_GET: + return bt_mesh_dfu_cli_status_get(dfu_cli, ¶m.ctx); + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + // automatic start + return 0; + case ESP_BLE_MESH_DFU_OP_UPDATE_CANCEL: + return bt_mesh_dfu_cli_cancel(dfu_cli, ¶m.ctx); + case ESP_BLE_MESH_DFU_OP_UPDATE_APPLY: + return bt_mesh_dfu_cli_apply(dfu_cli); + default: + BT_ERR("Invalid Device firmware Get opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_dfu_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t cb = {0}; + btc_ble_mesh_dfu_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_dfu_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: + cb.params = arg->dfu_get.params; + cb.send.err_code = btc_ble_mesh_dfu_client_get_state(arg->dfu_get.params, + arg->dfu_get.get); + btc_ble_mesh_dfu_client_cb(&cb, + ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT); + break; + case BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND: + cb.send.err_code = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)arg->send_arg.cli, + (struct bt_mesh_blob_cli_inputs *)arg->send_arg.inputs, + (struct bt_mesh_blob_io *)arg->send_arg.io, + (struct bt_mesh_dfu_cli_xfer *)arg->send_arg.xfer); + btc_ble_mesh_dfu_client_cb(&cb, + ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_dfu_client_arg_deep_free(msg); +} + +void btc_ble_mesh_dfu_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_dfu_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_DFU_CLIENT_EVT_MAX) { + btc_ble_mesh_dfu_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_dfu_client_free_req_data(msg); +} + +uint8_t btc_ble_mesh_dfu_cli_progress(struct esp_ble_mesh_dfu_cli *cli) +{ + return bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)cli); +} + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV + +void btc_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_verified((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_rejected((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)srv); +} + +bool btc_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv) +{ + return bt_mesh_dfu_srv_is_busy((struct bt_mesh_dfu_srv *)srv); +} + +uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) +{ + return bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)srv); +} +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +static inline void btc_ble_mesh_dfd_client_cb_to_app(btc_ble_mesh_dfd_client_cb_evt_t event, + esp_ble_mesh_dfd_client_cb_param_t *param) +{ + esp_ble_mesh_dfd_client_cb_t btc_ble_mesh_cb = + (esp_ble_mesh_dfd_client_cb_t)btc_profile_cb_get(BTC_PID_DFD_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static inline bool dfd_client_param_need(uint32_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + case ESP_BLE_MESH_DFD_OP_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return true; + default: + break; + } + return false; +} + +static int btc_ble_mesh_dfd_client_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + if (dfd_client_param_need(params->opcode) != (!!get)) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + switch(params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + if (get == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + return bt_mesh_dfd_cli_receivers_get(¶m, get->receivers_get.first_index, + get->receivers_get.entries_limit); + case ESP_BLE_MESH_DFD_OP_CAPABILITIES_GET: + return bt_mesh_dfd_cli_distribution_capabilities_get(¶m); + case ESP_BLE_MESH_DFD_OP_GET: + return bt_mesh_dfd_cli_distribution_get(¶m); + case ESP_BLE_MESH_DFD_OP_UPLOAD_GET: + return bt_mesh_dfd_cli_distribution_upload_get(¶m); + case ESP_BLE_MESH_DFD_OP_FW_GET: + return bt_mesh_dfd_cli_firmware_get(¶m, get->dist_fw_get.fwid); + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + return bt_mesh_dfd_cli_firmware_get_by_index(¶m, get->dist_fw_get_by_idx.dist_fw_idx); + default: + BT_ERR("UknOpc:%04x", params->opcode); + return -EINVAL; + } +} + +static int btc_ble_mesh_dfd_client_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + if (dfd_client_param_need(params->opcode) != (!!set)) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + return bt_mesh_dfd_cli_receivers_add(¶m, (dfd_cli_receiver_entry_t *)set->receivers_add.receivers, set->receivers_add.receivers_cnt); + case ESP_BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL: + return bt_mesh_dfd_cli_receivers_delete_all(¶m); + case ESP_BLE_MESH_DFD_OP_START: + return bt_mesh_dfd_cli_distribution_start(¶m, (dfd_cli_dist_start_t *)&set->dist_start); + case ESP_BLE_MESH_DFD_OP_SUSPEND: + return bt_mesh_dfd_cli_distribution_suspend(¶m); + case ESP_BLE_MESH_DFD_OP_CANCEL: + return bt_mesh_dfd_cli_distribution_cancel(¶m); + case ESP_BLE_MESH_DFD_OP_APPLY: + return bt_mesh_dfd_cli_distribution_apply(¶m); + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + return bt_mesh_dfd_cli_distribution_upload_start(¶m, (dfd_cli_dist_upload_start_t *)&set->dist_upload_start); + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + return bt_mesh_dfd_cli_distribution_upload_oob_start(¶m, (dfd_cli_dist_upload_oob_start_t *)&set->dist_upload_oob_start); + case ESP_BLE_MESH_DFD_OP_UPLOAD_CANCEL: + return bt_mesh_dfd_cli_distribution_upload_oob_cancel(¶m); + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return bt_mesh_dfd_cli_firmware_get_delete(¶m, set->dist_fw_del.fwid); + case ESP_BLE_MESH_DFD_OP_FW_DELETE_ALL: + return bt_mesh_dfd_cli_firmware_delete_all(¶m); + default: + BT_ERR("UknOpc:%04x", params->opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_dfd_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_dfd_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_EVT_DFD_CLIENT_MAX) { + btc_ble_mesh_dfd_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_dfd_client_rsp_deep_free(msg); +} + +void btc_ble_mesh_dfd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_dfd_client_args_t *dst = (btc_ble_mesh_dfd_client_args_t *)p_dest; + btc_ble_mesh_dfd_client_args_t *src = (btc_ble_mesh_dfd_client_args_t *)p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s,InvParam", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFD_CLIENT_GET: + dst->dfd_client_get.params = + (esp_ble_mesh_client_common_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfd_client_get.params == NULL) { + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_get.params, src->dfd_client_get.params, sizeof(esp_ble_mesh_client_common_param_t)); + + if (src->dfd_client_get.get) { + dst->dfd_client_get.get = (esp_ble_mesh_dfd_client_get_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_client_get_param_t)); + if (dst->dfd_client_get.get == NULL) { + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_get.get, src->dfd_client_get.get, sizeof(esp_ble_mesh_dfd_client_get_param_t)); + } + + switch (dst->dfd_client_get.params->opcode) { + case ESP_BLE_MESH_DFD_OP_FW_GET: + if (src->dfd_client_get.get->dist_fw_get.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + bt_mesh_free(dst->dfd_client_get.get); + dst->dfd_client_get.get = NULL; + break; + } + + dst->dfd_client_get.get->dist_fw_get.fwid = + bt_mesh_alloc_buf(src->dfd_client_get.get->dist_fw_get.fwid->len); + if (dst->dfd_client_get.get->dist_fw_get.fwid == NULL) { + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + bt_mesh_free(dst->dfd_client_get.get); + dst->dfd_client_get.get = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_get.get->dist_fw_get.fwid, + src->dfd_client_get.get->dist_fw_get.fwid->data, + src->dfd_client_get.get->dist_fw_get.fwid->len); + break; + default: + break; + } + break; + case BTC_BLE_MESH_ACT_DFD_CLIENT_SET: + dst->dfd_client_set.params = + (esp_ble_mesh_client_common_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfd_client_set.params == NULL) { + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.params, src->dfd_client_set.params, sizeof(esp_ble_mesh_client_common_param_t)); + + if (src->dfd_client_set.set) { + dst->dfd_client_set.set = (esp_ble_mesh_dfd_client_set_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_client_set_param_t)); + if (dst->dfd_client_set.set == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.set, src->dfd_client_set.set, sizeof(esp_ble_mesh_dfd_client_set_param_t)); + } + switch (dst->dfd_client_set.params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (src->dfd_client_set.set->receivers_add.receivers_cnt == 0) { + dst->dfd_client_set.set->receivers_add.receivers = NULL; + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->receivers_add.receivers = + (esp_ble_mesh_dfd_cli_receiver_entry_t *)bt_mesh_calloc(dst->dfd_client_set.set->receivers_add.receivers_cnt * + sizeof(esp_ble_mesh_dfd_cli_receiver_entry_t)); + if (dst->dfd_client_set.set->receivers_add.receivers == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.set->receivers_add.receivers, src->dfd_client_set.set->receivers_add.receivers, + dst->dfd_client_set.set->receivers_add.receivers_cnt * sizeof(esp_ble_mesh_dfd_cli_receiver_entry_t)); + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (src->dfd_client_set.set->dist_upload_start.fwid == NULL) { + dst->dfd_client_set.set->dist_upload_start.fwid = NULL; + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + + dst->dfd_client_set.set->dist_upload_start.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_start.fwid->len); + if (dst->dfd_client_set.set->dist_upload_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_start.fwid, + src->dfd_client_set.set->dist_upload_start.fwid->data, + src->dfd_client_set.set->dist_upload_start.fwid->len); + + if (src->dfd_client_set.set->dist_upload_start.fw_metadata->len == 0) { + dst->dfd_client_set.set->dist_upload_start.fw_metadata = NULL; + break; + } else { + dst->dfd_client_set.set->dist_upload_start.fw_metadata = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_start.fw_metadata->len); + if (dst->dfd_client_set.set->dist_upload_start.fw_metadata == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + bt_mesh_free_buf(dst->dfd_client_set.set->dist_upload_start.fwid); + dst->dfd_client_set.set->dist_upload_start.fwid = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_start.fw_metadata, + src->dfd_client_set.set->dist_upload_start.fw_metadata->data, + src->dfd_client_set.set->dist_upload_start.fw_metadata->len); + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (src->dfd_client_set.set->dist_upload_oob_start.url == NULL || + src->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_upload_oob_start.url = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_oob_start.url->len); + if (dst->dfd_client_set.set->dist_upload_oob_start.url == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_upload_oob_start.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_oob_start.fwid->len); + if (dst->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + bt_mesh_free_buf(dst->dfd_client_set.set->dist_upload_oob_start.url); + dst->dfd_client_set.set->dist_upload_oob_start.url = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_oob_start.url, + src->dfd_client_set.set->dist_upload_oob_start.url->data, + src->dfd_client_set.set->dist_upload_oob_start.url->len); + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_oob_start.fwid, + src->dfd_client_set.set->dist_upload_oob_start.fwid->data, + src->dfd_client_set.set->dist_upload_oob_start.fwid->len); + break; + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + if (src->dfd_client_set.set->dist_fw_del.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_fw_del.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_fw_del.fwid->len); + if (dst->dfd_client_set.set->dist_fw_del.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_fw_del.fwid, + src->dfd_client_set.set->dist_fw_del.fwid->data, + src->dfd_client_set.set->dist_fw_del.fwid->len); + break; + default: + break; + } + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_dfd_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_dfd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (msg->act >= ESP_BLE_MESH_ACT_DFD_CLIENT_MAX) { + BT_ERR("%s, Invalid event %d", __func__, msg->act); + return; + } + + arg = (btc_ble_mesh_dfd_client_args_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_ACT_DFD_CLIENT_GET: + if (arg->dfd_client_get.params == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + switch (arg->dfd_client_get.params->opcode) { + case ESP_BLE_MESH_DFD_OP_FW_GET: + if (arg->dfd_client_get.get->dist_fw_get.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_get.get->dist_fw_get.fwid); + break; + default: + break; + } + if (arg->dfd_client_get.get) { + bt_mesh_free(arg->dfd_client_get.get); + } + bt_mesh_free(arg->dfd_client_get.params); + break; + case ESP_BLE_MESH_ACT_DFD_CLIENT_SET: + if (arg->dfd_client_set.params == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + switch (arg->dfd_client_set.params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (arg->dfd_client_set.set->receivers_add.receivers == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free(arg->dfd_client_set.set->receivers_add.receivers); + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (arg->dfd_client_set.set->dist_upload_start.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_start.fwid); + if (arg->dfd_client_set.set->dist_upload_start.fw_metadata) { + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_start.fw_metadata); + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (arg->dfd_client_set.set->dist_upload_oob_start.url == NULL || + arg->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_oob_start.url); + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_oob_start.fwid); + break; + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + if (arg->dfd_client_set.set->dist_fw_del.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_fw_del.fwid); + break; + } + if (arg->dfd_client_set.set) { + bt_mesh_free(arg->dfd_client_set.set); + } + bt_mesh_free(arg->dfd_client_set.params); + break; + default: + BT_WARN("Unprocessed event %d", msg->act); + break; + } + + return; +} + +void btc_ble_mesh_dfd_client_rsp_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_dfd_client_cb_param_t *dst =(esp_ble_mesh_dfd_client_cb_param_t *) p_dest; + esp_ble_mesh_dfd_client_cb_param_t *src =(esp_ble_mesh_dfd_client_cb_param_t *) p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + dst->err_code = src->err_code; + + if (src->params) { + dst->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->params == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + memcpy(dst->params, src->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + switch(dst->params->opcode) { + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + dst->status_cb.receiver_list.first_index = src->status_cb.receiver_list.first_index; + dst->status_cb.receiver_list.entries_cnt = src->status_cb.receiver_list.entries_cnt; + if (dst->status_cb.receiver_list.entries_cnt) { + dst->status_cb.receiver_list.entries = bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_target_node_entry_t) * dst->status_cb.receiver_list.entries_cnt); + if (dst->status_cb.receiver_list.entries == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + memcpy(dst->status_cb.receiver_list.entries, src->status_cb.receiver_list.entries, + sizeof(esp_ble_mesh_dfd_target_node_entry_t) * dst->status_cb.receiver_list.entries_cnt); + } else { + dst->status_cb.receiver_list.entries = NULL; + } + break; + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + dst->status_cb.dist_caps.max_receiver_list_sz = src->status_cb.dist_caps.max_receiver_list_sz; + dst->status_cb.dist_caps.max_fw_list_sz = src->status_cb.dist_caps.max_fw_list_sz; + dst->status_cb.dist_caps.max_fw_sz = src->status_cb.dist_caps.max_fw_sz; + dst->status_cb.dist_caps.max_upload_space = src->status_cb.dist_caps.max_upload_space; + dst->status_cb.dist_caps.remaining_upload_space = src->status_cb.dist_caps.remaining_upload_space; + dst->status_cb.dist_caps.oob_retrieval_supported = src->status_cb.dist_caps.oob_retrieval_supported; + if (src->status_cb.dist_caps.supported_url_scheme_names) { + dst->status_cb.dist_caps.supported_url_scheme_names = + bt_mesh_alloc_buf(src->status_cb.dist_caps.supported_url_scheme_names->len); + if (dst->status_cb.dist_caps.supported_url_scheme_names == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.dist_caps.supported_url_scheme_names, + src->status_cb.dist_caps.supported_url_scheme_names->data, + src->status_cb.dist_caps.supported_url_scheme_names->len); + } else { + dst->status_cb.dist_caps.supported_url_scheme_names = NULL; + } + break; + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + dst->status_cb.upload_status.status = src->status_cb.upload_status.status; + dst->status_cb.upload_status.upload_phase = src->status_cb.upload_status.upload_phase; + dst->status_cb.upload_status.upload_progress = src->status_cb.upload_status.upload_progress; + dst->status_cb.upload_status.upload_type = src->status_cb.upload_status.upload_type; + + if (dst->status_cb.upload_status.upload_progress == ESP_BLE_MESH_DFD_UPLOAD_PROGRESS_UNSET) { + dst->status_cb.upload_status.fwid = NULL; + return; + } + + if (dst->status_cb.upload_status.upload_type == ESP_BLE_MESH_DFD_UPLOAD_TYPE_INBAND) { + if (src->status_cb.upload_status.fwid) { + dst->status_cb.upload_status.fwid = bt_mesh_alloc_buf(src->status_cb.upload_status.fwid->len); + if (dst->status_cb.upload_status.fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.upload_status.fwid, + src->status_cb.upload_status.fwid->data, + src->status_cb.upload_status.fwid->len); + } else { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + } + } else { + if(src->status_cb.upload_status.oob_fwid) { + dst->status_cb.upload_status.oob_fwid = bt_mesh_alloc_buf(src->status_cb.upload_status.oob_fwid->len); + if (dst->status_cb.upload_status.oob_fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.upload_status.oob_fwid, + src->status_cb.upload_status.oob_fwid->data, + src->status_cb.upload_status.oob_fwid->len); + } else { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + } + } + break; + case BLE_MESH_DFD_OP_FW_STATUS: + dst->status_cb.firmware_status.status = src->status_cb.firmware_status.status; + dst->status_cb.firmware_status.entry_cnt = src->status_cb.firmware_status.entry_cnt; + dst->status_cb.firmware_status.fw_idx = src->status_cb.firmware_status.fw_idx; + if (src->status_cb.firmware_status.fwid) { + dst->status_cb.firmware_status.fwid = bt_mesh_alloc_buf(src->status_cb.firmware_status.fwid->len); + if (dst->status_cb.firmware_status.fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.firmware_status.fwid, + src->status_cb.firmware_status.fwid->data, + src->status_cb.firmware_status.fwid->len); + } else { + dst->status_cb.firmware_status.fwid = NULL; + } + break; + case BLE_MESH_DFD_OP_RECEIVERS_STATUS: + dst->status_cb.receiver_status.status = src->status_cb.receiver_status.status; + dst->status_cb.receiver_status.receiver_list_cnt = src->status_cb.receiver_status.receiver_list_cnt; + break; + case BLE_MESH_DFD_OP_STATUS: + dst->status_cb.dist_status.status = src->status_cb.dist_status.status; + dst->status_cb.dist_status.dist_phase = src->status_cb.dist_status.dist_phase; + dst->status_cb.dist_status.multicast_address = src->status_cb.dist_status.multicast_address; + dst->status_cb.dist_status.appkey_idx = src->status_cb.dist_status.appkey_idx; + dst->status_cb.dist_status.ttl = src->status_cb.dist_status.ttl; + dst->status_cb.dist_status.timeout_base = src->status_cb.dist_status.timeout_base; + dst->status_cb.dist_status.trans_mode = src->status_cb.dist_status.trans_mode; + dst->status_cb.dist_status.update_policy = src->status_cb.dist_status.update_policy; + dst->status_cb.dist_status.firmware_image_index = src->status_cb.dist_status.firmware_image_index; + break; + default: + BT_ERR("Unknown opcode %04x", dst->params->opcode); + break; + + } + break; + case ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT: + break; + case ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP: + break; + default: + BT_ERR("Unknown event %d", msg->act); + } + +} + +void btc_ble_mesh_dfd_client_rsp_deep_free(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + return; + } + + arg = (esp_ble_mesh_dfd_client_cb_param_t *)(msg->arg); + + if (arg->params == NULL && + msg->act != ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + switch (arg->params->opcode) { + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + if (arg->status_cb.receiver_list.entries) { + bt_mesh_free(arg->status_cb.receiver_list.entries); + arg->status_cb.receiver_list.entries = NULL; + } + break; + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + if (arg->status_cb.dist_caps.supported_url_scheme_names) { + bt_mesh_free_buf(arg->status_cb.dist_caps.supported_url_scheme_names); + arg->status_cb.dist_caps.supported_url_scheme_names = NULL; + } + break; + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + /** + * firmware_id and upload_oob_firmware_id are a union + * structure, so only one pointer needs to be released + */ + if (arg->status_cb.upload_status.fwid) { + bt_mesh_free_buf(arg->status_cb.upload_status.fwid); + arg->status_cb.upload_status.fwid = NULL; + } + break; + case BLE_MESH_DFD_OP_FW_STATUS: + if (arg->status_cb.firmware_status.fwid) { + bt_mesh_free_buf(arg->status_cb.firmware_status.fwid); + arg->status_cb.firmware_status.fwid = NULL; + } + break; + } + break; + default: + break; + } + + if (arg->params) { + bt_mesh_free(arg->params); + } +} + +static void btc_ble_mesh_dfd_client_callback(esp_ble_mesh_dfd_client_cb_param_t *cb_params, + uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DFD_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, cb_params == NULL ? 0 : sizeof(esp_ble_mesh_dfd_client_cb_param_t), + btc_ble_mesh_dfd_client_rsp_deep_copy, btc_ble_mesh_dfd_client_rsp_deep_free); +} + +void bt_mesh_dfd_client_cb_evt_to_btc(btc_ble_mesh_dfd_client_cb_evt_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_dfd_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0U; + + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP; + break; + case BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT: + act = ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT; + break; + default: + BT_ERR("Unknown event %d", event); + break; + } + + params.opcode = ctx->recv_op; + params.model = (esp_ble_mesh_model_t *)model; + btc_ble_mesh_msg_ctx_copy((struct bt_mesh_msg_ctx *)¶ms.ctx, ctx, false); + + cb_params.params = ¶ms; + cb_params.err_code = 0; + + if (val && len) { + memcpy(&cb_params.status_cb, val, len); + } + + btc_ble_mesh_dfd_client_callback(&cb_params, act); + return; +} + +void btc_ble_mesh_dfd_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t cb = {0}; + btc_ble_mesh_dfd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s,InvParam", __func__); + return; + } + + arg = (btc_ble_mesh_dfd_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFD_CLIENT_GET: + cb.params = arg->dfd_client_get.params; + cb.err_code = btc_ble_mesh_dfd_client_get(arg->dfd_client_get.params, arg->dfd_client_get.get); + btc_ble_mesh_dfd_client_callback(&cb, ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP); + break; + case BTC_BLE_MESH_ACT_DFD_CLIENT_SET: + cb.params = arg->dfd_client_set.params; + cb.err_code = btc_ble_mesh_dfd_client_set(arg->dfd_client_set.params, arg->dfd_client_set.set); + btc_ble_mesh_dfd_client_callback(&cb, ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP); + break; + default: + break; + } + + btc_ble_mesh_dfd_client_arg_deep_free(msg); +} +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +#if CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +int btc_ble_mesh_dfd_srv_oob_check_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len) +{ + bt_mesh_dfd_srv_oob_check_complete((struct bt_mesh_dfd_srv *)srv, (struct bt_mesh_dfu_slot *)slot, status, fwid, fwid_len); + return 0; +} +int btc_ble_mesh_dfd_srv_oob_store_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len) +{ + bt_mesh_dfd_srv_oob_store_complete((struct bt_mesh_dfd_srv *)srv, (struct bt_mesh_dfu_slot *)slot, success, size, metadata, metadata_len); + return 0; +} +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c new file mode 100644 index 000000000000..1c92a05567bd --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "dfu_slot.h" +#include "esp_ble_mesh_dfu_model_api.h" +#include "esp_ble_mesh_dfu_slot_api.h" +#include "btc_ble_mesh_dfu_slot.h" + +#if CONFIG_BLE_MESH_DFU_SLOTS +int btc_ble_mesh_dfu_slot_count(void) +{ + return bt_mesh_dfu_slot_count(); +} + +struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_reserve(void) +{ + return (struct esp_ble_mesh_dfu_slot *)bt_mesh_dfu_slot_reserve(); +} + +int btc_ble_mesh_dfu_slot_info_set(struct esp_ble_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + return bt_mesh_dfu_slot_info_set((struct bt_mesh_dfu_slot *) dfu_slot, size, + metadata, metadata_len); +} + +int btc_ble_mesh_dfu_slot_fwid_set(struct esp_ble_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + return bt_mesh_dfu_slot_fwid_set((struct bt_mesh_dfu_slot *) dfu_slot, fwid, + fwid_len); +} + +int btc_ble_mesh_dfu_slot_commit(struct esp_ble_mesh_dfu_slot *dfu_slot) +{ + return bt_mesh_dfu_slot_commit((struct bt_mesh_dfu_slot *) dfu_slot); +} + +void btc_ble_mesh_dfu_slot_release(const struct esp_ble_mesh_dfu_slot *dfu_slot) +{ + bt_mesh_dfu_slot_release((const struct bt_mesh_dfu_slot *)dfu_slot); +} + +int btc_ble_mesh_dfu_slot_del(const struct esp_ble_mesh_dfu_slot *slot) +{ + return bt_mesh_dfu_slot_del((const struct bt_mesh_dfu_slot *)slot); +} + +void btc_ble_mesh_dfu_slot_del_all(void) +{ + bt_mesh_dfu_slot_del_all(); +} + +const struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_at(uint16_t img_idx) +{ + return (const struct esp_ble_mesh_dfu_slot *)bt_mesh_dfu_slot_at(img_idx); +} + +int btc_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct esp_ble_mesh_dfu_slot **slot) +{ + return bt_mesh_dfu_slot_get(fwid, fwid_len, (struct bt_mesh_dfu_slot **)slot); +} + +int btc_ble_mesh_dfu_slot_img_idx_get(const struct esp_ble_mesh_dfu_slot *slot) +{ + return bt_mesh_dfu_slot_img_idx_get((const struct bt_mesh_dfu_slot *)slot); +} + +size_t btc_ble_mesh_dfu_slot_foreach(esp_ble_mesh_dfu_slot_cb_t cb, void *user_data) +{ + return bt_mesh_dfu_slot_foreach((bt_mesh_dfu_slot_cb_t)cb, user_data); +} +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h new file mode 100644 index 000000000000..0111e8654949 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_DFU_MODEL_H_ +#define _BTC_BLE_MESH_DFU_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_dfu_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BLE_MESH_DFU_CLI +typedef enum { + BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND, + BTC_BLE_MESH_ACT_DFU_CLIENT_MAX, +} btc_ble_mesh_dfu_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfu_client_get_t *get; + } dfu_get; + struct { + struct esp_ble_mesh_dfu_cli *cli; + struct esp_ble_mesh_blob_cli_inputs *inputs; + struct esp_ble_mesh_blob_io *io; + struct esp_ble_mesh_dfu_cli_xfer *xfer; + } send_arg; +} btc_ble_mesh_dfu_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT, + BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + BTC_BLE_MESH_EVT_DFU_CLIENT_IMG_SEND_CMP, + BTC_BLE_MESH_EVT_DFU_CLIENT_MAX, +} btc_ble_mesh_dfu_client_cb_evt_t; + +void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfu_client_arg_deep_free(btc_msg_t *msg); +void bt_mesh_dfu_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); +void btc_ble_mesh_dfu_client_call_handler(btc_msg_t *msg); +void btc_ble_mesh_dfu_client_cb_handler(btc_msg_t *msg); +uint8_t btc_ble_mesh_dfu_cli_progress(struct esp_ble_mesh_dfu_cli *cli); +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV + +void btc_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv); + +bool btc_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); + +uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +typedef enum { + BTC_BLE_MESH_ACT_DFD_CLIENT_GET, + BTC_BLE_MESH_ACT_DFD_CLIENT_SET, + BTC_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP, + BTC_BLE_MESH_ACT_DFD_CLIENT_MAX, +} btc_ble_mesh_dfd_client_act_t; + +typedef enum { + BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, + BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_DFD_CLIENT_MAX, +} btc_ble_mesh_dfd_client_cb_evt_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfd_client_get_param_t *get; + } dfd_client_get; + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfd_client_set_param_t *set; + } dfd_client_set; +} btc_ble_mesh_dfd_client_args_t; + +void btc_ble_mesh_dfd_client_cb_handler(btc_msg_t *msg); +void btc_ble_mesh_dfd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfd_client_arg_deep_free(btc_msg_t *msg); +void btc_ble_mesh_dfd_client_rsp_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfd_client_rsp_deep_free(btc_msg_t *msg); +void bt_mesh_dfd_client_cb_evt_to_btc(btc_ble_mesh_dfd_client_cb_evt_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); +void btc_ble_mesh_dfd_client_call_handler(btc_msg_t *msg); + +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +#if CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +int btc_ble_mesh_dfd_srv_oob_check_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len); +int btc_ble_mesh_dfd_srv_oob_store_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_DFU_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h new file mode 100644 index 000000000000..90867586c9da --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_DFU_SLOT_H_ +#define _BTC_BLE_MESH_DFU_SLOT_H_ + +int btc_ble_mesh_dfu_slot_count(void); + +struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_reserve(void); + +int btc_ble_mesh_dfu_slot_info_set(struct esp_ble_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +int btc_ble_mesh_dfu_slot_fwid_set(struct esp_ble_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +int btc_ble_mesh_dfu_slot_commit(struct esp_ble_mesh_dfu_slot *dfu_slot); + +void btc_ble_mesh_dfu_slot_release(const struct esp_ble_mesh_dfu_slot *dfu_slot); + +int btc_ble_mesh_dfu_slot_del(const struct esp_ble_mesh_dfu_slot *slot); + +void btc_ble_mesh_dfu_slot_del_all(void); + +const struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_at(uint16_t img_idx); + +int btc_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct esp_ble_mesh_dfu_slot **slot); + +int btc_ble_mesh_dfu_slot_img_idx_get(const struct esp_ble_mesh_dfu_slot *slot); + +size_t btc_ble_mesh_dfu_slot_foreach(esp_ble_mesh_dfu_slot_cb_t cb, void *user_data); + +#endif /* _BTC_BLE_MESH_DFU_SLOT_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h index 070888ca55df..4bb82ed1a34f 100644 --- a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,11 @@ extern "C" { #endif +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + typedef enum { BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES, BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB, @@ -136,6 +141,10 @@ void bt_mesh_mbt_server_cb_evt_to_btc(uint8_t event, struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx); +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic pop +#endif + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c new file mode 100644 index 000000000000..19fce3b9a8c8 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c @@ -0,0 +1,699 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "dfu_slot.h" +#include "dfu.h" +#include "net.h" +#include "transport.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" +#include "btc_ble_mesh_dfu_model.h" + +#include "mesh_v1.1/dfu/dfd_cli.h" + +#if CONFIG_BLE_MESH_DFD_CLI +static const bt_mesh_client_op_pair_t dfd_cli_pair[] = { + {BLE_MESH_DFD_OP_RECEIVERS_ADD, BLE_MESH_DFD_OP_RECEIVERS_STATUS}, + {BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, BLE_MESH_DFD_OP_RECEIVERS_STATUS}, + {BLE_MESH_DFD_OP_RECEIVERS_GET, BLE_MESH_DFD_OP_RECEIVERS_LIST}, + {BLE_MESH_DFD_OP_CAPABILITIES_GET, BLE_MESH_DFD_OP_CAPABILITIES_STATUS}, + {BLE_MESH_DFD_OP_GET, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_START, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_SUSPEND, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_CANCEL, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_APPLY, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_GET, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_START, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_START_OOB, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_CANCEL, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_FW_GET, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_GET_BY_INDEX, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_DELETE, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_DELETE_ALL, BLE_MESH_DFD_OP_FW_STATUS}, +}; + +static bt_mesh_mutex_t dfd_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("DFDRspTmo"); + + bt_mesh_mutex_lock(&dfd_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + bt_mesh_dfd_client_cb_evt_to_btc(BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, node->model, &node->ctx, NULL, 0); + bt_mesh_client_free_node(node); + } + } + + bt_mesh_mutex_unlock(&dfd_client_lock); + + return; +} + +static void dfd_client_recv_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + void *status, size_t len) +{ + bt_mesh_client_node_t *node = NULL; + struct net_buf_simple buf = {0}; + btc_ble_mesh_dfd_client_cb_evt_t evt = 0; + + if (!model || !ctx) { + BT_ERR("%s,InvParam", __func__); + return; + } + + buf.data = (uint8_t *)status; + buf.len = (uint16_t)len; + + bt_mesh_mutex_lock(&dfd_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, &buf, true); + if (!node) { + BT_DBG("UnexpDfdStus:0x%04x", ctx->recv_op); + } else { + switch (ctx->recv_op) { + case BLE_MESH_DFD_OP_RECEIVERS_STATUS: + case BLE_MESH_DFD_OP_CAPABILITIES_GET: + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + case BLE_MESH_DFD_OP_STATUS: + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + case BLE_MESH_DFD_OP_FW_STATUS: + evt = BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP; + break; + default: + BT_ERR("UnkwnOpc:%04x", node->opcode); + break; + } + + if (!k_delayed_work_free(&node->timer)) { + bt_mesh_dfd_client_cb_evt_to_btc(evt, model, ctx, (const uint8_t *)status, len); + bt_mesh_client_free_node(node); + } + } + + bt_mesh_mutex_unlock(&dfd_client_lock); +} + +static void handle_receiver_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + + status.receiver_status.status = net_buf_simple_pull_u8(buf); + + if (status.receiver_status.status > BLE_MESH_DFD_ERR_SUSPEND_FAILED) { + BT_ERR("InvSrvStu:%d", status.receiver_status.status); + return; + } + + if (status.receiver_status.status != BLE_MESH_DFD_SUCCESS) { + BT_ERR("StusErr:%d", status); + return; + } + + status.receiver_status.receiver_list_cnt = net_buf_simple_pull_le16(buf); + + BT_DBG("RecvLstCnt:%d", status.receiver_status.receiver_list_cnt); + + dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_status)); +} + +static void handle_receiver_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + int i = 0; + uint32_t target_info = 0; + + dfd_status_t status = {0}; + status.receiver_list.entries_cnt = net_buf_simple_pull_le16(buf); + status.receiver_list.first_index = net_buf_simple_pull_le16(buf); + status.receiver_list.entries = bt_mesh_calloc(status.receiver_list.entries_cnt * sizeof(target_node_entry_t)); + for (i = 0; i < status.receiver_list.entries_cnt; i++) { + target_info = net_buf_simple_pull_le32(buf); + status.receiver_list.entries[i].addr = TARGET_ADDR(target_info); + status.receiver_list.entries[i].retrieved_update_phase = TARGET_UPDATE_PHASE(target_info); + status.receiver_list.entries[i].update_status = TARGET_UPDATE_STATUS(target_info); + status.receiver_list.entries[i].transfer_status = TARGET_TRANSFER_STATUS(target_info); + status.receiver_list.entries[i].transfer_progress = TARGET_TRANSFER_PROGRESS(target_info); + status.receiver_list.entries[i].update_fw_idx = net_buf_simple_pull_u8(buf); + } + dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_list)); + bt_mesh_free(status.receiver_list.entries); + return; +} + +static void handle_capabilities(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + struct net_buf_simple url_scheme_names = {0}; + + status.dist_caps.max_receiver_list_sz = net_buf_simple_pull_le16(buf); + status.dist_caps.max_fw_list_sz = net_buf_simple_pull_le16(buf); + status.dist_caps.max_fw_sz = net_buf_simple_pull_le32(buf); + status.dist_caps.max_upload_space = net_buf_simple_pull_le32(buf); + status.dist_caps.remaining_upload_space = net_buf_simple_pull_le32(buf); + status.dist_caps.oob_retrieval_supported = net_buf_simple_pull_le32(buf); + if (buf->len) { + status.dist_caps.supported_url_scheme_names = &url_scheme_names; + net_buf_simple_init_with_data(status.dist_caps.supported_url_scheme_names, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } + dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_caps)); + return; +} + +static void handle_dfd_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + uint8_t trans_mode_policy = 0; + + status.dist_status.status = net_buf_simple_pull_u8(buf); + status.dist_status.dist_phase = net_buf_simple_pull_u8(buf); + if (buf->len != 0 && buf->len != 10) { + BT_ERR("Invalid data"); + return; + } + status.dist_status.multicast_address = net_buf_simple_pull_le16(buf); + status.dist_status.appkey_idx = net_buf_simple_pull_le16(buf); + status.dist_status.ttl = net_buf_simple_pull_u8(buf); + status.dist_status.timeout_base = net_buf_simple_pull_le16(buf); + + trans_mode_policy = net_buf_simple_pull_u8(buf); + if ((trans_mode_policy & ~(BIT6 - 1)) != 0) { + BT_ERR("RFU should be zero"); + return; + } + status.dist_status.trans_mode = trans_mode_policy >> 6; + status.dist_status.update_policy = (trans_mode_policy >> 5) & 0x01; + status.dist_status.RFU = trans_mode_policy & 0x1f; + status.dist_status.fw_idx = net_buf_simple_pull_le16(buf); + dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_status)); + return; +} + +static void handle_upload_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + uint8_t progress_type = 0; + struct net_buf_simple buf_cache = {0}; + status.upload_status.status = net_buf_simple_pull_u8(buf); + status.upload_status.upload_phase = net_buf_simple_pull_u8(buf); + + if (buf->len == 0) { + status.upload_status.upload_progress = UPLOAD_PROGRESS_UNSET; + dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status)); + return; + } + + progress_type = net_buf_simple_pull_u8(buf); + status.upload_status.upload_progress = progress_type>>1; + + if (status.upload_status.upload_progress >= UPLOAD_PROGRESS_UNSET) { + BT_ERR("Invalid upload progress"); + return; + } + + if (buf->len == 0) { + BT_ERR("InvFwID"); + return; + } + + status.upload_status.upload_type = progress_type & 0x01; + if (status.upload_status.upload_type == UPLOAD_IN_BAND) { + status.upload_status.fwid = &buf_cache; + net_buf_simple_init_with_data(status.upload_status.fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } else if (status.upload_status.upload_type == UPLOAD_OOB){ + status.upload_status.oob_fwid = &buf_cache; + net_buf_simple_init_with_data(status.upload_status.oob_fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } else { + BT_ERR("Invalid upload type:%d", status.upload_status.upload_type); + return; + } + + dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status)); + return; +} + +static void handle_fw_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + struct net_buf_simple buf_cache = {0}; + status.firmware_status.status = net_buf_simple_pull_u8(buf); + status.firmware_status.entry_cnt = net_buf_simple_pull_le16(buf); + status.firmware_status.firmware_image_index = net_buf_simple_pull_le16(buf); + if (buf->len) { + status.firmware_status.fwid = &buf_cache; + net_buf_simple_init_with_data(status.firmware_status.fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } + + dfd_client_recv_status(model, ctx, &status, sizeof(status.firmware_status)); + return; +} + +const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[] = { + { BLE_MESH_DFD_OP_RECEIVERS_STATUS, 3, handle_receiver_status }, + { BLE_MESH_DFD_OP_RECEIVERS_LIST, 4 , handle_receiver_list }, + { BLE_MESH_DFD_OP_CAPABILITIES_STATUS, 17, handle_capabilities }, + { BLE_MESH_DFD_OP_STATUS, 2, handle_dfd_status }, + { BLE_MESH_DFD_OP_UPLOAD_STATUS, 2, handle_upload_status }, + { BLE_MESH_DFD_OP_FW_STATUS, 5, handle_fw_status }, +}; + +int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, dfd_cli_receiver_entry_t *receivers, uint16_t receivers_cnt) +{ + uint16_t msg_length = 2; + struct net_buf_simple *msg = NULL; + dfd_cli_receiver_entry_t *entry = NULL; + int err = 0; + + if (param == NULL) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + BT_INFO("AddedValidCnt:%d", receivers_cnt); + msg_length += (receivers_cnt * 3); + + /* needs to confirm long or short mic */ + if (msg_length > BLE_MESH_MAX_PDU_LEN_WITH_SMIC) { + BT_ERR("Too much receivers added once time"); + return -EINVAL; + } + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_RECEIVERS_ADD); + + for (int i = 0; i < receivers_cnt; i++) { + entry = &receivers[i]; + if (BLE_MESH_ADDR_IS_UNICAST(entry->addr)) { + net_buf_simple_add_le16(msg, entry->addr); + net_buf_simple_add_u8(msg, entry->fw_idx); + BT_INFO("AddedUnicastAddr:0x%04x,FwIdx:%d", entry->addr, entry->fw_idx); + } + } + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_receivers_delete_all(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL); + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_receivers_get(bt_mesh_client_common_param_t *param, uint16_t first_index, uint16_t entries_limit) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_GET, 4); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_GET); + net_buf_simple_add_le16(&msg, first_index); + net_buf_simple_add_le16(&msg, entries_limit); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_capabilities_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CAPABILITIES_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CAPABILITIES_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_start_t *start) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_START, 2 + 1 + 2 + 1 + 2 + 16); + if (!param || !start) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_START); + net_buf_simple_add_le16(&msg, start->app_idx); + net_buf_simple_add_u8(&msg, start->ttl); + net_buf_simple_add_le16(&msg, start->timeout_base); + net_buf_simple_add_u8(&msg, ((start->trans_mode) << 6) | ((start->update_policy) << 5)); + net_buf_simple_add_le16(&msg, start->fw_idx); + + if (start->is_va) { + net_buf_simple_add_mem(&msg, &(start->label_uuid), 16); + } else { + net_buf_simple_add_le16(&msg, start->group_addr); + } + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_suspend(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_SUSPEND, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_SUSPEND); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_cancel(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CANCEL, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CANCEL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_apply(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_APPLY, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_APPLY); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_upload_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_upload_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_start_t *start) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err = 0; + + if (!param || !start) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + msg_length += (1 + 2 + 8 + 4 + 1 + start->fwid->len); + if (start->fw_metadata) { + msg_length += start->fw_metadata->len; + } + + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START); + net_buf_simple_add_u8(msg, start->ttl); + net_buf_simple_add_le16(msg, start->timeout_base); + net_buf_simple_add_le64(msg, start->blob_id); + net_buf_simple_add_le32(msg, start->fw_size); + if (start->fw_metadata) { + net_buf_simple_add_u8(msg, start->fw_metadata->len); + net_buf_simple_add_mem(msg, start->fw_metadata->data, start->fw_metadata->len); + } else { + net_buf_simple_add_u8(msg, 0); + } + net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_oob_start_t *start) +{ + int err = 0; + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + + if (!param || !start) { + BT_ERR("Invalid param"); + return -1; + } + + if (!start->url) { + BT_ERR("Null url info"); + return -1; + } + + if (!start->fwid) { + BT_ERR("Invalid firmware id"); + return -1; + } + + msg_length += (1 + start->url->len + start->fwid->len); + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START_OOB); + net_buf_simple_add_u8(msg, start->url->len); + net_buf_simple_add_mem(msg, start->url->data, start->url->len); + net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_distribution_upload_oob_cancel(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL, 0); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_firmware_get(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err; + + + if (!fwid) { + BT_ERR("NULL Firmware id"); + return -EINVAL; + } + + msg_length += fwid->len; + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_GET); + net_buf_simple_add_mem(msg, fwid->data, fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_firmware_get_by_index(bt_mesh_client_common_param_t *param, uint16_t fw_id_index) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX, 2); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX); + + net_buf_simple_add_le16(&msg, fw_id_index); + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_firmware_get_delete(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err; + + + if (!fwid) { + BT_ERR("NULL Firmware id"); + return -EINVAL; + } + + msg_length += fwid->len; + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_DELETE); + net_buf_simple_add_mem(msg, fwid->data, fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_firmware_delete_all(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_DELETE_ALL, 0); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_DELETE_ALL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +static int dfd_cli_init(struct bt_mesh_model *model) +{ + bt_mesh_dfd_client_t *client = NULL; + dfd_internal_data_t *internal = NULL; + + if (!model) { + BT_ERR("Invalid Device Firmware Distribution Client model"); + return -EINVAL; + } + + if (!bt_mesh_model_in_primary(model)) { + BT_ERR("Device Firmware Distribution Client only allowed in primary element"); + return -EINVAL; + } + + client = (bt_mesh_dfd_client_t *)model->user_data; + if (!client) { + BT_ERR("No Device Firmware Distribution Client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(dfd_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(dfd_cli_pair); + client->op_pair = dfd_cli_pair; + client->internal_data = internal; + BT_INFO("Dfd client initialized"); + bt_mesh_mutex_create(&dfd_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int dfd_cli_deinit(struct bt_mesh_model *model) +{ + bt_mesh_dfd_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Device Firmware Distribution Client model"); + return -EINVAL; + } + + client = (bt_mesh_dfd_client_t *)model->user_data; + if (!client) { + BT_ERR("No Device Firmware Distribution Client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&dfd_client_lock); + + return 0; +} +#endif + +const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb = { + .init = dfd_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfd_cli_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; +#endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c new file mode 100644 index 000000000000..955419ef1f6c --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c @@ -0,0 +1,1310 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "dfu_slot.h" +#include "dfu.h" +#include "dfd_srv_internal.h" +#include "net.h" +#include "transport.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/dfu/dfd_srv.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#if CONFIG_BLE_MESH_DFD_SRV +#define DFD_UPLOAD_STATUS_MSG_MAXLEN (5 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN) + +_Static_assert((DFD_UPLOAD_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_UPLOAD_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Distribution Upload Status message does not fit into the maximum " + "outgoing SDU size."); + +#define DFD_UPLOAD_START_MSG_MAXLEN (16 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) + +_Static_assert((DFD_UPLOAD_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_UPLOAD_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Distribution Upload Start message does not fit into the maximum " + "incoming SDU size."); + +#define DFD_RECEIVERS_LIST_MSG_MAXLEN (4 + CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 5) + +_Static_assert((DFD_RECEIVERS_LIST_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_RECEIVERS_LIST) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Distribution Receivers List message does not fit into the maximum " + "outgoing SDU size."); + +#define DFD_RECEIVERS_ADD_MSG_MAXLEN (CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 3) + +_Static_assert((DFD_RECEIVERS_ADD_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_RECEIVERS_ADD) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Distribution Receivers Add message does not fit into the maximum " + "incoming SDU size."); + +struct slot_search_ctx { + off_t offset; + size_t size; + bool failed; +}; + +static void dfd_phase_set(struct bt_mesh_dfd_srv *srv, + enum bt_mesh_dfd_phase new_phase) +{ + srv->phase = new_phase; + + if (srv->cb && srv->cb->phase) { + srv->cb->phase(srv, srv->phase); + } +} + +static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfd_srv *srv, + uint16_t addr) +{ + for (int i = 0; i < srv->target_cnt; ++i) { + if (addr == srv->targets[i].blob.addr) { + return &srv->targets[i]; + } + } + + return NULL; +} + +static bool is_busy(const struct bt_mesh_dfd_srv *srv) +{ + return srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS || + srv->phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE; +} + +static bool upload_is_busy(const struct bt_mesh_dfd_srv *srv) +{ + return bt_mesh_blob_srv_is_busy(&srv->upload.blob) || + srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; +} + +static int slot_del(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot) +{ + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } + + return bt_mesh_dfu_slot_del(slot); +} + +static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFD_OP_RECEIVERS_STATUS, 3); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFD_OP_RECEIVERS_STATUS); + + net_buf_simple_add_u8(&buf, status); + net_buf_simple_add_le16(&buf, srv->target_cnt); + + bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_dfd_status status = BLE_MESH_DFD_SUCCESS; + struct bt_mesh_dfd_srv *srv = mod->user_data; + + if (buf->len % 3) { + return -EINVAL; + } + + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + receivers_status_rsp(srv, ctx, + BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); + return 0; + } + + while (buf->len >= 3 && status == BLE_MESH_DFD_SUCCESS) { + uint8_t img_idx; + uint16_t addr; + + addr = net_buf_simple_pull_le16(buf); + img_idx = net_buf_simple_pull_u8(buf); + + status = bt_mesh_dfd_srv_receiver_add(srv, addr, img_idx); + } + + receivers_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); + + return 0; +} + +static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + uint16_t first, cnt; + uint8_t progress; + int i; + + first = net_buf_simple_pull_le16(buf); + cnt = net_buf_simple_pull_le16(buf); + if (cnt == 0) { + return -EINVAL; + } + + /* Create a buffer that can fit the full target list, maxing out at TX_SDU_MAX: */ + NET_BUF_SIMPLE_DEFINE( + rsp, BLE_MESH_MODEL_BUF_LEN(BLE_MESH_DFD_OP_RECEIVERS_LIST, + DFD_RECEIVERS_LIST_MSG_MAXLEN)); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_RECEIVERS_LIST); + + net_buf_simple_add_le16(&rsp, srv->target_cnt); + net_buf_simple_add_le16(&rsp, first); + + cnt = MIN(cnt, srv->target_cnt - first); + progress = bt_mesh_dfu_cli_progress(&srv->dfu) / 2; + + for (i = 0; i < cnt && net_buf_simple_tailroom(&rsp) >= 5 + BLE_MESH_MIC_SHORT; i++) { + const struct bt_mesh_dfu_target *t = &srv->targets[i + first]; + + net_buf_simple_add_le32( + &rsp, ((t->blob.addr & BIT_MASK(15)) | + ((t->phase & BIT_MASK(4)) << 15U) | + ((t->status & BIT_MASK(3)) << 19U) | + ((t->blob.status & BIT_MASK(4)) << 22U) | + ((progress & BIT_MASK(6)) << 26U))); + net_buf_simple_add_u8(&rsp, t->img_idx); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static enum bt_mesh_dfu_iter slot_space_cb(const struct bt_mesh_dfu_slot *slot, + void *user_data) +{ + size_t *total = user_data; + + *total += slot->size; + + return BLE_MESH_DFU_ITER_CONTINUE; +} + +static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + size_t size = 0; + + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_CAPABILITIES_GET, 17); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_CAPABILITIES_GET); + + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFU_SLOT_CNT); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE); + + /* Remaining size */ + (void)bt_mesh_dfu_slot_foreach(slot_space_cb, &size); + size = MIN(size, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE); + + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE - size); + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct bt_mesh_dfd_srv *srv = mod->user_data; + + if (srv->oob_schemes.count > 0) { + net_buf_simple_add_u8(&rsp, 1); + net_buf_simple_add_mem(&rsp, srv->oob_schemes.schemes, + srv->oob_schemes.count); + } else +#endif + { + net_buf_simple_add_u8(&rsp, 0); + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_STATUS, 12); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->phase); + + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } + + net_buf_simple_add_le16(&rsp, srv->inputs.group); + net_buf_simple_add_le16(&rsp, srv->inputs.app_idx); + net_buf_simple_add_u8(&rsp, srv->inputs.ttl); + net_buf_simple_add_le16(&rsp, srv->inputs.timeout_base); + net_buf_simple_add_u8(&rsp, ((srv->dfu.xfer.blob.mode & BIT_MASK(2)) | + ((srv->apply & BIT_MASK(1)) << 2))); + net_buf_simple_add_le16(&rsp, srv->slot_idx); + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + + return 0; +} + +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_start_params params; + uint8_t byte; + + params.app_idx = net_buf_simple_pull_le16(buf); + params.ttl = net_buf_simple_pull_u8(buf); + params.timeout_base = net_buf_simple_pull_le16(buf); + byte = net_buf_simple_pull_u8(buf); + params.xfer_mode = byte & BIT_MASK(2); + params.apply = (byte >> 2U) & BIT_MASK(1); + params.slot_idx = net_buf_simple_pull_le16(buf); + + if (buf->len == 16) { + /* TODO: Virtual addresses not supported. */ + status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + return 0; + } + + if (buf->len != 2) { + return -EINVAL; + } + + params.group = net_buf_simple_pull_le16(buf); + + status_rsp(srv, ctx, bt_mesh_dfd_srv_start(srv, ¶ms)); + + return 0; +} + +static int handle_suspend(const struct bt_mesh_model *mod, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); + + return 0; +} + +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + bt_mesh_dfd_srv_cancel(srv, ctx); + + return 0; +} + +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); + + return 0; +} + +static void upload_status_rsp_with_progress(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, + uint8_t progress) +{ + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_UPLOAD_STATUS, + DFD_UPLOAD_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_UPLOAD_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->upload.phase); + + if (srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_IDLE || + !srv->upload.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + net_buf_simple_add_u8(&rsp, progress | BIT(7)); + net_buf_simple_add_mem(&rsp, srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); + } else +#endif + { + net_buf_simple_add_u8(&rsp, progress); + net_buf_simple_add_mem(&rsp, srv->upload.slot->fwid, + srv->upload.slot->fwid_len); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static void upload_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + uint8_t progress; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + progress = srv->cb->oob_progress_get(srv, srv->upload.slot); + } else +#endif + { + progress = bt_mesh_blob_srv_progress(&srv->upload.blob); + } + + upload_status_rsp_with_progress(srv, ctx, status, progress); +} + +static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + + return 0; +} + +static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, + const uint8_t *fwid, size_t fwid_len) +{ + int err = bt_mesh_dfu_slot_fwid_set(srv->upload.slot, fwid, fwid_len); + + switch (err) { + case -EFBIG: /* Fwid too long */ + case -EALREADY: /* Other server is in progress with this fwid */ + bt_mesh_dfu_slot_release(srv->upload.slot); + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + break; + case -EEXIST: /* Img with this fwid already is in list */ + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + bt_mesh_dfu_slot_release(srv->upload.slot); + + err = bt_mesh_dfu_slot_get(fwid, fwid_len, &srv->upload.slot); + if (!err) { + upload_status_rsp_with_progress(srv, ctx, BLE_MESH_DFD_SUCCESS, 100); + } else { + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + } + break; + case 0: + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + break; + case -EINVAL: /* Slot in wrong state. */ + default: + break; + } + + return err; +} + +static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + size_t meta_len, fwid_len, size; + const uint8_t *meta, *fwid; + uint16_t timeout_base; + uint64_t blob_id; + int err; + uint8_t ttl; + + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + meta_len = net_buf_simple_pull_u8(buf); + if (buf->len < meta_len) { + return -EINVAL; + } + + meta = net_buf_simple_pull_mem(buf, meta_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + BT_DBG("Upload Start: size: %d, fwid: %s, metadata: %s", size, bt_hex(fwid, fwid_len), + bt_hex(meta, meta_len)); + + if (size > CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE) { + upload_status_rsp(srv, ctx, + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + if (upload_is_busy(srv)) { + if (!srv->upload.slot) { + BT_WARN("Busy with no upload slot"); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + return 0; + } + + if (srv->upload.slot->fwid_len == fwid_len && + !memcmp(srv->upload.slot->fwid, fwid, fwid_len) && + srv->upload.slot->metadata_len == meta_len && + !memcmp(srv->upload.slot->metadata, meta, meta_len) && + srv->upload.blob.state.xfer.id == blob_id && + srv->upload.blob.state.ttl == ttl && + srv->upload.blob.state.timeout_base == timeout_base +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + && !srv->upload.is_oob +#endif + ) { + BT_DBG("Duplicate upload start"); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + return 0; + } + + BT_WARN("Upload already in progress"); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; + } + + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + srv->upload.is_oob = false; +#endif + srv->upload.slot = bt_mesh_dfu_slot_reserve(); + + if (!srv->upload.slot) { + BT_WARN("No space for slot"); + upload_status_rsp(srv, ctx, + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + err = set_upload_fwid(srv, ctx, fwid, fwid_len); + if (err) { + return err; + } + + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, meta, meta_len); + switch (err) { + case -EFBIG: + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + break; + case 0: + break; + default: + return err; + } + + srv->io = NULL; + err = srv->cb->recv(srv, srv->upload.slot, &srv->io); + if (err || !srv->io) { + BT_ERR("App rejected upload. err: %d io: %p", err, srv->io); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + return 0; + } + + err = bt_mesh_blob_srv_recv(&srv->upload.blob, blob_id, srv->io, ttl, + timeout_base); + if (err) { + BT_ERR("BLOB Server rejected upload (err: %d)", err); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + return 0; + } + + BT_DBG("%s", bt_hex(fwid, fwid_len)); + + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + + return 0; +} + +static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + uint8_t uri_len; + uint8_t *uri; + uint16_t fwid_len; + uint8_t *fwid; + + uri_len = net_buf_simple_pull_u8(buf); + + if (uri_len > buf->len) { + return -EINVAL; + } + + uri = net_buf_simple_pull_mem(buf, uri_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + BT_DBG("Upload OOB Start"); + BT_INFO("URI %s", bt_hex(uri, uri_len)); + BT_INFO("FWID %s", bt_hex(fwid, fwid_len)); + + if (upload_is_busy(srv)) { +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob && + uri_len == srv->upload.oob.uri_len && + fwid_len == srv->upload.oob.current_fwid_len && + !memcmp(uri, srv->upload.oob.uri, uri_len) && + !memcmp(fwid, srv->upload.oob.current_fwid, fwid_len)) { + /* Same image, return SUCCESS for idempotency */ + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + return 0; + } +#endif + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + } else if (srv->upload.is_oob && srv->upload.is_pending_oob_check) { + /* Ignore the request if we didn't confirm the previous one. */ + return 0; +#endif + } + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (uri_len > CONFIG_BLE_MESH_DFU_URI_MAXLEN || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + return 0; + } + + struct bt_mesh_dfu_slot *slot = bt_mesh_dfu_slot_reserve(); + + if (slot == NULL) { + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } + + srv->upload.is_oob = true; + srv->upload.slot = slot; + memcpy(srv->upload.oob.uri, uri, uri_len); + srv->upload.oob.uri_len = uri_len; + memcpy(srv->upload.oob.current_fwid, fwid, fwid_len); + srv->upload.oob.current_fwid_len = fwid_len; + memcpy(&srv->upload.oob.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + + int status = srv->cb->start_oob_upload(srv, srv->upload.slot, srv->upload.oob.uri, + srv->upload.oob.uri_len, + srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); + + if (status != BLE_MESH_DFD_SUCCESS) { + upload_status_rsp(srv, ctx, status); + bt_mesh_dfu_slot_release(srv->upload.slot); + } else { + srv->upload.is_pending_oob_check = true; + } +#else + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + + return 0; +} + +static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_IDLE; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + srv->cb->cancel_oob_upload(srv, srv->upload.slot); + } else +#endif + { + (void)bt_mesh_blob_srv_cancel(&srv->upload.blob); + } + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + + return 0; +} + +static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, uint16_t idx, + const uint8_t *fwid, size_t fwid_len) +{ + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_FW_STATUS, + 7 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_FW_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_le16(&rsp, bt_mesh_dfu_slot_count()); + + net_buf_simple_add_le16(&rsp, idx); + if (fwid) { + net_buf_simple_add_mem(&rsp, fwid, fwid_len); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfu_slot *slot; + const uint8_t *fwid; + size_t fwid_len; + int idx; + + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + idx = bt_mesh_dfu_slot_get(fwid, fwid_len, &slot); + if (idx >= 0) { + fw_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS, idx, fwid, + fwid_len); + } else { + fw_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, + fwid, fwid_len); + } + + return 0; +} + +static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + const struct bt_mesh_dfu_slot *slot; + uint16_t idx; + + idx = net_buf_simple_pull_le16(buf); + + slot = bt_mesh_dfu_slot_at(idx); + if (slot) { + fw_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS, idx, slot->fwid, + slot->fwid_len); + } else { + fw_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_FW_NOT_FOUND, idx, + NULL, 0); + } + + return 0; +} + +static int handle_fw_delete(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + const uint8_t *fwid; + size_t fwid_len; + + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete(srv, &fwid_len, &fwid); + + fw_status_rsp(srv, ctx, status, 0xffff, fwid, fwid_len); + + return 0; +} + +static enum bt_mesh_dfu_iter slot_del_cb(const struct bt_mesh_dfu_slot *slot, + void *user_data) +{ + struct bt_mesh_dfd_srv *srv = user_data; + + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } + + return BLE_MESH_DFU_ITER_CONTINUE; +} + +static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[] = { + { BLE_MESH_DFD_OP_RECEIVERS_ADD, 3, (void *)handle_receivers_add }, + { BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0, (void *)handle_receivers_delete_all }, + { BLE_MESH_DFD_OP_RECEIVERS_GET, 4, (void *)handle_receivers_get }, + { BLE_MESH_DFD_OP_CAPABILITIES_GET, 0, (void *)handle_capabilities_get }, + { BLE_MESH_DFD_OP_GET, 0, (void *)handle_get }, + { BLE_MESH_DFD_OP_START, 10, (void *)handle_start }, + { BLE_MESH_DFD_OP_SUSPEND, 0, (void *)handle_suspend }, + { BLE_MESH_DFD_OP_CANCEL, 0, (void *)handle_cancel }, + { BLE_MESH_DFD_OP_APPLY, 0, (void *)handle_apply }, + { BLE_MESH_DFD_OP_UPLOAD_GET, 0, (void *)handle_upload_get }, + { BLE_MESH_DFD_OP_UPLOAD_START, 16, (void *)handle_upload_start }, + { BLE_MESH_DFD_OP_UPLOAD_START_OOB, 2, (void *)handle_upload_start_oob }, + { BLE_MESH_DFD_OP_UPLOAD_CANCEL, 0, (void *)handle_upload_cancel }, + { BLE_MESH_DFD_OP_FW_GET, 0, (void *)handle_fw_get }, + { BLE_MESH_DFD_OP_FW_GET_BY_INDEX, 2, (void *)handle_fw_get_by_index }, + { BLE_MESH_DFD_OP_FW_DELETE, 0, (void *)handle_fw_delete }, + { BLE_MESH_DFD_OP_FW_DELETE_ALL, 0, (void *)handle_fw_delete_all }, + + BLE_MESH_MODEL_OP_END +}; + +static void dfu_suspended(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED); +} + +static void dfu_ended(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; + + BT_DBG("reason: %u, phase: %u, apply: %u", reason, srv->phase, srv->apply); + + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE) { + return; + } + + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + return; + } + + if (reason != BLE_MESH_DFU_SUCCESS) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); + return; + } + + if (!srv->apply) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS); + return; + } + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_APPLYING_UPDATE); + + err = bt_mesh_dfu_cli_apply(cli); + if (err) { + BT_ERR("Apply failed: %d", err); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); + } +} + +static void dfu_applied(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; + + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); + return; + } + + if (srv->phase != BLE_MESH_DFD_PHASE_APPLYING_UPDATE) { + return; + } + + err = bt_mesh_dfu_cli_confirm(cli); + if (err) { + BT_ERR("Confirm failed: %d", err); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); + } +} + +static void dfu_confirmed(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + + if (srv->phase != BLE_MESH_DFD_PHASE_APPLYING_UPDATE && + srv->phase != BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + return; + } + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_COMPLETED); +} + +const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb = { + .suspended = dfu_suspended, + .ended = dfu_ended, + .applied = dfu_applied, + .confirmed = dfu_confirmed, +}; + +static int upload_start(struct bt_mesh_blob_srv *b, struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_blob_xfer *xfer) +{ + BT_DBG(""); + return 0; +} + +static void upload_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfd_srv, upload.blob); + + if (srv->upload.phase != BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { + return; + } + + BT_DBG("%u", success); + + if (success && (bt_mesh_dfu_slot_commit(srv->upload.slot) == 0)) { + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return; + } + + /* Will delete slot when we start a new upload */ + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; +} + +static void upload_timeout(struct bt_mesh_blob_srv *b) +{ + BT_DBG(""); + + upload_end(b, b->state.xfer.id, false); +} + +const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb = { + .start = upload_start, + .end = upload_end, + .suspended = upload_timeout, +}; + +static int dfd_srv_init(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + srv->mod = mod; + + return 0; +} + +static void dfd_srv_reset(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfd_srv *srv = mod->user_data; + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_IDLE; + + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; + + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + bt_mesh_dfu_slot_del_all(); +} + +static int dfd_srv_deinit(struct bt_mesh_model *mod) +{ + dfd_srv_reset(mod); + return 0; +} +const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb = { + .init = dfd_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfd_srv_deinit, +#endif +}; + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, + uint8_t img_idx) +{ + struct bt_mesh_dfu_target *t; + struct bt_mesh_blob_target_pull *p; + + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + return BLE_MESH_DFD_SUCCESS; + } + + t = target_get(srv, addr); + if (t) { + t->img_idx = img_idx; + return BLE_MESH_DFD_SUCCESS; + } + + /* New target node, add it to the list */ + + if (srv->target_cnt == ARRAY_SIZE(srv->targets)) { + return BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; + } + + t = &srv->targets[srv->target_cnt]; + p = &srv->pull_ctxs[srv->target_cnt]; + srv->target_cnt++; + + memset(t, 0, sizeof(*t)); + memset(p, 0, sizeof(*p)); + t->blob.addr = addr; + t->blob.pull = p; + t->img_idx = img_idx; + + BT_DBG("Added receiver 0x%04x img: %u", t->blob.addr, + t->img_idx); + + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv) +{ + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; + + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_dfd_start_params *params) +{ + int err, i; + struct bt_mesh_dfu_cli_xfer xfer = { 0 }; + + if (!srv->target_cnt) { + return BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; + } + + if (!bt_mesh_app_key_get(params->app_idx)) { + return BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX; + } + + xfer.mode = params->xfer_mode; + xfer.slot = bt_mesh_dfu_slot_at(params->slot_idx); + if (!xfer.slot) { + return BLE_MESH_DFD_ERR_FW_NOT_FOUND; + } + + if (srv->inputs.app_idx == params->app_idx && + srv->inputs.timeout_base == params->timeout_base && + srv->inputs.group == params->group && srv->inputs.ttl == params->ttl && + srv->dfu.xfer.blob.mode == xfer.mode && srv->apply == params->apply && + srv->slot_idx == params->slot_idx) { + if (is_busy(srv) || + srv->phase == BLE_MESH_DFD_PHASE_COMPLETED) { + BT_WARN("Already completed or in progress"); + return BLE_MESH_DFD_SUCCESS; + } else if (srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + bt_mesh_dfu_cli_resume(&srv->dfu); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE); + return BLE_MESH_DFD_SUCCESS; + } + } else if (is_busy(srv) || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + BT_WARN("Busy with distribution"); + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + BT_WARN("Canceling distribution"); + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + srv->io = NULL; + err = srv->cb->send(srv, xfer.slot, &srv->io); + if (err || !srv->io) { + return BLE_MESH_DFD_ERR_INTERNAL; + } + + sys_slist_init(&srv->inputs.targets); + for (i = 0; i < srv->target_cnt; i++) { + uint16_t addr = srv->targets[i].blob.addr; + + memset(&srv->targets[i].blob, 0, sizeof(struct bt_mesh_blob_target)); + memset(&srv->pull_ctxs[i], 0, sizeof(struct bt_mesh_blob_target_pull)); + srv->targets[i].blob.addr = addr; + srv->targets[i].blob.pull = &srv->pull_ctxs[i]; + + sys_slist_append(&srv->inputs.targets, &srv->targets[i].blob.n); + } + + srv->slot_idx = params->slot_idx; + srv->inputs.app_idx = params->app_idx; + srv->inputs.timeout_base = params->timeout_base; + srv->inputs.group = params->group; + srv->inputs.ttl = params->ttl; + srv->apply = params->apply; + + BT_DBG("Distribution Start: slot: %d, appidx: %d, tb: %d, addr: %04X, ttl: %d, apply: %d", + params->slot_idx, params->app_idx, params->timeout_base, params->group, params->ttl, + params->apply); + + /* DFD Server will always retrieve targets' capabilities before distributing a firmware.*/ + xfer.blob_params = NULL; + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE); + err = bt_mesh_dfu_cli_send(&srv->dfu, &srv->inputs, srv->io, &xfer); + if (err) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + return BLE_MESH_DFD_ERR_INTERNAL; + } + + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv) +{ + int err; + + if (srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + return BLE_MESH_DFD_SUCCESS; + } + + if (srv->phase != BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE) { + return BLE_MESH_DFD_ERR_WRONG_PHASE; + } + + err = bt_mesh_dfu_cli_suspend(&srv->dfu); + if (err) { + return BLE_MESH_DFD_ERR_SUSPEND_FAILED; + } + + srv->phase = BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED; + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx) +{ + enum bt_mesh_dfd_phase prev_phase; + int err; + + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_IDLE) { + if (ctx != NULL) { + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + } + return BLE_MESH_DFD_SUCCESS; + } + + if (srv->phase == BLE_MESH_DFD_PHASE_COMPLETED || + srv->phase == BLE_MESH_DFD_PHASE_FAILED) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + } + return BLE_MESH_DFD_SUCCESS; + } + + /* Phase TRANSFER_ACTIVE, TRANSFER_SUSPENDED, TRANSFER_SUCCESS, APPLYING_UPDATE: */ + + prev_phase = srv->phase; + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_CANCELING_UPDATE); + err = bt_mesh_dfu_cli_cancel(&srv->dfu, NULL); + if (err) { + if (ctx != NULL) { + status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); + } + return BLE_MESH_DFD_ERR_INTERNAL; + } + + if (prev_phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { + /* Disable randomization for the Firmware Distribution State message to avoid + * reordering when Firmware Distribution Server sends 2 messages in a row when + * cancelling the update (see section 6.2.3.10 of MshDFUv1.0). + */ + /* + * Changed by Espressif: Access Message random delay is not currently supported in IDF. + */ + // ctx->rnd_delay = false; + } + + if (ctx != NULL) { + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + } + + if (prev_phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); + } + } + + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv) +{ + int err; + + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE || + srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED || + srv->phase == BLE_MESH_DFD_PHASE_FAILED) { + return BLE_MESH_DFD_ERR_WRONG_PHASE; + } + + if (srv->phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_COMPLETED) { + return BLE_MESH_DFD_SUCCESS; + } + + err = bt_mesh_dfu_cli_apply(&srv->dfu); + if (err) { + return BLE_MESH_DFD_ERR_INTERNAL; + } + + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_APPLYING_UPDATE); + return BLE_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, + const uint8_t **fwid) +{ + struct bt_mesh_dfu_slot *slot; + int idx, err; + + if (srv->phase != BLE_MESH_DFD_PHASE_IDLE) { + *fwid = NULL; + *fwid_len = 0; + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + idx = bt_mesh_dfu_slot_get(*fwid, *fwid_len, &slot); + if (idx < 0) { + return BLE_MESH_DFD_SUCCESS; + } + + err = slot_del(srv, slot); + if (err) { + *fwid = NULL; + *fwid_len = 0; + return BLE_MESH_DFD_ERR_INTERNAL; + } else { + return BLE_MESH_DFD_SUCCESS; + } +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv) +{ + if (srv->phase != BLE_MESH_DFD_PHASE_IDLE) { + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + + bt_mesh_dfu_slot_del_all(); + + return BLE_MESH_DFD_SUCCESS; +} + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len) +{ + int err; + + if (slot != srv->upload.slot || !srv->upload.is_oob || + srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + !srv->upload.is_pending_oob_check) { + /* This should not happen, unless the application calls the function with a + * "wrong" pointer or at a wrong time. + */ + return -EINVAL; + } + + srv->upload.is_pending_oob_check = false; + + if (status != BLE_MESH_DFD_SUCCESS) { + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, &srv->upload.oob.ctx, status); + return -ECANCELED; + } + + err = set_upload_fwid(srv, &srv->upload.oob.ctx, fwid, fwid_len); + + if (err) { + return err; + } + + upload_status_rsp(srv, &srv->upload.oob.ctx, BLE_MESH_DFD_SUCCESS); + return 0; +} + +int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len) +{ + int err = 0; + + if (srv->upload.phase != BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + srv->upload.slot != slot || !srv->upload.is_oob) { + return -EINVAL; + } + + if (!success) { + goto error; + } + + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, metadata, metadata_len); + if (err) { + goto error; + } + + err = bt_mesh_dfu_slot_commit(srv->upload.slot); + if (err) { + goto error; + } + + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return 0; + +error: + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + bt_mesh_dfu_slot_release(srv->upload.slot); + return err; +} +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h new file mode 100644 index 000000000000..403b8b3d17f6 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ +#define _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ + +#include "mesh_v1.1/dfu/dfd_srv.h" + +#if CONFIG_BLE_MESH_DFD_SRV +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfd_start_params { + uint16_t app_idx, timeout_base, slot_idx, group; + enum bt_mesh_blob_xfer_mode xfer_mode; + uint8_t ttl; + bool apply; +}; + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, + uint8_t img_idx); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_dfd_start_params *params); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, + const uint8_t **fwid); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv); + +#ifdef __cplusplus +} +#endif +#endif +#endif /* _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h new file mode 100644 index 000000000000..17a20598031f --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "mesh/buf.h" + +#if CONFIG_BLE_MESH_DFU_SRV || CONFIG_BLE_MESH_DFU_CLI +#define BLE_MESH_DFU_OP_UPDATE_INFO_GET BLE_MESH_MODEL_OP_2(0x83, 0x08) +#define BLE_MESH_DFU_OP_UPDATE_INFO_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x09) + +#define BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK BLE_MESH_MODEL_OP_2(0x83, 0x0a) +#define BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x0b) + +#define BLE_MESH_DFU_OP_UPDATE_GET BLE_MESH_MODEL_OP_2(0x83, 0x0c) +#define BLE_MESH_DFU_OP_UPDATE_START BLE_MESH_MODEL_OP_2(0x83, 0x0d) +#define BLE_MESH_DFU_OP_UPDATE_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x0e) +#define BLE_MESH_DFU_OP_UPDATE_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x0f) +#define BLE_MESH_DFU_OP_UPDATE_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x10) + +#define DFU_UPDATE_INFO_STATUS_MSG_MINLEN (4 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BLE_MESH_DFU_URI_MAXLEN) +#define DFU_UPDATE_START_MSG_MAXLEN (12 + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) + +static inline uint16_t dfu_metadata_checksum(struct net_buf_simple *buf) +{ + /* Simple Fletcher-16 checksum to ensure duplicate start messages don't + * have different metadata. + */ + struct net_buf_simple_state state; + uint8_t sum[2] = {0, 0}; + + net_buf_simple_save(buf, &state); + + while (buf->len) { + uint8_t byte = net_buf_simple_pull_u8(buf); + + sum[0] += byte; + sum[1] += sum[0]; + } + + net_buf_simple_restore(buf, &state); + + return (sum[0] << 8U) | sum[1]; +} +#endif /* CONFIG_BLE_MESH_DFU_SRV || CONFIG_BLE_MESH_DFU_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c new file mode 100644 index 000000000000..e5ff20c328af --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c @@ -0,0 +1,1513 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "access.h" +#include "dfu.h" +#include "btc_ble_mesh_dfu_model.h" +#include "blob.h" +#include "mesh/slist.h" +#include "mesh/mutex.h" +#include "mesh_v1.1/dfu/dfu.h" +#include "mesh_v1.1/dfu/dfu_cli.h" + +#if CONFIG_BLE_MESH_DFU_CLI +#define TARGETS_FOR_EACH(cli, target) \ + SYS_SLIST_FOR_EACH_CONTAINER( \ + (sys_slist_t *)&((cli)->blob.inputs)->targets, target, blob.n) + +#define MSG_CTX(cli, dst) \ + { \ + .app_idx = (cli)->blob.inputs->app_idx, .addr = dst, \ + .send_ttl = (cli)->blob.inputs->ttl, \ + } + +#define DFU_CLI(blob_cli) CONTAINER_OF(blob_cli, struct bt_mesh_dfu_cli, blob) + +_Static_assert((DFU_UPDATE_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum outgoing SDU size."); + +_Static_assert((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_INFO_STATUS) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_RX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum incoming SDU " + "size."); + +enum req { + REQ_NONE, + REQ_METADATA, + REQ_IMG, + REQ_STATUS, + INTERNAL_REQ_IMG, +}; + +enum { + FLAG_FAILED = BIT(0), + FLAG_CANCELLED = BIT(1), + FLAG_SKIP_CAPS_GET = BIT(2), + FLAG_RESUME = BIT(3), + FLAG_COMPLETED = BIT(4), +}; + +static void bt_mesh_dfu_cli_rm_req_from_list(bt_mesh_dfu_cli_req_t *req); +static int req_free(bt_mesh_dfu_cli_req_t *req); + +static int32_t dfu_cli_timeout = (10 * MSEC_PER_SEC); + +static struct { + bt_mesh_mutex_t op_lock; + sys_slist_t list; +} dfu_req_list; + +static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfu_cli *cli, + uint16_t addr) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (addr == target->blob.addr) { + return target; + } + } + + return NULL; +} + +static void req_timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_dfu_cli_req_t *req = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + + BT_WARN("Receive dfu status message timeout"); + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + req = CONTAINER_OF(work, bt_mesh_dfu_cli_req_t, timer.work); + memcpy(&ctx, &req->ctx, sizeof(struct bt_mesh_msg_ctx)); + if (req->type == REQ_NONE) { + assert(0); + } + if (req == NULL) { + assert(0); + } + + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT, + req->dfu_cli->mod, &ctx, NULL, 0); + } + + bt_mesh_dfu_cli_rm_req_from_list(req); + if (req->params) { + bt_mesh_free(req->params); + } + req_free(req); + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); +} + +static bt_mesh_dfu_cli_req_t* req_alloc(void) +{ + bt_mesh_dfu_cli_req_t *req = bt_mesh_calloc(sizeof(bt_mesh_dfu_cli_req_t)); + if (!req) { + BT_ERR("device firmware client allocl failed"); + return NULL; + } + + req->ctx.addr = BLE_MESH_ADDR_UNASSIGNED; + req->type = REQ_NONE; + k_delayed_work_init(&req->timer, req_timeout_handler); + return req; +} + +static int req_free(bt_mesh_dfu_cli_req_t *req) +{ + if (req->node.next) { + BT_ERR("req still in list"); + return -EINVAL; + } + + k_delayed_work_free(&req->timer); + bt_mesh_free(req); + return 0; +} + +static int is_valid_req(bt_mesh_dfu_cli_req_t *req) +{ + if (!req || + req->ctx.addr == BLE_MESH_ADDR_UNASSIGNED) { + return false; + } + + return true; +} + +static void bt_mesh_dfu_cli_req_list_init(void) +{ + sys_slist_init(&dfu_req_list.list); + bt_mesh_r_mutex_create(&dfu_req_list.op_lock); +} + +static void bt_mesh_dfu_cli_add_req_to_list(bt_mesh_dfu_cli_req_t *req) +{ + if (!is_valid_req(req)) { + return; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + sys_slist_append(&dfu_req_list.list, &req->node); + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); +} + +static void bt_mesh_dfu_cli_rm_req_from_list(bt_mesh_dfu_cli_req_t *req) +{ + if (!is_valid_req(req)) { + return; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + sys_slist_find_and_remove(&dfu_req_list.list, &req->node); + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + + k_delayed_work_cancel(&req->timer); +} + +static bt_mesh_dfu_cli_req_t* bt_mesh_dfu_req_find_by_addr(uint16_t addr) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + sys_snode_t *peek = NULL; + + if (addr == BLE_MESH_ADDR_UNASSIGNED) { + return NULL; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + SYS_SLIST_FOR_EACH_NODE(&dfu_req_list.list, peek) { + req = (bt_mesh_dfu_cli_req_t*)peek; + if (req->ctx.addr == addr) { + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return req; + } + } + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return NULL; +} + +static void bt_mesh_dfu_req_list_free(void) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + sys_snode_t *peek = NULL; + sys_snode_t *nxt = NULL; + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + SYS_SLIST_FOR_EACH_NODE_SAFE(&dfu_req_list.list, peek, nxt) { + req = (bt_mesh_dfu_cli_req_t*)peek; + if (req->params) { + bt_mesh_free(req->params); + } + bt_mesh_dfu_cli_rm_req_from_list(req); + k_delayed_work_cancel(&req->timer); + req_free(req); + } + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return; +} + +static void target_failed(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_dfu_target *target, + enum bt_mesh_dfu_status status) +{ + target->status = status; + + BT_ERR("Target 0x%04x failed: %u", target->blob.addr, status); + + /* Invalidate blob status to prevent the target from being included in + * future sending: + */ + if (target->blob.status == BT_MESH_BLOB_SUCCESS) { + target->blob.status = BT_MESH_BLOB_ERR_INTERNAL; + } + + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target); + } +} + +static void dfu_complete(struct bt_mesh_dfu_cli *cli) +{ + BT_DBG(""); + + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, BLE_MESH_DFU_SUCCESS); + } +} + +static void dfu_applied(struct bt_mesh_dfu_cli *cli) +{ + BT_DBG(""); + + cli->xfer.state = STATE_APPLIED; + + if (cli->cb && cli->cb->applied) { + cli->cb->applied(cli); + } +} + +static void dfu_failed(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason) +{ + BT_DBG("%u", reason); + + cli->xfer.flags |= FLAG_FAILED; + + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, reason); + } +} + +static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type, + uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + void *params) +{ + if (!cli->req || + cli->req->type != REQ_NONE) { + return -EBUSY; + } + + cli->req->params = params; + cli->req->type = type; + cli->req->dfu_cli = cli; + cli->req->opcode = opcode; + + if (ctx) { + memcpy(&cli->req->ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + } + + return 0; +} + +static int req_wait(struct bt_mesh_dfu_cli *cli, k_timeout_t timeout) +{ + int err = ESP_OK; + bt_mesh_dfu_cli_req_t *req = cli->req; + + req->timeout = timeout; + k_delayed_work_submit(&req->timer, timeout); + bt_mesh_dfu_cli_add_req_to_list(req); + return err; +} + +static bool targets_active(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BLE_MESH_DFU_SUCCESS) { + return true; + } + } + + return false; +} + +/******************************************************************************* + * Blob client + ******************************************************************************/ +static void refresh(struct bt_mesh_dfu_cli *cli); + +static void blob_caps(struct bt_mesh_blob_cli *b, + const struct bt_mesh_blob_cli_caps *caps) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; + + if (!caps) { + dfu_failed(cli, BLE_MESH_DFU_ERR_RESOURCES); + return; + } + + cli->xfer.blob.block_size_log = caps->max_block_size_log; + cli->xfer.blob.chunk_size = caps->max_chunk_size; + + /* If mode is not already set and server reported it supports all modes + * default to PUSH, otherwise set value reported by server. If mode + * was set and server supports all modes, keep old value; set + * reported value otherwise. + */ + if (!(cli->xfer.blob.mode & BT_MESH_BLOB_XFER_MODE_ALL)) { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + BT_MESH_BLOB_XFER_MODE_PUSH : caps->modes; + } else { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + cli->xfer.blob.mode : caps->modes; + } + + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + BT_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } +} + +static void blob_lost_target(struct bt_mesh_blob_cli *b, + struct bt_mesh_blob_target *blobt, + enum bt_mesh_blob_status reason) +{ + struct bt_mesh_dfu_target *target = + CONTAINER_OF(blobt, struct bt_mesh_dfu_target, blob); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if ((cli->xfer.state == STATE_CONFIRM || cli->xfer.state == STATE_APPLY) && + target->effect == BLE_MESH_DFU_EFFECT_UNPROV) { + /* Reset status for such targets to use them in consequent procedures. See sections + * 7.1.2.6 and 7.1.2.9 of the MeshDFU. + */ + target->blob.status = BT_MESH_BLOB_SUCCESS; + return; + } + + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); +} + +static void blob_suspended(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + BT_DBG("BLOB transfer suspended"); + + cli->xfer.state = STATE_SUSPENDED; + + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } +} + +static void blob_end(struct bt_mesh_blob_cli *b, + const struct bt_mesh_blob_xfer *xfer, bool success) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + bt_mesh_dfu_cli_req_t *req = NULL; + + if (b->tx.target) { + req = bt_mesh_dfu_req_find_by_addr(b->tx.target->addr); + if (req) { + req->img_cb = NULL; + } + } + + if (success) { + refresh(cli); + return; + } + + if (cli->xfer.state == STATE_CANCEL) { + /* The user cancelled the transfer, DFU will end when all + * targets have been notified. + */ + return; + } + + if (cli->xfer.state != STATE_TRANSFER) { + BT_ERR("Blob failed in invalid state %u", cli->xfer.state); + return; + } + + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); +} + +const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers = { + .caps = blob_caps, + .lost_target = blob_lost_target, + .suspended = blob_suspended, + .end = blob_end, +}; + +/******************************************************************************* + * Message sending + ******************************************************************************/ + +static void tx_start(uint16_t dur, int err, void *cb_data); +static void tx_end(int err, void *cb_data); + +static const struct bt_mesh_send_cb send_cb = { + .start = tx_start, + .end = tx_end, +}; + +static void tx_start(uint16_t dur, int err, void *cb_data) +{ + if (err) { + tx_end(err, cb_data); + } +} + +static void tx_end(int err, void *cb_data) +{ + struct bt_mesh_dfu_cli *cli = cb_data; + + blob_cli_broadcast_tx_complete(&cli->blob); +} + +static int tx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, const struct bt_mesh_send_cb *cb, + struct bt_mesh_dfu_cli *cli) +{ + int err; + + err = bt_mesh_model_send(mod, ctx, buf, cb, cli); + if (err) { + BT_ERR("Send err: %d", err); + if (cb) { + cb->end(err, cli); + } + return err; + } + + return 0; +} + +static int info_get(struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t max_count, + const struct bt_mesh_send_cb *cb) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_INFO_GET, 2); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_INFO_GET); + net_buf_simple_add_u8(&buf, idx); + net_buf_simple_add_u8(&buf, max_count); + + return tx(cli->mod, ctx, &buf, cb, cli); +} + +static void send_info_get(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + cli->req->img_cnt = 0xff; + + info_get(cli, &ctx, 0, cli->req->img_cnt, &send_cb); +} + +static void send_update_start(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_target *target; + + if (b->tx.ctx.force_unicast) { + target = target_get(cli, dst); + } else { + target = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *) & ((cli)->blob.inputs)->targets, + target, blob.n); + } + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_START, + DFU_UPDATE_START_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_START); + + net_buf_simple_add_u8(&buf, cli->blob.inputs->ttl); + net_buf_simple_add_le16(&buf, cli->blob.inputs->timeout_base); + net_buf_simple_add_le64(&buf, cli->xfer.blob.id); + net_buf_simple_add_u8(&buf, target->img_idx); + net_buf_simple_add_mem(&buf, cli->xfer.slot->metadata, + cli->xfer.slot->metadata_len); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_get(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_GET); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_cancel(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_CANCEL); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_apply(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_APPLY, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_APPLY); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +/******************************************************************************* + * Distribution procedure + ******************************************************************************/ +static void transfer(struct bt_mesh_blob_cli *b); +static void apply(struct bt_mesh_dfu_cli *cli); +static void applied(struct bt_mesh_blob_cli *b); +static void confirmed(struct bt_mesh_blob_cli *b); +static void cancelled(struct bt_mesh_blob_cli *b); + +static void initiate(struct bt_mesh_dfu_cli *cli) +{ + struct blob_cli_broadcast_ctx tx = { + .send = send_update_start, + .next = transfer, + .acked = true, + }; + struct bt_mesh_dfu_target *target; + int img_idx = -1; + + /** If firmware img index is the same for all targets, we can send Firmware Update Start + * message using multicast address. Otherwise, it has to be send in a unicast way. + */ + TARGETS_FOR_EACH(cli, target) { + if (img_idx == -1) { + img_idx = target->img_idx; + } else if (target->img_idx != img_idx) { + tx.force_unicast = true; + break; + } + } + + BT_DBG(""); + + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; + cli->xfer.state = STATE_TRANSFER; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void skip_targets_from_broadcast(struct bt_mesh_dfu_cli *cli, bool skip) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + /* If distributor is in the targets list, or target is in Verify phase, + * disable it until Retrieve Capabilities and BLOB Transfer procedures + * are completed. + */ + if (bt_mesh_has_addr(target->blob.addr) || + target->phase == BLE_MESH_DFU_PHASE_VERIFY) { + target->blob.skip = skip; + break; + } + } +} + +static bool transfer_skip(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (!bt_mesh_has_addr(target->blob.addr) || !target->blob.skip) { + return false; + } + } + + return true; +} + +static void transfer(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; + + BT_DBG(""); + + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } + + skip_targets_from_broadcast(cli, true); + + if (transfer_skip(cli)) { + /* If distributor only updates itself, or all targets are in Verify phase, + * proceed to the refresh step immediately. + */ + refresh(cli); + return; + } + + if (cli->xfer.flags & FLAG_RESUME) { + cli->xfer.flags ^= FLAG_RESUME; + err = bt_mesh_blob_cli_resume(b); + if (err) { + BT_ERR("Resuming BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else if (cli->xfer.flags & FLAG_SKIP_CAPS_GET) { + cli->xfer.flags ^= FLAG_SKIP_CAPS_GET; + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + BT_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else { + err = bt_mesh_blob_cli_caps_get(&cli->blob, cli->blob.inputs); + if (err) { + BT_ERR("Failed starting blob xfer: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } +} + +static void refreshed(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } + + cli->xfer.state = STATE_VERIFIED; + dfu_complete(cli); +} + +static void refresh(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_get, + .next = refreshed, + .acked = true + }; + + BT_DBG(""); + + cli->xfer.state = STATE_REFRESH; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; + + /* If distributor is in the targets list, enable it again so it participates in Distribute + * Firmware procedure. + */ + skip_targets_from_broadcast(cli, false); + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void apply(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_apply, + .next = applied, + .acked = true + }; + + BT_DBG(""); + + cli->xfer.state = STATE_APPLY; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void applied(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } + + dfu_applied(cli); +} + +static enum bt_mesh_dfu_iter target_img_cb(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t cnt, + const struct bt_mesh_dfu_img *img, + void *cb_data) +{ + struct bt_mesh_dfu_target *target; + + if ((img->fwid_len != cli->xfer.slot->fwid_len) || + memcmp(cli->xfer.slot->fwid, img->fwid, img->fwid_len)) { + return BLE_MESH_DFU_ITER_CONTINUE; + } + + target = target_get(cli, ctx->addr); + if (target) { + BT_DBG("SUCCESS: 0x%04x applied dfu (as image %u)", ctx->addr, + idx); + target->phase = BLE_MESH_DFU_PHASE_APPLY_SUCCESS; + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } else { + BT_WARN("Target 0x%04x not found", ctx->addr); + } + + return BLE_MESH_DFU_ITER_STOP; +} + +static void confirm(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_info_get, + .next = confirmed, + .acked = true, + .optional = true, + }; + + BT_DBG(""); + + cli->op = BLE_MESH_DFU_OP_UPDATE_INFO_STATUS; + cli->req->img_cb = target_img_cb; + cli->req->ttl = cli->blob.inputs->ttl; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void confirmed(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_target *target; + bool success = false; + + cli->req->img_cb = NULL; + + TARGETS_FOR_EACH(cli, target) { + if (target->status != BLE_MESH_DFU_SUCCESS) { + /* Target either failed at earlier stage or during confirmation. In any + * case, the app is already notified. Don't consider the target here. + */ + continue; + } + + if (target->effect == BLE_MESH_DFU_EFFECT_UNPROV) { + if (!target->blob.acked) { + success = true; + continue; + } + + BT_DBG("Target 0x%04x still provisioned", target->blob.addr); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + } else if (!target->blob.acked) { + BT_DBG("Target 0x%04x failed to respond", target->blob.addr); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + } else if (target->status == BLE_MESH_DFU_SUCCESS) { + success = true; + } + } + + if (success) { + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = FLAG_COMPLETED; + + if (cli->cb && cli->cb->confirmed) { + cli->cb->confirmed(cli); + } + } else { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + } +} + +static void cancel(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_cancel, + .next = cancelled, + .acked = true + }; + + BT_DBG(""); + + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void cancelled(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + cli->xfer.flags |= FLAG_CANCELLED; + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); +} + +/******************************************************************************* + * Message handlers + ******************************************************************************/ + +static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_cli *cli = mod->user_data; + bt_mesh_dfu_cli_req_t *req = NULL; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_phase phase; + struct bt_mesh_dfu_target *target; + uint8_t byte; + + byte = net_buf_simple_pull_u8(buf); + status = byte & BIT_MASK(3); + phase = byte >> 5; + + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); + + // The req will be NULL if the target is a group address. + if (req && req->type == REQ_STATUS) { + if (req->params) { + struct bt_mesh_dfu_target_status *rsp = req->params; + + rsp->status = status; + rsp->phase = phase; + if (buf->len == 13) { + rsp->ttl = net_buf_simple_pull_u8(buf); + rsp->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + rsp->timeout_base = net_buf_simple_pull_le16(buf); + rsp->blob_id = net_buf_simple_pull_le64(buf); + rsp->img_idx = net_buf_simple_pull_u8(buf); + } else if (buf->len) { + return -EINVAL; + } + + rsp->ttl = 0U; + rsp->effect = BLE_MESH_DFU_EFFECT_NONE; + rsp->timeout_base = 0U; + rsp->blob_id = 0U; + rsp->img_idx = 0U; + } + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + req->dfu_cli->mod, &req->ctx, req->params, + sizeof(struct bt_mesh_dfu_target_status)); + bt_mesh_free(req->params); + bt_mesh_dfu_cli_rm_req_from_list(req); + k_delayed_work_cancel(&req->timer); + req_free(req); + } + + if (cli->op != BLE_MESH_DFU_OP_UPDATE_STATUS) { + return 0; + } + + target = target_get(cli, ctx->addr); + if (!target) { + BT_WARN("Unknown target 0x%04x", ctx->addr); + return -ENOENT; + } + + BT_DBG("%u phase: %u, cur state: %u", status, phase, cli->xfer.state); + + target->phase = phase; + + if (cli->xfer.state == STATE_APPLY && phase == BLE_MESH_DFU_PHASE_IDLE && + status == BLE_MESH_DFU_ERR_WRONG_PHASE) { + BT_DBG("Response received with Idle phase"); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + if (status != BLE_MESH_DFU_SUCCESS) { + target_failed(cli, target, status); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + if (buf->len == 13) { + net_buf_simple_pull_u8(buf); /* ttl */ + target->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + net_buf_simple_pull_le16(buf); /* timeout */ + + if (net_buf_simple_pull_le64(buf) != cli->xfer.blob.id) { + BT_WARN("Invalid BLOB ID"); + target_failed(cli, target, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + target->img_idx = net_buf_simple_pull_u8(buf); + + BT_DBG("Target 0x%04x receiving transfer", ctx->addr); + } else if (buf->len) { + return -EINVAL; + } + + if (cli->xfer.state == STATE_REFRESH) { + if (phase == BLE_MESH_DFU_PHASE_VERIFY) { + BT_DBG("Still pending..."); + return 0; + } else if (phase == BLE_MESH_DFU_PHASE_VERIFY_FAIL) { + BT_WARN("Verification failed on target 0x%04x", + target->blob.addr); + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + } + } else if (cli->xfer.state == STATE_APPLY) { + if (phase != BLE_MESH_DFU_PHASE_APPLYING && + (target->effect == BLE_MESH_DFU_EFFECT_UNPROV || + phase != BLE_MESH_DFU_PHASE_IDLE)) { + BT_WARN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + return 0; + } else if (cli->xfer.state == STATE_CONFIRM) { + if (phase == BLE_MESH_DFU_PHASE_APPLYING) { + BT_DBG("Still pending..."); + return 0; + } + + if (phase != BLE_MESH_DFU_PHASE_IDLE) { + BT_WARN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + } else if (cli->xfer.state == STATE_CANCEL) { + target->phase = BLE_MESH_DFU_PHASE_TRANSFER_CANCELED; + } + + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + + return 0; +} + +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_target *target; + bt_mesh_dfu_cli_req_t *req = NULL; + enum bt_mesh_dfu_iter it = BLE_MESH_DFU_ITER_CONTINUE; + uint8_t img_cnt, idx; + + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); + if (!req) { + return 0; + } + + if (req->type == INTERNAL_REQ_IMG) { + goto confirm_procedure; + } + + if (!req->img_cb || + req->type != REQ_IMG) { + BT_WARN("Unexpected info status from 0x%04x req %p type %d", ctx->addr, req, req->type); + return 0; + } + + img_cnt = net_buf_simple_pull_u8(buf); + if (img_cnt < req->img_cnt) { + req->img_cnt = img_cnt; + } + + idx = net_buf_simple_pull_u8(buf); + if (idx >= img_cnt) { + BT_WARN("Invalid idx %u", idx); + return -ENOENT; + } + + BT_DBG("Image list from 0x%04x from index %u", ctx->addr, idx); + + while (buf->len && req->img_cb && idx < req->img_cnt) { + char uri_buf[CONFIG_BLE_MESH_DFU_URI_MAXLEN + 1]; + struct bt_mesh_dfu_img img; + size_t uri_len; + + img.fwid_len = net_buf_simple_pull_u8(buf); + if (buf->len < img.fwid_len + 1) { + BT_WARN("Invalid format: fwid"); + return -EINVAL; + } + + img.fwid = net_buf_simple_pull_mem(buf, img.fwid_len); + + uri_len = net_buf_simple_pull_u8(buf); + if (buf->len < uri_len) { + BT_WARN("Invalid format: uri"); + return -EINVAL; + } + + BT_DBG("\tImage %u\n\r\tfwid: %s", idx, bt_hex(img.fwid, img.fwid_len)); + + if (uri_len) { + size_t uri_buf_len = + MIN(CONFIG_BLE_MESH_DFU_URI_MAXLEN, uri_len); + + memcpy(uri_buf, net_buf_simple_pull_mem(buf, uri_len), + uri_buf_len); + uri_buf[uri_buf_len] = '\0'; + img.uri = uri_buf; + } else { + img.uri = NULL; + } + + it = req->img_cb(cli, ctx, idx, img_cnt, &img, + req->params); + if (it != BLE_MESH_DFU_ITER_CONTINUE) { + if (req->type == REQ_IMG) { + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + } + + return 0; + } + + idx++; + } + + if (idx < req->img_cnt) { + BT_DBG("Fetching more images (%u/%u)", idx, req->img_cnt); + ctx->send_ttl = req->ttl; + info_get(cli, ctx, idx, req->img_cnt - idx, + (req->type == REQ_IMG) ? NULL : &send_cb); + return 0; + } else { + if (req->img_cb) { + // used to notify cb function the image output finished + req->img_cb(cli, ctx, idx, img_cnt, NULL, NULL); + } + } + + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + return 0; + +confirm_procedure: + /* Confirm-procedure termination: */ + target = target_get(cli, ctx->addr); + if (target) { + BT_WARN("Target 0x%04x failed to apply image: %s", ctx->addr, + bt_hex(cli->xfer.slot->fwid, cli->xfer.slot->fwid_len)); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } + + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + + return 0; +} + +static int handle_metadata_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + struct bt_mesh_dfu_metadata_status *rsp = NULL; + uint8_t hdr, idx; + + hdr = net_buf_simple_pull_u8(buf); + idx = net_buf_simple_pull_u8(buf); + + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); + if (!req) { + BT_WARN("Unexcept metadata status form 0x%04x", ctx->addr); + return 0; + } + + rsp = req->params; + + if (req->type != REQ_METADATA || + idx != rsp->idx) { + BT_WARN("Unexpected metadata status from 0x%04x img %u", + ctx->addr, idx); + if (req->type != REQ_METADATA) { + BT_WARN("Expected %u", req->type); + } else { + BT_WARN("Expected 0x%04x img %u", req->ctx.addr, idx); + } + + return 0; + } + + rsp->status = hdr & BIT_MASK(3); + rsp->effect = (hdr >> 3); + + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + req->dfu_cli->mod, &req->ctx, req->params, + sizeof(struct bt_mesh_dfu_metadata_status)); + + bt_mesh_free(rsp); + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[] = { + {BLE_MESH_DFU_OP_UPDATE_STATUS, 1, (void *)handle_status}, + {BLE_MESH_DFU_OP_UPDATE_INFO_STATUS, 2, (void *)handle_info_status}, + {BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2, (void *)handle_metadata_status}, + BLE_MESH_MODEL_OP_END, +}; + +static int dfu_cli_init(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_cli *cli = mod->user_data; + + if (mod->elem_idx != 0) { + BT_ERR("DFU update client must be instantiated on first elem"); + return -EINVAL; + } + + cli->mod = mod; + + cli->blob.cb = &_bt_mesh_dfu_cli_blob_handlers; + + bt_mesh_dfu_cli_req_list_init(); + + return 0; +} + +static void dfu_cli_reset(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_cli *cli = mod->user_data; + + bt_mesh_dfu_req_list_free(); + cli->req = NULL; + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = 0; +} + +static int dfu_cli_deinit(struct bt_mesh_model *mod) +{ + dfu_cli_reset(mod); + return 0; +} + +const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb = { + .init = dfu_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfu_cli_deinit, +#endif +}; + +/******************************************************************************* + * Public API + ******************************************************************************/ + +int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer) +{ + struct bt_mesh_dfu_target *target; + + if (bt_mesh_dfu_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->xfer.blob.mode = xfer->mode; + cli->xfer.blob.size = xfer->slot->size; + + if (xfer->blob_id == 0) { + bt_mesh_rand(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + } else { + cli->xfer.blob.id = xfer->blob_id; + } + + cli->xfer.io = io; + cli->blob.inputs = inputs; + cli->xfer.slot = xfer->slot; + cli->xfer.flags = 0U; + + if (xfer->blob_params) { + cli->xfer.flags |= FLAG_SKIP_CAPS_GET; + cli->xfer.blob.block_size_log = xfer->blob_params->block_size_log; + cli->xfer.blob.chunk_size = xfer->blob_params->chunk_size; + } + + /* Phase will be set based on target status messages: */ + TARGETS_FOR_EACH(cli, target) { + target->status = BLE_MESH_DFU_SUCCESS; + target->phase = BLE_MESH_DFU_PHASE_UNKNOWN; + } + + initiate(cli); + return 0; +} + +int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli) +{ + int err; + + err = bt_mesh_blob_cli_suspend(&cli->blob); + if (!err) { + cli->xfer.state = STATE_SUSPENDED; + } + + return err; +} + +int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + if (cli->xfer.state != STATE_SUSPENDED) { + return -EINVAL; + } + + cli->xfer.flags = FLAG_RESUME; + + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->blob.timedout) { + target->status = BLE_MESH_DFU_SUCCESS; + target->phase = BLE_MESH_DFU_PHASE_UNKNOWN; + } + } + + initiate(cli); + return 0; +} + +int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + if (ctx) { + int err; + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_STATUS, BLE_MESH_DFU_OP_UPDATE_CANCEL, ctx, NULL); + if (err) { + return err; + } + bt_mesh_dfu_cli_add_req_to_list(req); + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_CANCEL); + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); + } + + if (cli->xfer.state == STATE_IDLE) { + return -EALREADY; + } + + cli->xfer.state = STATE_CANCEL; + blob_cli_broadcast_abort(&cli->blob); + cancel(cli); + return 0; +} + +int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli) +{ + if (cli->xfer.state != STATE_VERIFIED) { + return -EBUSY; + } + + apply(cli); + + return 0; +} + +int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + + if (cli->xfer.state != STATE_APPLIED) { + return -EBUSY; + } + + req = req_alloc(); + if (!req) { + BT_ERR("%s: alloc req failed", req); + return -ENOMEM; + } + + cli->req = req; + req_setup(cli, INTERNAL_REQ_IMG, BLE_MESH_DFU_OP_UPDATE_INFO_GET, NULL, NULL); + bt_mesh_dfu_cli_add_req_to_list(req); + + cli->xfer.state = STATE_CONFIRM; + confirm(cli); + + return 0; +} + +uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli) +{ + if (cli->xfer.state == STATE_TRANSFER) { + return bt_mesh_blob_cli_xfer_progress_active_get(&cli->blob); + } + + if (cli->xfer.state == STATE_IDLE) { + if (cli->xfer.flags & FLAG_COMPLETED) { + return 100U; + } + return 0U; + } + + return 100U; +} + +bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli) +{ + return (cli->xfer.state == STATE_TRANSFER || + cli->xfer.state == STATE_REFRESH || + cli->xfer.state == STATE_APPLY || + cli->xfer.state == STATE_CONFIRM) && + !(cli->xfer.flags & FLAG_FAILED); +} + +int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t first_idx, uint8_t max_count) +{ + int err; + + if (bt_mesh_dfu_req_find_by_addr(ctx->addr)) { + BT_WARN("Exists waiting request"); + return -EBUSY; + } + + cli->req = req_alloc(); + if (!cli->req) { + return -ENOMEM; + } + + err = req_setup(cli, REQ_IMG, BLE_MESH_DFU_OP_UPDATE_INFO_GET, ctx, cb_data); + if (err) { + req_free(cli->req); + return err; + } + + cli->req->img_cb = cb; + cli->req->ttl = ctx->send_ttl; + cli->req->img_cnt = max_count; + + err = info_get(cli, ctx, first_idx, cli->req->img_cnt, NULL); + if (err) { + cli->req->img_cb = NULL; + cli->req->type = REQ_NONE; + req_free(cli->req); + return err; + } + + err = req_wait(cli, K_MSEC(dfu_cli_timeout)); + + return err; +} + +int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + struct net_buf_simple *metadata) +{ + int err; + bt_mesh_dfu_cli_req_t *req = NULL; + + struct bt_mesh_dfu_metadata_status *rsp = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_metadata_status)); + if (!rsp) { + BT_ERR("Alloc metadata status failed"); + return -ENOMEM; + } + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_METADATA, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, ctx, rsp); + if (err) { + return err; + } + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, + 1 + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK); + + net_buf_simple_add_u8(&buf, img_idx); + + if (metadata) { + net_buf_simple_add_mem(&buf, metadata->data, metadata->len); + } + + rsp->idx = img_idx; + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); +} + +int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx) +{ + int err; + bt_mesh_dfu_cli_req_t *req = NULL; + + struct bt_mesh_dfu_target_status *rsp = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_target_status)); + if (!rsp) { + BT_ERR("dfu target status alloc failed"); + return -ENOMEM; + } + + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_STATUS, BLE_MESH_DFU_OP_UPDATE_GET, ctx, rsp); + if (err) { + return err; + } + + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_GET); + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); +} + +int32_t bt_mesh_dfu_cli_timeout_get(void) +{ + return dfu_cli_timeout; +} + +void bt_mesh_dfu_cli_timeout_set(int32_t t) +{ + dfu_cli_timeout = t; +} +#endif /* CONFIG_BLE_MESH_DFU_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c new file mode 100644 index 000000000000..9c966c5e389e --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c @@ -0,0 +1,105 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "crypto.h" +#include "access.h" +#include "mesh/byteorder.h" +#include "mesh/buf.h" +#include "mesh_v1.1/dfu/dfu_metadata.h" + +#if CONFIG_BLE_MESH_DFU_METADATA +int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, + struct bt_mesh_dfu_metadata *metadata) +{ + if (buf->len < 12) { + return -EMSGSIZE; + } + + metadata->fw_ver.major = net_buf_simple_pull_u8(buf); + metadata->fw_ver.minor = net_buf_simple_pull_u8(buf); + metadata->fw_ver.revision = net_buf_simple_pull_le16(buf); + metadata->fw_ver.build_num = net_buf_simple_pull_le32(buf); + metadata->fw_size = net_buf_simple_pull_le24(buf); + metadata->fw_core_type = net_buf_simple_pull_u8(buf); + + if (metadata->fw_core_type & BLE_MESH_DFU_FW_CORE_TYPE_APP) { + if (buf->len < 6) { + return -EMSGSIZE; + } + + metadata->comp_hash = net_buf_simple_pull_le32(buf); + metadata->elems = net_buf_simple_pull_le16(buf); + } + + metadata->user_data = buf->len > 0 ? buf->data : NULL; + metadata->user_data_len = buf->len; + + return 0; +} + +int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, + struct net_buf_simple *buf) +{ + size_t md_len_min = 12 + metadata->user_data_len; + + if (metadata->fw_core_type & BLE_MESH_DFU_FW_CORE_TYPE_APP) { + md_len_min += 6; + } + + if (net_buf_simple_tailroom(buf) < md_len_min) { + return -EMSGSIZE; + } + + net_buf_simple_add_u8(buf, metadata->fw_ver.major); + net_buf_simple_add_u8(buf, metadata->fw_ver.minor); + net_buf_simple_add_le16(buf, metadata->fw_ver.revision); + net_buf_simple_add_le32(buf, metadata->fw_ver.build_num); + net_buf_simple_add_le24(buf, metadata->fw_size); + net_buf_simple_add_u8(buf, metadata->fw_core_type); + net_buf_simple_add_le32(buf, metadata->comp_hash); + net_buf_simple_add_le16(buf, metadata->elems); + + if (metadata->user_data_len > 0) { + net_buf_simple_add_mem(buf, metadata->user_data, metadata->user_data_len); + } + + return 0; +} + +int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, uint32_t *hash) +{ + uint8_t mac[16]; + int err; + struct bt_mesh_sg sg = {.data = buf->data, .len = buf->len}; + + /* The implementation of this function is the same as function `bt_mesh_aes_cmac_raw_key` in Zephyr. */ + err = bt_mesh_aes_cmac(key, &sg, 1, mac); + if (err) { + return err; + } + + *hash = sys_get_le32(mac); + + return 0; +} + +int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash) +{ + NET_BUF_SIMPLE_DEFINE(buf, BLE_MESH_TX_SDU_MAX); + int err; + + err = bt_mesh_get_comp_data(&buf, 0, 0, true); + if (err) { + return err; + } + + err = bt_mesh_dfu_metadata_comp_hash_get(&buf, key, hash); + return err; +} +#endif /* CONFIG_BLE_MESH_DFU_METADATA */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c new file mode 100644 index 000000000000..76f3a87e8182 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c @@ -0,0 +1,444 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "dfu_slot.h" +#include +#include +#include + +#include "mesh/common.h" +#include "mesh/utils.h" +#include "settings_nvs.h" +#include "settings.h" + +#if CONFIG_BLE_MESH_DFU_SLOTS +#define SLOT_ENTRY_BUFLEN 25 + +#define DFU_SLOT_SETTINGS_PATH "mesh/dfu/s" + +#define HEADER_SIZE offsetof(struct slot, slot.fwid) + +#define PROP_HEADER "h" +#define PROP_FWID "id" +#define PROP_METADATA "m" +#define SETTINGS_NAME_END '=' +#define SETTINGS_NAME_SEPARATOR '/' + +static sys_slist_t list; + +static struct slot { + uint32_t idx; + struct bt_mesh_dfu_slot slot; + sys_snode_t n; +} slots[CONFIG_BLE_MESH_DFU_SLOT_CNT]; + +static uint32_t slot_index; + +inline int settings_name_next(const char *name, const char **next) +{ + int rc = 0; + + if (next) { + *next = NULL; + } + + if (!name) { + return 0; + } + + /* name might come from flash directly, in flash the name would end + * with '=' or '\0' depending how storage is done. Flash reading is + * limited to what can be read + */ + while ((*name != '\0') && (*name != SETTINGS_NAME_END) && + (*name != SETTINGS_NAME_SEPARATOR)) { + rc++; + name++; + } + + if (*name == SETTINGS_NAME_SEPARATOR) { + if (next) { + *next = name + 1; + } + return rc; + } + + return rc; +} + +#if CONFIG_BLE_MESH_SETTINGS +static char *slot_entry_encode(uint16_t idx, char buf[SLOT_ENTRY_BUFLEN], + const char *property) +{ + snprintf(buf, SLOT_ENTRY_BUFLEN, DFU_SLOT_SETTINGS_PATH "/%x/%s", idx, + property); + + return buf; +} +#endif + +static bool slot_eq(const struct bt_mesh_dfu_slot *slot, + const uint8_t *fwid, size_t fwid_len) +{ + return (slot->fwid_len == fwid_len) && + !memcmp(fwid, slot->fwid, fwid_len); +} + +static bool is_slot_committed(struct slot *slot_to_check) +{ + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s == slot_to_check) { + return true; + } + } + + return false; +} + +static int slot_store(const struct slot *slot_to_store) +{ + int err = 0; +#if CONFIG_BLE_MESH_SETTINGS + uint16_t idx = ARRAY_INDEX(slots, slot_to_store); + char buf[SLOT_ENTRY_BUFLEN]; + + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_HEADER), + (uint8_t *)slot_to_store, HEADER_SIZE); + if (err) { + return err; + } + + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_FWID), + slot_to_store->slot.fwid, slot_to_store->slot.fwid_len); + if (err) { + return err; + } + + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_METADATA), + slot_to_store->slot.metadata, slot_to_store->slot.metadata_len); + +#endif + return err; +} + +static void slot_erase(struct slot *slot_to_erase) +{ +#if CONFIG_BLE_MESH_SETTINGS + uint16_t idx = ARRAY_INDEX(slots, slot_to_erase); + char buf[SLOT_ENTRY_BUFLEN]; + + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_HEADER)); + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_FWID)); + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_METADATA)); +#endif +} + +static void slot_index_defrag(void) +{ + slot_index = 0; + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + s->idx = ++slot_index; + slot_store(s); + } +} + +int bt_mesh_dfu_slot_count(void) +{ + int cnt = 0; + sys_snode_t *n; + + SYS_SLIST_FOR_EACH_NODE(&list, n) { + cnt++; + } + + return cnt; +} + +struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void) +{ + struct slot *slot = NULL; + + for (int i = 0; i < ARRAY_SIZE(slots); ++i) { + if (slots[i].idx == 0) { + slot = &slots[i]; + break; + } + } + + if (!slot) { + BT_WARN("No space"); + return NULL; + } + + if (slot_index == UINT32_MAX) { + slot_index_defrag(); + } + + slot->slot.fwid_len = 0; + slot->slot.metadata_len = 0; + slot->slot.size = 0; + slot->idx = ++slot_index; + + BT_DBG("Reserved slot #%u", slot - &slots[0]); + + return &slot->slot; +} + +int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (metadata_len > CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) { + return -EFBIG; + } + + if (slot->idx == 0 || is_slot_committed(slot)) { + return -EINVAL; + } + + slot->slot.size = size; + slot->slot.metadata_len = metadata_len; + memcpy(slot->slot.metadata, metadata, metadata_len); + return 0; +} + +int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + return -EFBIG; + } + + if (slot->idx == 0) { + return -EINVAL; + } + + if (is_slot_committed(slot)) { + return -EEXIST; + } + + for (int i = 0; i < ARRAY_SIZE(slots); i++) { + if (slots[i].idx != 0 && + slot_eq(&slots[i].slot, fwid, fwid_len)) { + return -EALREADY; + } + } + + slot->slot.fwid_len = fwid_len; + memcpy(slot->slot.fwid, fwid, fwid_len); + return 0; +} + +int bt_mesh_dfu_slot_commit(struct bt_mesh_dfu_slot *dfu_slot) +{ + int err; + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (slot->idx == 0 || + slot->slot.fwid_len == 0 || + slot->slot.size == 0 || + is_slot_committed(slot)) { + return -EINVAL; + } + + err = slot_store(slot); + if (err) { + BT_WARN("Store failed (err: %d)", err); + return err; + } + + sys_slist_append(&list, &slot->n); + + BT_DBG("Stored slot #%u: %s", ARRAY_INDEX(slots, slot), + bt_hex(slot->slot.fwid, slot->slot.fwid_len)); + return 0; +} + +void bt_mesh_dfu_slot_release(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (is_slot_committed(slot)) { + return; + } + + slot->idx = 0; +} + +int bt_mesh_dfu_slot_del(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (!sys_slist_find_and_remove(&list, &slot->n)) { + return -EINVAL; + } + + int idx = ARRAY_INDEX(slots, slot); + + BT_DBG("%u", idx); + + slot_erase(slot); + slot->idx = 0; + + return 0; +} + +void bt_mesh_dfu_slot_del_all(void) +{ + struct slot *s; + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + slot_erase(s); + s->idx = 0; + } + + sys_slist_init(&list); +} + +const struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_at(uint16_t img_idx) +{ + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (!img_idx--) { + return &s->slot; + } + } + + return NULL; +} + +int bt_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct bt_mesh_dfu_slot **slot) +{ + struct slot *s; + int idx = 0; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (slot_eq(&s->slot, fwid, fwid_len)) { + if (slot) { + *slot = &s->slot; + } + return idx; + } + idx++; + } + + return -ENOENT; +} + +int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *s; + int idx = 0; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (&s->slot == dfu_slot) { + return idx; + } + idx++; + } + + return -ENOENT; +} + +size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data) +{ + enum bt_mesh_dfu_iter iter; + size_t cnt = 0; + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + cnt++; + + if (!cb) { + continue; + } + + iter = cb(&s->slot, user_data); + if (iter != BLE_MESH_DFU_ITER_CONTINUE) { + break; + } + } + + return cnt; +} + +#if 0 +static int slot_data_load(const char *key, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + const char *prop; + size_t len; + uint16_t idx; + + idx = strtol(key, NULL, 16); + + if (idx >= ARRAY_SIZE(slots)) { + return 0; + } + + len = settings_name_next(key, &prop); + + if (!strncmp(prop, PROP_HEADER, len)) { + if (read_cb(cb_arg, &slots[idx], HEADER_SIZE) > 0) { + struct slot *s, *prev = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s->idx > slots[idx].idx) { + break; + } + + prev = s; + } + + if (prev == NULL) { + sys_slist_prepend(&list, &slots[idx].n); + } else { + sys_slist_insert(&list, &prev->n, &slots[idx].n); + } + + if (slots[idx].idx >= slot_index) { + slot_index = slots[idx].idx + 1; + } + } + return 0; + } + + if (!strncmp(prop, PROP_FWID, len)) { + if (read_cb(cb_arg, &slots[idx].slot.fwid, + sizeof(slots[idx].slot.fwid)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } + + slots[idx].slot.fwid_len = len_rd; + return 0; + } + + if (!strncmp(prop, PROP_METADATA, len)) { + if (read_cb(cb_arg, &slots[idx].slot.metadata, + sizeof(slots[idx].slot.metadata)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } + + slots[idx].slot.metadata_len = len_rd; + return 0; + } + + return 0; +} +#endif +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h new file mode 100644 index 000000000000..7509ad24a633 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h @@ -0,0 +1,137 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh_v1.1/dfu/dfu.h" +#if CONFIG_BLE_MESH_DFU_SLOTS +/** @brief Slot iteration callback. + * + * @param slot A valid DFU image slot. + * @param user_data User data passed to @ref bt_mesh_dfu_slot_foreach. + * + * @return Iteration action determining next step. + */ +typedef enum bt_mesh_dfu_iter(*bt_mesh_dfu_slot_cb_t) +(const struct bt_mesh_dfu_slot *slot, void *user_data); + +/** @brief Get the number of slots committed to the firmware list. + * + * @return Number of committed slots. + */ +int bt_mesh_dfu_slot_count(void); + +/** @brief Reserve a new DFU image slot for a distributable image. + * + * A DFU image slot represents a single distributable DFU image with all its + * metadata. The slot data must be set using @ref bt_mesh_dfu_slot_info_set and + * @ref bt_mesh_dfu_slot_fwid_set, and the slot committed using + * @ref bt_mesh_dfu_slot_commit for the slot to be considered part of the slot + * list. + * + * @return A pointer to the reserved slot, or NULL if allocation failed. + */ +struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void); + +/** @brief Set the size and metadata for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the + * metadata. + * @param size The size of the image. + * @param metadata Metadata or NULL. + * @param metadata_len Length of the metadata, at most @c + * CONFIG_BLE_MESH_DFU_METADATA_MAXLEN. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +/** @brief Set the new fwid for the incoming image for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the fwid. + * @param fwid Fwid to set. + * @param fwid_len Length of the fwid, at most @c + * CONFIG_BLE_MESH_DFU_FWID_MAXLEN. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +/** @brief Commit the reserved slot to the list of slots, and store it + * persistently. + * + * If the commit fails for any reason, the slot will still be in the reserved + * state after this call. + * + * @param dfu_slot Pointer to the reserved slot. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_commit(struct bt_mesh_dfu_slot *dfu_slot); + +/** @brief Release a reserved slot so that it can be reserved again. + * + * @param dfu_slot Pointer to the reserved slot. + */ +void bt_mesh_dfu_slot_release(const struct bt_mesh_dfu_slot *dfu_slot); + +/** @brief Delete a committed DFU image slot. + * + * @param slot Slot to delete. Must be a valid pointer acquired from this + * module. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfu_slot_del(const struct bt_mesh_dfu_slot *slot); + +/** @brief Delete all DFU image slots. + * + * @return 0 on success, or (negative) error code on failure. + */ +void bt_mesh_dfu_slot_del_all(void); + +/** @brief Get the DFU image slot at the given firmware image list index. + * + * @param idx DFU image slot index. + * + * @return The DFU image slot at the given index, or NULL if no slot exists with the + * given index. + */ +const struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_at(uint16_t img_idx); + +/** @brief Get the committed DFU image slot for the image with the given + * firmware ID. + * + * @param fwid Firmware ID. + * @param fwid_len Firmware ID length. + * @param slot Slot pointer to fill. + * + * @return Slot index on success, or negative error code on failure. + */ +int bt_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct bt_mesh_dfu_slot **slot); + +/** @brief Get the index in the firmware image list for the given slot. + * + * @param slot Slot to find. + * + * @return Slot index on success, or negative error code on failure. + */ +int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *slot); + +/** @brief Iterate through all DFU image slots. + * + * Calls the callback for every DFU image slot or until the callback returns + * something other than @ref BLE_MESH_DFU_ITER_CONTINUE. + * + * @param cb Callback to call for each slot, or NULL to just count the + * number of slots. + * @param user_data User data to pass to the callback. + * + * @return The number of slots iterated over. + */ +size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data); +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c new file mode 100644 index 000000000000..b36746a8220c --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c @@ -0,0 +1,631 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh_v1.1/dfu/dfu.h" +#include "mesh_v1.1/dfu/dfu_srv.h" + +#include "dfu.h" +#include "blob.h" +#include "access.h" + +#if CONFIG_BLE_MESH_SETTINGS +#include "settings.h" +#endif + +#if CONFIG_BLE_MESH_DFU_SRV +#define UPDATE_IDX_NONE 0xff + +_Static_assert((DFU_UPDATE_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum incoming SDU size."); + +_Static_assert((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_INFO_STATUS) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_TX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum outgoing SDU " + "size."); + +static void store_state(struct bt_mesh_dfu_srv *srv) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, &srv->update, + sizeof(srv->update)); +#endif +} + +static void erase_state(struct bt_mesh_dfu_srv *srv) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#endif +} + +static void xfer_failed(struct bt_mesh_dfu_srv *srv) +{ + if (!bt_mesh_dfu_srv_is_busy(srv) || + srv->update.idx >= srv->img_count) { + return; + } + + erase_state(srv); + + if (srv->cb->end) { + srv->cb->end(srv, &srv->imgs[srv->update.idx], false); + } +} + +static enum bt_mesh_dfu_status metadata_check(struct bt_mesh_dfu_srv *srv, + uint8_t idx, + struct net_buf_simple *buf, + enum bt_mesh_dfu_effect *effect) +{ + *effect = BLE_MESH_DFU_EFFECT_NONE; + + if (idx >= srv->img_count) { + return BLE_MESH_DFU_ERR_FW_IDX; + } + + if (!srv->cb->check) { + return BLE_MESH_DFU_SUCCESS; + } + + if (srv->cb->check(srv, &srv->imgs[idx], buf, effect)) { + *effect = BLE_MESH_DFU_EFFECT_NONE; + return BLE_MESH_DFU_ERR_METADATA; + } + + return BLE_MESH_DFU_SUCCESS; +} + +static void apply_rsp_sent(int err, void *cb_params) +{ + struct bt_mesh_dfu_srv *srv = cb_params; + + if (err) { + /* return phase back to give client one more chance. */ + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_OK; + BT_WARN("Apply response failed, wait for retry (err %d)", err); + return; + } + + BT_DBG(""); + + if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) { + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); + BT_DBG("Prerequisites for apply callback are wrong"); + return; + } + + store_state(srv); + + err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]); + if (err) { + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); + BT_DBG("Application apply callback failed (err %d)", err); + } +} + +static void apply_rsp_sending(uint16_t duration, int err, void *cb_params) +{ + if (err) { + apply_rsp_sent(err, cb_params); + } +} + +static void verify(struct bt_mesh_dfu_srv *srv) +{ + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY; + + if (srv->update.idx >= srv->img_count) { + bt_mesh_dfu_srv_rejected(srv); + return; + } + + if (!srv->cb->end) { + bt_mesh_dfu_srv_verified(srv); + return; + } + + srv->cb->end(srv, &srv->imgs[srv->update.idx], true); + if (srv->update.phase == BLE_MESH_DFU_PHASE_VERIFY) { + store_state(srv); + } +} + +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + uint8_t idx, limit; + + if (srv->update.phase == BLE_MESH_DFU_PHASE_APPLYING) { + BT_INFO("Still applying, not responding"); + return -EBUSY; + } + + idx = net_buf_simple_pull_u8(buf); + limit = net_buf_simple_pull_u8(buf); + + BT_DBG("from %u (limit: %u)", idx, limit); + + NET_BUF_SIMPLE_DEFINE(rsp, BLE_MESH_TX_SDU_MAX); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFU_OP_UPDATE_INFO_STATUS); + net_buf_simple_add_u8(&rsp, srv->img_count); + net_buf_simple_add_u8(&rsp, idx); + + for (; idx < srv->img_count && limit > 0; ++idx) { + uint32_t entry_len; + + if (!srv->imgs[idx].fwid) { + continue; + } + + entry_len = 2 + srv->imgs[idx].fwid_len; + if (srv->imgs[idx].uri) { + entry_len += strlen(srv->imgs[idx].uri); + } + + if (net_buf_simple_tailroom(&rsp) + BLE_MESH_MIC_SHORT < entry_len) { + break; + } + + net_buf_simple_add_u8(&rsp, srv->imgs[idx].fwid_len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].fwid, + srv->imgs[idx].fwid_len); + + if (srv->imgs[idx].uri) { + size_t len = strlen(srv->imgs[idx].uri); + + net_buf_simple_add_u8(&rsp, len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].uri, len); + } else { + net_buf_simple_add_u8(&rsp, 0); + } + + limit--; + } + + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static int handle_metadata_check(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_effect effect; + uint8_t idx; + + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS); + + idx = net_buf_simple_pull_u8(buf); + status = metadata_check(srv, idx, buf, &effect); + + BT_DBG("%u", idx); + + net_buf_simple_add_u8(&rsp, (status & BIT_MASK(3)) | (effect << 3)); + net_buf_simple_add_u8(&rsp, idx); + + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static void update_status_rsp(struct bt_mesh_dfu_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfu_status status, + const struct bt_mesh_send_cb *send_cb) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_STATUS, 14); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_STATUS); + + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(3)) | + (srv->update.phase << 5))); + + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + net_buf_simple_add_u8(&buf, srv->update.ttl); + net_buf_simple_add_u8(&buf, srv->update.effect); + net_buf_simple_add_le16(&buf, srv->update.timeout_base); + net_buf_simple_add_le64(&buf, srv->blob.state.xfer.id); + net_buf_simple_add_u8(&buf, srv->update.idx); + + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv); +} + +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + + BT_DBG(""); + + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); + + return 0; +} + +static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx, + uint16_t timeout_base, + const uint64_t *blob_id, uint8_t ttl, + uint16_t meta_checksum) +{ + return (srv->update.idx != idx || srv->blob.state.xfer.id != *blob_id || + srv->update.ttl != ttl || + srv->update.timeout_base != timeout_base || + srv->update.meta != meta_checksum); +} + +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + const struct bt_mesh_blob_io *io; + uint16_t timeout_base, meta_checksum; + enum bt_mesh_dfu_status status; + uint8_t ttl, idx; + uint64_t blob_id; + int err; + struct net_buf_simple_state buf_state; + + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + idx = net_buf_simple_pull_u8(buf); + meta_checksum = dfu_metadata_checksum(buf); + + BT_DBG("%u ttl: %u extra time: %u", idx, ttl, timeout_base); + + if ((!buf->len || meta_checksum == srv->update.meta) && + srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.ttl == ttl && + srv->update.timeout_base == timeout_base && + srv->update.idx == idx && + srv->blob.state.xfer.id == blob_id) { + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BLE_MESH_DFU_SUCCESS; + store_state(srv); + /* blob srv will resume the transfer. */ + BT_DBG("Resuming transfer"); + goto rsp; + } + + if (bt_mesh_dfu_srv_is_busy(srv)) { + if (is_active_update(srv, idx, timeout_base, &blob_id, ttl, + meta_checksum)) { + status = BLE_MESH_DFU_ERR_WRONG_PHASE; + } else { + status = BLE_MESH_DFU_SUCCESS; + srv->update.ttl = ttl; + srv->blob.state.xfer.id = blob_id; + } + + BT_WARN("Busy. Phase: %u", srv->update.phase); + goto rsp; + } + + net_buf_simple_save(buf, &buf_state); + status = metadata_check(srv, idx, buf, + (enum bt_mesh_dfu_effect *)&srv->update.effect); + net_buf_simple_restore(buf, &buf_state); + if (status != BLE_MESH_DFU_SUCCESS) { + goto rsp; + } + + srv->update.ttl = ttl; + srv->update.timeout_base = timeout_base; + srv->update.meta = meta_checksum; + + io = NULL; + err = srv->cb->start(srv, &srv->imgs[idx], buf, &io); + if (err == -EALREADY || (!err && bt_mesh_has_addr(ctx->addr))) { + /* This image has already been received or this is a + * self-update. Skip the transfer phase and proceed to + * verifying update. + */ + status = BLE_MESH_DFU_SUCCESS; + srv->update.idx = idx; + srv->blob.state.xfer.id = blob_id; + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY; + update_status_rsp(srv, ctx, status, NULL); + verify(srv); + return 0; + } + + if (err == -ENOMEM) { + status = BLE_MESH_DFU_ERR_RESOURCES; + goto rsp; + } + + if (err == -EBUSY) { + status = BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE; + goto rsp; + } + + if (err || !io || !io->wr) { + status = BLE_MESH_DFU_ERR_INTERNAL; + goto rsp; + } + + err = bt_mesh_blob_srv_recv(&srv->blob, blob_id, io, + ttl, timeout_base); + if (err) { + status = BLE_MESH_DFU_ERR_BLOB_XFER_BUSY; + goto rsp; + } + + srv->update.idx = idx; + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BLE_MESH_DFU_SUCCESS; + store_state(srv); + +rsp: + update_status_rsp(srv, ctx, status, NULL); + + return 0; +} + +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + + if (srv->update.idx == UPDATE_IDX_NONE) { + goto rsp; + } + + BT_DBG(""); + + bt_mesh_blob_srv_cancel(&srv->blob); + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + xfer_failed(srv); + +rsp: + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); + + return 0; +} + +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + static const struct bt_mesh_send_cb send_cb = { + .start = apply_rsp_sending, + .end = apply_rsp_sent, + }; + + BT_DBG(""); + + if (srv->update.phase == BLE_MESH_DFU_PHASE_APPLYING) { + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); + return 0; + } + + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY_OK) { + BT_WARN("Apply: Invalid phase %u", srv->update.phase); + update_status_rsp(srv, ctx, BLE_MESH_DFU_ERR_WRONG_PHASE, NULL); + return 0; + } + + /* Postponing the apply callback until the response has been sent, in + * case it triggers a reboot: + */ + srv->update.phase = BLE_MESH_DFU_PHASE_APPLYING; + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, &send_cb); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = { + { BLE_MESH_DFU_OP_UPDATE_INFO_GET, 2, (void *)handle_info_get }, + { BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, 1, (void *)handle_metadata_check }, + { BLE_MESH_DFU_OP_UPDATE_GET, 0, (void *)handle_get }, + { BLE_MESH_DFU_OP_UPDATE_START, 12, (void *)handle_start }, + { BLE_MESH_DFU_OP_UPDATE_CANCEL, 0, (void *)handle_cancel }, + { BLE_MESH_DFU_OP_UPDATE_APPLY, 0, (void *)handle_apply }, + BLE_MESH_MODEL_OP_END, +}; + +static int dfu_srv_init(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + + srv->mod = mod; + srv->update.idx = UPDATE_IDX_NONE; + srv->blob.cb = &_bt_mesh_dfu_srv_blob_cb; + + if (!srv->cb || !srv->cb->start || !srv->imgs || srv->img_count == 0 || + srv->img_count == UPDATE_IDX_NONE) { + BT_ERR("Invalid DFU Server initialization"); + return -EINVAL; + } + + return 0; +} + +__attribute__((unused)) +static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *name, + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + ssize_t len; + + if (len_rd < sizeof(srv->update)) { + return -EINVAL; + } + + len = read_cb(cb_arg, &srv->update, sizeof(srv->update)); + if (len < 0) { + return len; + } + + BT_DBG("Recovered transfer (phase: %u, idx: %u)", srv->update.phase, + srv->update.idx); + if (srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + BT_DBG("Settings recovered mid-transfer, setting transfer error"); + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + } else if (srv->update.phase == BLE_MESH_DFU_PHASE_VERIFY_OK) { + BT_DBG("Settings recovered before application, setting verification fail"); + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_FAIL; + } + + return 0; +} + +static void dfu_srv_reset(struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_srv *srv = mod->user_data; + + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + erase_state(srv); +} + +static int dfu_srv_deinit(struct bt_mesh_model *mod) +{ + dfu_srv_reset(mod); + return 0; +} + +const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb = { + .init = dfu_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfu_srv_deinit, +#endif +}; + +static void blob_suspended(struct bt_mesh_blob_srv *b) +{ + struct bt_mesh_dfu_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + store_state(srv); +} + +static void blob_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) +{ + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + BT_DBG("success: %u", success); + + if (!success) { + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + xfer_failed(srv); + return; + } + + verify(srv); +} + +static int blob_recover(struct bt_mesh_blob_srv *b, + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io) +{ + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + if (!srv->cb->recover || + srv->update.phase != BLE_MESH_DFU_PHASE_TRANSFER_ERR || + srv->update.idx >= srv->img_count) { + return -ENOTSUP; + } + + return srv->cb->recover(srv, &srv->imgs[srv->update.idx], io); +} + +const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb = { + .suspended = blob_suspended, + .end = blob_end, + .recover = blob_recover, +}; + +void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY) { + BT_WARN("Wrong state"); + return; + } + + BT_DBG(""); + + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_OK; + store_state(srv); +} + +void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY) { + BT_WARN("Wrong state"); + return; + } + + BT_DBG(""); + + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_FAIL; + store_state(srv); +} + +void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase == BLE_MESH_DFU_PHASE_IDLE) { + BT_WARN("Wrong state"); + return; + } + + (void)bt_mesh_blob_srv_cancel(&srv->blob); +} + +void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BLE_MESH_DFU_PHASE_APPLYING) { + BT_WARN("Wrong state"); + return; + } + + BT_DBG(""); + + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); +} + +bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv) +{ + return srv->update.phase != BLE_MESH_DFU_PHASE_IDLE && + srv->update.phase != BLE_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY_FAIL; +} + +uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv) +{ + if (!bt_mesh_dfu_srv_is_busy(srv)) { + return 0U; + } + + if (srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + return bt_mesh_blob_srv_progress(&srv->blob); + } + + return 100U; +} +#endif /* CONFIG_BLE_MESH_DFU_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h new file mode 100644 index 000000000000..a9634ef22040 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h @@ -0,0 +1,146 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_DFD_H__ +#define _BLE_MESH_v11_DFD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_MESH_DFD_OP_RECEIVERS_ADD BLE_MESH_MODEL_OP_2(0x83, 0x11) +#define BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x12) +#define BLE_MESH_DFD_OP_RECEIVERS_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x13) +#define BLE_MESH_DFD_OP_RECEIVERS_GET BLE_MESH_MODEL_OP_2(0x83, 0x14) +#define BLE_MESH_DFD_OP_RECEIVERS_LIST BLE_MESH_MODEL_OP_2(0x83, 0x15) +#define BLE_MESH_DFD_OP_CAPABILITIES_GET BLE_MESH_MODEL_OP_2(0x83, 0x16) +#define BLE_MESH_DFD_OP_CAPABILITIES_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x17) +#define BLE_MESH_DFD_OP_GET BLE_MESH_MODEL_OP_2(0x83, 0x18) +#define BLE_MESH_DFD_OP_START BLE_MESH_MODEL_OP_2(0x83, 0x19) +#define BLE_MESH_DFD_OP_SUSPEND BLE_MESH_MODEL_OP_2(0x83, 0x1a) +#define BLE_MESH_DFD_OP_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x1b) +#define BLE_MESH_DFD_OP_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x1c) +#define BLE_MESH_DFD_OP_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x1d) +#define BLE_MESH_DFD_OP_UPLOAD_GET BLE_MESH_MODEL_OP_2(0x83, 0x1e) +#define BLE_MESH_DFD_OP_UPLOAD_START BLE_MESH_MODEL_OP_2(0x83, 0x1f) +#define BLE_MESH_DFD_OP_UPLOAD_START_OOB BLE_MESH_MODEL_OP_2(0x83, 0x20) +#define BLE_MESH_DFD_OP_UPLOAD_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x21) +#define BLE_MESH_DFD_OP_UPLOAD_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x22) +#define BLE_MESH_DFD_OP_FW_GET BLE_MESH_MODEL_OP_2(0x83, 0x23) +#define BLE_MESH_DFD_OP_FW_GET_BY_INDEX BLE_MESH_MODEL_OP_2(0x83, 0x24) +#define BLE_MESH_DFD_OP_FW_DELETE BLE_MESH_MODEL_OP_2(0x83, 0x25) +#define BLE_MESH_DFD_OP_FW_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x26) +#define BLE_MESH_DFD_OP_FW_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x27) + +/** + * @defgroup bt_mesh_dfd Firmware Distribution models + * @ingroup bt_mesh + * @{ + */ + +/** Firmware distribution status. */ +enum bt_mesh_dfd_status { + /** The message was processed successfully. */ + BLE_MESH_DFD_SUCCESS, + + /** Insufficient resources on the node. */ + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BLE_MESH_DFD_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + BLE_MESH_DFD_ERR_INTERNAL, + + /** The requested firmware image is not stored on the Distributor. */ + BLE_MESH_DFD_ERR_FW_NOT_FOUND, + + /** The AppKey identified by the AppKey Index is not known to the node. + */ + BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + + /** There are no Target nodes in the Distribution Receivers List + * state. + */ + BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + + /** Another firmware image distribution is in progress. */ + BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + + /** Another upload is in progress. */ + BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + + /** The URI scheme name indicated by the Update URI is not supported. */ + BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED, + + /** The format of the Update URI is invalid. */ + BLE_MESH_DFD_ERR_URI_MALFORMED, + + /** The URI is currently unreachable. */ + BLE_MESH_DFD_ERR_URI_UNREACHABLE, + + /** The Check Firmware OOB procedure did not find any new firmware. */ + BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + + /** The suspension of the Distribute Firmware procedure failed. */ + BLE_MESH_DFD_ERR_SUSPEND_FAILED, +}; + +/** Firmware distribution phases. */ +enum bt_mesh_dfd_phase { + /** No firmware distribution is in progress. */ + BLE_MESH_DFD_PHASE_IDLE, + + /** Firmware distribution is in progress. */ + BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE, + + /** The Transfer BLOB procedure has completed successfully. */ + BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS, + + /** The Apply Firmware on Target Nodes procedure is being executed. */ + BLE_MESH_DFD_PHASE_APPLYING_UPDATE, + + /** The Distribute Firmware procedure has completed successfully. */ + BLE_MESH_DFD_PHASE_COMPLETED, + + /** The Distribute Firmware procedure has failed. */ + BLE_MESH_DFD_PHASE_FAILED, + + /** The Cancel Firmware Update procedure is being executed. */ + BLE_MESH_DFD_PHASE_CANCELING_UPDATE, + + /** The Transfer BLOB procedure is suspended. */ + BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED, +}; + +/** Firmware upload phases. */ +enum bt_mesh_dfd_upload_phase { + /** No firmware upload is in progress. */ + BLE_MESH_DFD_UPLOAD_PHASE_IDLE, + + /** The Store Firmware procedure is being executed. */ + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + + /** The Store Firmware procedure or Store Firmware OOB procedure failed. + */ + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + + /** The Store Firmware procedure or the Store Firmware OOB procedure + * completed successfully. + */ + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFD_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h new file mode 100644 index 000000000000..2fa96b037359 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h @@ -0,0 +1,472 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfd_cli Device Firmware Distribution Client model + * @ingroup bt_mesh_dfd + * @{ + * @brief API for the Device Firmware Distribution Client model + */ + +#ifndef _BLE_MESH_v11_DFD_CLI_H__ +#define _BLE_MESH_v11_DFD_CLI_H__ + +#include "mesh/access.h" +#include "mesh/client_common.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Device Firmware Distribution Client model instance. */ +typedef bt_mesh_client_user_data_t bt_mesh_dfd_client_t; + +/** @brief DFD Client internal data structure. */ +typedef bt_mesh_client_internal_data_t dfd_internal_data_t; + +/*!< Maximum value of upload progress indicating progress is unset. */ +#define UPLOAD_PROGRESS_UNSET 101 + +/*!< In-band upload type. */ +#define UPLOAD_IN_BAND 0x00 + +/*!< Out-of-band upload type. */ +#define UPLOAD_OOB 0x01 + +/*!< Upload type is not set. */ +#define UPLOAD_TYPE_UNSET 0xFF + +/*!< Extract target address from target info bitfield. */ +#define TARGET_ADDR(target_info) (target_info >> 17) + +/*!< Extract target update phase from target info bitfield. */ +#define TARGET_UPDATE_PHASE(target_info) ((target_info >> 13) & 0x0f) + +/*!< Extract target update status from target info bitfield. */ +#define TARGET_UPDATE_STATUS(target_info) ((target_info >> 10) & 0x07) + +/*!< Extract target transfer status from target info bitfield. */ +#define TARGET_TRANSFER_STATUS(target_info) ((target_info >> 6) & 0x0f) + +/*!< Extract target transfer progress from target info bitfield. */ +#define TARGET_TRANSFER_PROGRESS(target_info) (target_info & 0x3f) + +/** + * @brief DFD Client receiver entry structure. + * + * This structure represents a single receiver node that will receive firmware + * distribution. Each receiver is identified by its unicast address and the + * firmware image index that should be distributed to it. + */ +typedef struct { + uint16_t addr; /*!< Unicast address of the receiver node. */ + uint8_t fw_idx; /*!< Index of the firmware image to distribute. */ +} dfd_cli_receiver_entry_t; + +/** + * @brief Target node entry information structure. + * + * This structure contains detailed information about a target node's + * firmware distribution status, including address, update phase, transfer + * progress, and other related information. + */ +typedef struct { + uint32_t addr:15; /*!< Unicast address of the target node. */ + uint32_t retrieved_update_phase:4; /*!< Current update phase of the target. */ + uint32_t update_status:3; /*!< Update status of the target node. */ + uint32_t transfer_status:4; /*!< Transfer status of the target. */ + uint32_t transfer_progress:6; /*!< Transfer progress percentage. */ + uint8_t update_fw_idx; /*!< Index of firmware being updated. */ +} target_node_entry_t; + +/** + * @brief DFD receiver status response structure. + * + * This structure contains the status response for receiver add/delete + * operations, including the operation result and current receiver list size. + */ +typedef struct { + uint8_t status; /*!< Status code of the operation (see @ref bt_mesh_dfd_status). */ + uint16_t receiver_list_cnt; /*!< Current number of receivers in the distribution list. */ +} dfd_cli_receiver_status_t; + +/** + * @brief DFD receiver list response structure. + * + * This structure contains the response to a receivers get request, + * providing a list of target nodes with their current status information. + */ +typedef struct { + uint16_t entries_cnt; /*!< Number of receiver entries in the list. */ + uint16_t first_index; /*!< Index of the first entry in the list. */ + target_node_entry_t *entries; /*!< Pointer to array of target node entries. */ +} dfd_cli_receiver_list_t; + +/** + * @brief DFD distribution capabilities structure. + * + * This structure contains the capabilities of the DFD Server, including + * storage limits, receiver limits, and supported features. + */ +typedef struct { + uint16_t max_receiver_list_sz; /*!< Maximum number of receivers supported. */ + uint16_t max_fw_list_sz; /*!< Maximum number of firmware images supported. */ + uint32_t max_fw_sz; /*!< Maximum firmware image size supported. */ + uint32_t max_upload_space; /*!< Total upload storage space available. */ + uint32_t remaining_upload_space; /*!< Remaining upload storage space. */ + uint8_t oob_retrieval_supported; /*!< OOB retrieval support flag. */ + struct net_buf_simple *supported_url_scheme_names; /*!< Supported URL scheme names. */ +} dfd_cli_dist_caps_t; + +/** + * @brief DFD distribution status structure. + * + * This structure contains the current status of an ongoing or completed + * firmware distribution operation, including phase, progress, and configuration. + */ +typedef struct { + uint8_t status; /*!< Distribution status code (see @ref bt_mesh_dfd_status). */ + uint8_t dist_phase; /*!< Current distribution phase (see @ref bt_mesh_dfd_phase). */ + uint16_t multicast_address; /*!< Multicast address used for distribution. */ + uint16_t appkey_idx; /*!< Application key index used for distribution. */ + uint8_t ttl; /*!< TTL value used for distribution messages. */ + uint16_t timeout_base; /*!< Base timeout value for distribution. */ + uint8_t trans_mode:2; /*!< Transfer mode (push or pull). */ + uint8_t update_policy:1; /*!< Update policy (single or all). */ + uint8_t RFU:5; /*!< Reserved for future use. */ + uint16_t fw_idx; /*!< Index of firmware being distributed. */ +} dfd_cli_dist_status_t; + +/** + * @brief DFD upload status structure. + * + * This structure contains the current status of a firmware upload operation, + * including phase, progress, and firmware identification. + */ +typedef struct { + uint8_t status; /*!< Upload operation status code (see @ref bt_mesh_dfd_status). */ + uint8_t upload_phase; /*!< Current upload phase (see @ref bt_mesh_dfd_upload_phase). */ + uint8_t upload_progress:7; /*!< Upload progress percentage (0-100). */ + uint8_t upload_type:1; /*!< Upload type (in-band or OOB). */ + union { + struct net_buf_simple *fwid; /*!< Firmware ID for in-band uploads. */ + struct net_buf_simple *oob_fwid; /*!< Firmware ID for OOB uploads. */ + }; +} dfd_cli_upload_status_t; + +/** + * @brief DFD firmware status structure. + * + * This structure contains the status response for firmware management + * operations, including information about firmware images. + */ +typedef struct { + uint8_t status; /*!< Firmware operation status code (see @ref bt_mesh_dfd_status). */ + uint16_t entry_cnt; /*!< Number of firmware entries. */ + uint16_t firmware_image_index; /*!< Index of the firmware image. */ + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ +} dfd_cli_firmware_status_t; + +/** + * @brief DFD distribution start parameters structure. + * + * This structure contains parameters for starting a firmware distribution + * operation, including target configuration and distribution settings. + */ +typedef struct { + uint8_t ttl; /*!< TTL value for distribution messages. */ + uint8_t trans_mode:2; /*!< Transfer mode (push or pull). */ + uint8_t update_policy:1; /*!< Update policy (single or all). */ + uint8_t RFU:5; /*!< Reserved for future use. */ + uint16_t app_idx; /*!< Application key index for distribution. */ + uint16_t timeout_base; /*!< Base timeout value for distribution. */ + uint16_t fw_idx; /*!< Index of firmware to distribute. */ + bool is_va; /*!< True if using virtual address, false for group address. */ + union { + uint16_t group_addr; /*!< Group address for distribution (if is_va is false). */ + uint8_t label_uuid[16]; /*!< Virtual label UUID for distribution (if is_va is true). */ + }; +} dfd_cli_dist_start_t; + +/** + * @brief DFD distribution upload start parameters structure. + * + * This structure contains parameters for starting an in-band firmware + * upload operation to the DFD Server. + */ +typedef struct { + uint8_t ttl; /*!< TTL value for upload messages. */ + uint16_t timeout_base; /*!< Base timeout value for upload. */ + uint32_t fw_size; /*!< Size of the firmware image in bytes. */ + uint64_t blob_id; /*!< BLOB ID for the firmware transfer. */ + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ + struct net_buf_simple *fw_metadata; /*!< Firmware metadata buffer. */ +} dfd_cli_dist_upload_start_t; + +/** + * @brief DFD distribution OOB upload start parameters structure. + * + * This structure contains parameters for starting an out-of-band firmware + * upload operation to the DFD Server. + */ +typedef struct { + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ + struct net_buf_simple *url; /*!< URL for retrieving the firmware. */ +} dfd_cli_dist_upload_oob_start_t; + +/** + * @brief DFD status response union. + * + * This union contains different status response structures for various DFD + * Client operations, allowing type-safe access to operation-specific responses. + */ +typedef union { + dfd_cli_receiver_status_t receiver_status; /*!< Receiver add/delete status. */ + dfd_cli_receiver_list_t receiver_list; /*!< Receiver list response. */ + dfd_cli_dist_caps_t dist_caps; /*!< Distribution capabilities. */ + dfd_cli_dist_status_t dist_status; /*!< Distribution status. */ + dfd_cli_upload_status_t upload_status; /*!< Upload status. */ + dfd_cli_firmware_status_t firmware_status; /*!< Firmware management status. */ +} dfd_status_t; + +/*!< DFD Client model operation handlers. */ +extern const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[]; + +/*!< DFD Client model callbacks. */ +extern const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb; + +/** + * @brief Add receivers to the distribution list. + * + * Add multiple target nodes to the DFD Server's distribution receiver list. + * These receivers will be included in subsequent firmware distribution operations. + * + * @param[in] param Common client parameters for the operation. + * @param[in] receivers Pointer to array of receiver entries to add. + * @param[in] receivers_cnt Number of receiver entries in the array. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, + dfd_cli_receiver_entry_t *receivers, + uint16_t receivers_cnt); + +/** + * @brief Delete all receivers from the distribution list. + * + * Remove all target nodes from the DFD Server's distribution receiver list. + * This operation will clear the entire receiver list. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_delete_all(bt_mesh_client_common_param_t *param); + +/** + * @brief Get the distribution receiver list. + * + * Retrieve a portion of the DFD Server's distribution receiver list. + * Supports pagination to retrieve large receiver lists in chunks. + * + * @param[in] param Common client parameters for the operation. + * @param[in] first_index Index of the first receiver entry to retrieve. + * @param[in] entries_limit Maximum number of entries to retrieve. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_get(bt_mesh_client_common_param_t *param, + uint16_t first_index, + uint16_t entries_limit); + +/** + * @brief Get distribution capabilities from the DFD Server. + * + * Query the DFD Server's capabilities, including storage limits, + * supported features, and maximum receiver count. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_capabilities_get(bt_mesh_client_common_param_t *param); +/** + * @brief Get current distribution status from the DFD Server. + * + * Query the current status of firmware distribution operations, + * including phase, progress, and configuration information. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_get(bt_mesh_client_common_param_t *param); + +/** + * @brief Start firmware distribution to receivers. + * + * Initiate firmware distribution to all target nodes in the distribution + * receiver list using the specified configuration parameters. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start Distribution start parameters and configuration. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_start_t *start); + +/** + * @brief Suspend ongoing firmware distribution. + * + * Suspend a currently active firmware distribution operation. + * The distribution can be resumed later if needed. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_suspend(bt_mesh_client_common_param_t *param); + +/** + * @brief Cancel firmware distribution. + * + * Cancel an ongoing or suspended firmware distribution operation. + * This will terminate the distribution process. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_cancel(bt_mesh_client_common_param_t *param); + +/** + * @brief Apply distributed firmware on target nodes. + * + * Apply the distributed firmware image on target nodes that have + * successfully received the firmware transfer. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_apply(bt_mesh_client_common_param_t *param); +/** + * @brief Get firmware upload status from the DFD Server. + * + * Query the current status of firmware upload operations, including + * phase, progress, and transfer information. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_get(bt_mesh_client_common_param_t *param); + +/** + * @brief Start in-band firmware upload to the DFD Server. + * + * Initiate an in-band firmware upload using BLOB transfer protocol. + * The firmware image will be transferred directly through the mesh network. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start Upload start parameters including firmware details. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_start_t *start); + +/** + * @brief Start out-of-band firmware upload to the DFD Server. + * + * Initiate an out-of-band firmware upload where the DFD Server + * retrieves the firmware from the specified URL. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start OOB upload start parameters including URL and firmware ID. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_oob_start_t *start); + +/** + * @brief Cancel out-of-band firmware upload. + * + * Cancel an ongoing out-of-band firmware upload operation. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_oob_cancel(bt_mesh_client_common_param_t *param); +/** + * @brief Get firmware information by firmware ID. + * + * Query detailed information about a specific firmware image + * stored on the DFD Server using its firmware ID. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fwid Firmware ID to query information for. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get(bt_mesh_client_common_param_t *param, + struct net_buf_simple *fwid); + +/** + * @brief Get firmware information by index. + * + * Query detailed information about a firmware image stored on the + * DFD Server using its index in the firmware list. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fw_id_index Index of the firmware image to query. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get_by_index(bt_mesh_client_common_param_t *param, + uint16_t fw_id_index); + +/** + * @brief Delete specific firmware image by firmware ID. + * + * Delete a specific firmware image from the DFD Server's storage + * using its firmware ID. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fwid Firmware ID of the image to delete. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get_delete(bt_mesh_client_common_param_t *param, + struct net_buf_simple *fwid); + +/** + * @brief Delete all firmware images from the DFD Server. + * + * Delete all firmware images stored on the DFD Server. + * This operation will clear the entire firmware storage. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_delete_all(bt_mesh_client_common_param_t *param); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* _BLE_MESH_v11_DFD_CLI_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h new file mode 100644 index 000000000000..b494ce775dd1 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h @@ -0,0 +1,311 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfd_srv Firmware Distribution Server model + * @ingroup bt_mesh_dfd + * @{ + * @brief API for the Firmware Distribution Server model + */ + +#ifndef _BLE_MESH_v11_DFD_SRV_H__ +#define _BLE_MESH_v11_DFD_SRV_H__ + +#include "mesh/access.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX +#define CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX 0 +#endif + +#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE +#define CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE 0 +#endif + +#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE +#define CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE 0 +#endif + +struct bt_mesh_dfd_srv; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +/** + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB + * upload support. + * + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + * @param[in] _oob_schemes Array of OOB schemes supported by the server, + * each scheme being a code point from the + * Bluetooth SIG Assigned Numbers document. + * @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes. + */ +#define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \ + { \ + .cb = _cb, \ + .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + .oob_schemes = { \ + .schemes = _oob_schemes, \ + .count = _oob_schemes_count, \ + }, \ + } +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + +/** + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv. + * + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + */ +#define BT_MESH_DFD_SRV_INIT(_cb) \ + { \ + .cb = _cb, \ + .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + } + +/** + * @brief Firmware Distribution Server model Composition Data entry. + * + * @param _srv Pointer to a @ref bt_mesh_dfd_srv instance. + */ +#define BT_MESH_MODEL_DFD_SRV(_srv) \ + BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu), \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob), \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL, \ + _srv, &_bt_mesh_dfd_srv_cb) + +/** Firmware Distribution Server callbacks: */ +struct bt_mesh_dfd_srv_cb { + + /** @brief Slot receive callback. + * + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*recv)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + /** @brief Firmware upload OOB start callback. + * + * Called at the start of an OOB firmware upload. The application must + * start a firmware check using an OOB mechanism, and then call + * @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return + * value of this function, the application must then start storing the + * firmware image using an OOB mechanism, and call + * @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory + * to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot Slot to be used for the upload. + * @param uri Pointer to buffer containing the URI used to + * check for new firmware. + * @param uri_len Length of the URI buffer. + * @param fwid Pointer to buffer containing the current + * firmware ID to be used when checking for + * availability of new firmware. + * @param fwid_len Length of the current firmware ID. Must be set + * to the length of the new firmware ID if it is + * available, or to 0 if new firmware is not + * available. + * + * @return BLE_MESH_DFD_SUCCESS on success, or error code otherwise. + */ + int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const char *uri, uint8_t uri_len, + const uint8_t *fwid, uint16_t fwid_len); + + /** @brief Cancel store OOB callback + * + * Called when an OOB store is cancelled. The application must stop + * any ongoing OOB image transfer. This callback is mandatory to + * support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to cancel + */ + void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); + + /** @brief Get the progress of an ongoing OOB store + * + * Called by the Firmware Distribution Server model when it needs to + * get the current progress of an ongoing OOB store from the + * application. This callback is mandatory to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to get progress for. + * + * @return The current progress of the ongoing OOB store, in percent. + */ + uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + + /** @brief Slot delete callback. + * + * Called when the Firmware Distribution Server is about to delete a DFU image slot. + * All allocated data associated with the firmware slot should be + * deleted. + * + * @param srv Firmware Update Server instance. + * @param slot DFU image slot being deleted. + */ + void (*del)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); + + /** @brief Slot send callback. + * + * Called at the start of a distribution procedure. The callback must + * fill @c io with a pointer to a readable BLOB stream for the Firmware + * Distribution Server to read the firmware image from. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being sent. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*send)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); + + /** @brief Phase change callback (Optional). + * + * Called whenever the phase of the Firmware Distribution Server changes. + * + * @param srv Firmware Distribution Server model instance. + * @param phase New Firmware Distribution phase. + */ + void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase); +}; + +/** Firmware Distribution Server instance. */ +struct bt_mesh_dfd_srv { + const struct bt_mesh_dfd_srv_cb *cb; + const struct bt_mesh_model *mod; + struct bt_mesh_dfu_cli dfu; + struct bt_mesh_dfu_target targets[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + const struct bt_mesh_blob_io *io; + uint16_t target_cnt; + uint16_t slot_idx; + bool apply; + enum bt_mesh_dfd_phase phase; + struct bt_mesh_blob_cli_inputs inputs; + + struct { + enum bt_mesh_dfd_upload_phase phase; + struct bt_mesh_dfu_slot *slot; + const struct flash_area *area; + struct bt_mesh_blob_srv blob; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + bool is_oob; + bool is_pending_oob_check; + struct { + uint8_t uri_len; + char uri[CONFIG_BLE_MESH_DFU_URI_MAXLEN]; + uint16_t current_fwid_len; + uint8_t current_fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + struct bt_mesh_msg_ctx ctx; + } oob; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + } upload; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct { + const uint8_t *schemes; + const uint8_t count; + } oob_schemes; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +}; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +/** @brief Call when an OOB check has completed or failed + * + * This should be called by the application after an OOB check started by the @c start_oob_upload + * callback has completed or failed. The @p status param should be set to one of the following + * values: + * + * * @c BLE_MESH_DFD_SUCCESS if the check was successful and a new firmware ID was found. + * * @c BLE_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly. + * * @c BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node. + * * @c BLE_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached. + * * @c BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new + * firmware is available. + * + * If this function returns 0, the application should then download the firmware to the + * slot. If an error code is returned, the application should abort the OOB upload. + * + * @param srv Firmware Distribution Server model instance. + * @param slot The slot used in the OOB upload. + * @param status The result of the firmware check. + * @param fwid If the check was successful and new firmware found, this should point to a + * buffer containing the new firmware ID to store. + * @param fwid_len The length of the firmware ID pointed to by @p fwid. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len); + +/** @brief Call when an OOB store has completed or failed + * + * This should be called by the application after an OOB store started after a successful call to + * @c bt_mesh_dfd_srv_oob_check_complete has completed successfully or failed. + * + * @param srv Firmware Distribution Server model instance. + * @param slot The slot used when storing the firmware image. + * @param success @c true if the OOB store completed successfully, @c false otherwise. + * @param size The size of the stored firmware image, in bytes. + * @param metadata Pointer to the metadata received OOB, or @c NULL if no metadata was + * received. + * @param metadata_len Size of the metadata pointed to by @p metadata. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb; +extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb; +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFD_SRV_H__ */ + +/** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h new file mode 100644 index 000000000000..073aae901b14 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h @@ -0,0 +1,173 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_DFU_H__ +#define _BLE_MESH_v11_DFU_H__ + +#include + +#include "mesh/types.h" +#include "mesh/utils.h" + +#include "mesh_v1.1/mbt/blob.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_dfu Bluetooth Mesh Device Firmware Update + * @ingroup bt_mesh + * @{ + */ + +#ifndef CONFIG_BLE_MESH_DFU_FWID_MAXLEN +#define CONFIG_BLE_MESH_DFU_FWID_MAXLEN 0 +#endif + +#ifndef CONFIG_BLE_MESH_DFU_METADATA_MAXLEN +#define CONFIG_BLE_MESH_DFU_METADATA_MAXLEN 0 +#endif + +#ifndef CONFIG_BLE_MESH_DFU_URI_MAXLEN +#define CONFIG_BLE_MESH_DFU_URI_MAXLEN 0 +#endif + +#ifndef CONFIG_BLE_MESH_DFU_SLOT_CNT +#define CONFIG_BLE_MESH_DFU_SLOT_CNT 0 +#endif + +/** DFU transfer phase. */ +enum bt_mesh_dfu_phase { + /** Ready to start a Receive Firmware procedure. */ + BLE_MESH_DFU_PHASE_IDLE, + + /** The Transfer BLOB procedure failed. */ + BLE_MESH_DFU_PHASE_TRANSFER_ERR, + + /** The Receive Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE, + + /** The Verify Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_VERIFY, + + /** The Verify Firmware procedure completed successfully. */ + BLE_MESH_DFU_PHASE_VERIFY_OK, + + /** The Verify Firmware procedure failed. */ + BLE_MESH_DFU_PHASE_VERIFY_FAIL, + + /** The Apply New Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_APPLYING, + + /** Firmware transfer has been canceled. */ + BLE_MESH_DFU_PHASE_TRANSFER_CANCELED, + + /** Firmware applying succeeded. */ + BLE_MESH_DFU_PHASE_APPLY_SUCCESS, + + /** Firmware applying failed. */ + BLE_MESH_DFU_PHASE_APPLY_FAIL, + + /** Phase of a node was not yet retrieved. */ + BLE_MESH_DFU_PHASE_UNKNOWN, +}; + +/** DFU status. */ +enum bt_mesh_dfu_status { + /** The message was processed successfully. */ + BLE_MESH_DFU_SUCCESS, + + /** Insufficient resources on the node */ + BLE_MESH_DFU_ERR_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BLE_MESH_DFU_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + BLE_MESH_DFU_ERR_INTERNAL, + + /** The message contains a firmware index value that is not expected. */ + BLE_MESH_DFU_ERR_FW_IDX, + + /** The metadata check failed. */ + BLE_MESH_DFU_ERR_METADATA, + + /** The Server cannot start a firmware update. */ + BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, + + /** Another BLOB transfer is in progress. */ + BLE_MESH_DFU_ERR_BLOB_XFER_BUSY, +}; + +/** Expected effect of a DFU transfer. */ +enum bt_mesh_dfu_effect { + /** No changes to node Composition Data. */ + BLE_MESH_DFU_EFFECT_NONE, + + /** Node Composition Data changed and the node does not support remote + * provisioning. + */ + BLE_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, + + /** Node Composition Data changed, and remote provisioning is supported. + * The node supports remote provisioning and Composition Data Page + * 0x80. Page 0x80 contains different Composition Data than Page 0x0. + */ + BLE_MESH_DFU_EFFECT_COMP_CHANGE, + + /** Node will be unprovisioned after the update. */ + BLE_MESH_DFU_EFFECT_UNPROV, +}; + +/** Action for DFU iteration callbacks. */ +enum bt_mesh_dfu_iter { + /** Stop iterating. */ + BLE_MESH_DFU_ITER_STOP, + + /** Continue iterating. */ + BLE_MESH_DFU_ITER_CONTINUE, +}; + +/** DFU image instance. + * + * Each DFU image represents a single updatable firmware image. + */ +struct bt_mesh_dfu_img { + /** Firmware ID. */ + const void *fwid; + + /** Length of the firmware ID. */ + size_t fwid_len; + + /** Update URI, or NULL. */ + const char *uri; +}; + +/** DFU image slot for DFU distribution. */ +struct bt_mesh_dfu_slot { + /** Size of the firmware in bytes. */ + size_t size; + /** Length of the firmware ID. */ + size_t fwid_len; + /** Length of the metadata. */ + size_t metadata_len; + /** Firmware ID. */ + uint8_t fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + /** Metadata. */ + uint8_t metadata[CONFIG_BLE_MESH_DFU_METADATA_MAXLEN]; +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFU_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h new file mode 100644 index 000000000000..531e35999426 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h @@ -0,0 +1,430 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model + * @ingroup bt_mesh_dfu + * @{ + * @brief API for the Bluetooth Mesh Firmware Update Client model + */ + +#ifndef _BLE_MESH_v11_DFU_CLI_H__ +#define _BLE_MESH_v11_DFU_CLI_H__ + +#include "freertos/semphr.h" + +#include "mesh/access.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/dfu/dfu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfu_cli; + +/** + * + * @brief Initialization parameters for the @ref bt_mesh_dfu_cli. + * + * @sa bt_mesh_dfu_cli_cb. + * + * @param _handlers Handler callback structure. + */ +#define BLE_MESH_DFU_CLI_INIT(_handlers) \ + { \ + .cb = _handlers, \ + .blob = { .cb = &_bt_mesh_dfu_cli_blob_handlers }, \ + } + +/** + * + * @brief Firmware Update Client model Composition Data entry. + * + * @param _cli Pointer to a @ref bt_mesh_dfu_cli instance. + */ +#define BT_MESH_MODEL_DFU_CLI(_cli) \ + BT_MESH_MODEL_BLOB_CLI(&(_cli)->blob), \ + BT_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFU_CLI, _bt_mesh_dfu_cli_op, NULL, \ + _cli, &_bt_mesh_dfu_cli_cb) + +/** DFU Target node. */ +struct bt_mesh_dfu_target { + /** BLOB Target node */ + struct bt_mesh_blob_target blob; + /** Image index on the Target node */ + uint8_t img_idx; + /** Expected DFU effect, see @ref bt_mesh_dfu_effect. */ + uint8_t effect; + /** Current DFU status, see @ref bt_mesh_dfu_status. */ + uint8_t status; + /** Current DFU phase, see @ref bt_mesh_dfu_phase. */ + uint8_t phase; +}; + +/** Metadata status response. */ +struct bt_mesh_dfu_metadata_status { + /** Image index. */ + uint8_t idx; + /** Status code. */ + enum bt_mesh_dfu_status status; + /** Effect of transfer. */ + enum bt_mesh_dfu_effect effect; +}; + +/** DFU Target node status parameters. + * The structure should be same as + * @ref esp_ble_mesh_device_firmware_update_status_t +*/ +struct bt_mesh_dfu_target_status { + /** Status of the previous operation. */ + enum bt_mesh_dfu_status status; + /** Phase of the current DFU transfer. */ + enum bt_mesh_dfu_phase phase; + /** The effect the update will have on the Target device's state. */ + enum bt_mesh_dfu_effect effect; + /** BLOB ID used in the transfer. */ + uint64_t blob_id; + /** Image index to transfer. */ + uint8_t img_idx; + /** TTL used in the transfer. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** @brief DFU image callback. + * + * The image callback is called for every DFU image on the Target node when + * calling @ref bt_mesh_dfu_cli_imgs_get. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context of the received message. + * @param idx Image index. + * @param total Total number of images on the Target node. + * @param img Image information for the given image index. + * @param cb_data Callback data. + * + * @retval BLE_MESH_DFU_ITER_STOP Stop iterating through the image list and + * return from @ref bt_mesh_dfu_cli_imgs_get. + * @retval BLE_MESH_DFU_ITER_CONTINUE Continue iterating through the image list + * if any images remain. + */ +typedef enum bt_mesh_dfu_iter(*bt_mesh_dfu_img_cb_t)(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t total, + const struct bt_mesh_dfu_img *img, + void *cb_data); + +/** Firmware Update Client event callbacks. */ +struct bt_mesh_dfu_cli_cb { + /** @brief BLOB transfer is suspended. + * + * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. + * + * @param cli Firmware Update Client model instance. + */ + void (*suspended)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU ended. + * + * Called when the DFU transfer ends, either because all Target nodes were + * lost or because the transfer was completed successfully. + * + * @param cli Firmware Update Client model instance. + * @param reason Reason for ending. + */ + void (*ended)(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason); + + /** @brief DFU transfer applied on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_apply. + * + * @param cli Firmware Update Client model instance. + */ + void (*applied)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU transfer confirmed on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_confirm. + * + * @param cli Firmware Update Client model instance. + */ + void (*confirmed)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU Target node was lost. + * + * A DFU Target node was dropped from the receivers list. The Target node's + * @c status is set to reflect the reason for the failure. + * + * @param cli Firmware Update Client model instance. + * @param target DFU Target node that was lost. + */ + void (*lost_target)(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_dfu_target *target); +}; + +enum { + STATE_IDLE, + STATE_TRANSFER, + STATE_REFRESH, + STATE_VERIFIED, + STATE_APPLY, + STATE_APPLIED, + STATE_CONFIRM, + STATE_CANCEL, + STATE_SUSPENDED, +}; + +typedef struct { + sys_snode_t node; + uint8_t ttl; + uint8_t type; + uint8_t img_cnt; + uint32_t opcode; + void *params; + bt_mesh_dfu_img_cb_t img_cb; + struct bt_mesh_dfu_cli *dfu_cli; + struct bt_mesh_msg_ctx ctx; + int32_t timeout; + struct k_delayed_work timer; /* Time used to get response. Only for internal use. */ +} bt_mesh_dfu_cli_req_t; + +/** Firmware Update Client model instance. + * + * Should be initialized with @ref BLE_MESH_DFU_CLI_INIT. + */ +struct bt_mesh_dfu_cli { + /** Callback structure. */ + const struct bt_mesh_dfu_cli_cb *cb; + /** Underlying BLOB Transfer Client. */ + struct bt_mesh_blob_cli blob; + + /* runtime state */ + + uint32_t op; + struct bt_mesh_model *mod; + + struct { + const struct bt_mesh_dfu_slot *slot; + const struct bt_mesh_blob_io *io; + struct bt_mesh_blob_xfer blob; + uint8_t state; + uint8_t flags; + } xfer; + + bt_mesh_dfu_cli_req_t *req; +}; + +/** BLOB parameters for Firmware Update Client transfer: */ +struct bt_mesh_dfu_cli_xfer_blob_params { + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** Firmware Update Client transfer parameters: */ +struct bt_mesh_dfu_cli_xfer { + /** BLOB ID to use for this transfer, or 0 to set it randomly. */ + uint64_t blob_id; + /** DFU image slot to transfer. */ + const struct bt_mesh_dfu_slot *slot; + /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ + enum bt_mesh_blob_xfer_mode mode; + /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' + * capabilities before sending a firmware. + */ + const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params; +}; + +/** @brief Start distributing a DFU. + * + * Starts distribution of the firmware in the given slot to the list of DFU + * Target nodes in @c ctx. The transfer runs in the background, and its end is + * signalled through the @ref bt_mesh_dfu_cli_cb::ended callback. + * + * @note The BLOB Transfer Client transfer inputs @c targets list must point to a list of @ref + * bt_mesh_dfu_target nodes. + * + * @param cli Firmware Update Client model instance. + * @param inputs BLOB Transfer Client transfer inputs. + * @param io BLOB stream to read BLOB from. + * @param xfer Firmware Update Client transfer parameters. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer); + +/** @brief Suspend a DFU transfer. + * + * @param cli Firmware Update Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli); + +/** @brief Resume the suspended transfer. + * + * @param cli Firmware Update Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli); + +/** @brief Cancel a DFU transfer. + * + * Will cancel the ongoing DFU transfer, or the transfer on a specific Target + * node if @c ctx is valid. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context, or NULL to cancel the ongoing DFU transfer. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx); + +/** @brief Apply the completed DFU transfer. + * + * A transfer can only be applied after it has ended successfully. The Firmware + * Update Client's @c applied callback is called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli); + +/** @brief Confirm that the active transfer has been applied on the Target nodes. + * + * A transfer can only be confirmed after it has been applied. The Firmware Update + * Client's @c confirmed callback is called at the end of the confirm + * procedure. + * + * Target nodes that have reported the effect as @ref BLE_MESH_DFU_EFFECT_UNPROV + * are expected to not respond to the query, and will fail if they do. + * + * @param cli Firmware Update Client model instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli); + +/** @brief Get progress as a percentage of completion. + * + * @param cli Firmware Update Client model instance. + * + * @return The progress of the current transfer in percent, or 0 if no + * transfer is active. + */ +uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli); + +/** @brief Check whether a DFU transfer is in progress. + * + * @param cli Firmware Update Client model instance. + * + * @return true if the BLOB Transfer Client is currently participating in a transfer, + * false otherwise. + */ +bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli); + +/** @brief Perform a DFU image list request. + * + * Requests the full list of DFU images on a Target node, and iterates through + * them, calling the @c cb for every image. + * + * The DFU image list request can be used to determine which image index the + * Target node holds its different firmwares in. + * + * Waits for a response until the procedure timeout expires. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param cb Callback to call for each image index. + * @param cb_data Callback data to pass to @c cb. + * @param first_idx Index of the first requested imgs entry. + * @param max_count Max number of images to return. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t first_idx, uint8_t max_count); + +/** @brief Perform a metadata check for the given DFU image slot. + * + * The metadata check procedure allows the Firmware Update Client to check if a Target + * node will accept a transfer of this DFU image slot, and what the effect would be. + * + * Waits for a response until the procedure timeout expires. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param img_idx Target node's image index to check. + * @param metadata DFU image metadata to check for. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + struct net_buf_simple *metadata); + +/** @brief Get the status of a Target node. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx); + +/** @brief Get the current procedure timeout value. + * + * @return The configured procedure timeout. + */ +int32_t bt_mesh_dfu_cli_timeout_get(void); + +/** @brief Set the procedure timeout value. + * + * @param timeout The new procedure timeout. + */ +void bt_mesh_dfu_cli_timeout_set(int32_t timeout); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb; +extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFU_CLI_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h new file mode 100644 index 000000000000..baa4049a2bca --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_metadata Bluetooth Mesh Device Firmware Update (DFU) metadata + * @ingroup bt_mesh_dfu + * @{ + * @brief Common types and functions for the Bluetooth Mesh DFU metadata. + */ + +#ifndef _BLE_MESH_v11_DFU_METADATA_H__ +#define _BLE_MESH_v11_DFU_METADATA_H__ + +#include + +#include + +#include "mesh/types.h" +#include "mesh/utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Firmware version. */ +struct bt_mesh_dfu_metadata_fw_ver { + /** Firmware major version. */ + uint8_t major; + /** Firmware minor version. */ + uint8_t minor; + /** Firmware revision. */ + uint16_t revision; + /** Firmware build number. */ + uint32_t build_num; +}; + +/** Firmware core type. */ +enum bt_mesh_dfu_metadata_fw_core_type { + /** Application core. */ + BLE_MESH_DFU_FW_CORE_TYPE_APP = BIT(0), + /** Application-specific BLOB. */ + BLE_MESH_DFU_FW_CORE_TYPE_APP_SPECIFIC_BLOB = BIT(2), +}; + +/** Firmware metadata. */ +struct bt_mesh_dfu_metadata { + /** New firmware version. */ + struct bt_mesh_dfu_metadata_fw_ver fw_ver; + /** New firmware size. */ + uint32_t fw_size; + /** New firmware core type. */ + enum bt_mesh_dfu_metadata_fw_core_type fw_core_type; + /** Hash of incoming Composition Data. */ + uint32_t comp_hash; + /** New number of node elements. */ + uint16_t elems; + /** Application-specific data for new firmware. This field is optional. */ + uint8_t *user_data; + /** Length of the application-specific field. */ + uint32_t user_data_len; +}; + +/** @brief Decode a firmware metadata from a network buffer. + * + * @param buf Buffer containing a raw metadata to be decoded. + * @param metadata Pointer to a metadata structure to be filled. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, + struct bt_mesh_dfu_metadata *metadata); + +/** @brief Encode a firmware metadata into a network buffer. + * + * @param metadata Firmware metadata to be encoded. + * @param buf Buffer to store the encoded metadata. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, + struct net_buf_simple *buf); + +/** @brief Compute hash of the Composition Data state. + * + * The format of the Composition Data is defined in MshPRTv1.1: 4.2.2.1. + * + * @param buf Pointer to buffer holding Composition Data. + * @param key 128-bit key to be used in the hash computation. + * @param hash Pointer to a memory location to which the hash will be stored. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, uint32_t *hash); + +/** @brief Compute hash of the Composition Data Page 0 of this device. + * + * @param key 128-bit key to be used in the hash computation. + * @param hash Pointer to a memory location to which the hash will be stored. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFU_METADATA_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h new file mode 100644 index 000000000000..dc134fe07e01 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h @@ -0,0 +1,264 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_srv Firmware Update Server model + * @ingroup bt_mesh_dfu + * @{ + * @brief API for the Bluetooth Mesh Firmware Update Server model + */ + +#ifndef _BLE_MESH_v11_DFU_SRV_H__ +#define _BLE_MESH_v11_DFU_SRV_H__ + +#include "mesh/access.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfu_srv; + +/** + * + * @brief Initialization parameters for @ref bt_mesh_dfu_srv. + * + * @param _handlers DFU handler function structure. + * @param _imgs List of @ref bt_mesh_dfu_img managed by this Server. + * @param _img_count Number of DFU images managed by this Server. + */ +#define BLE_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ + { \ + .blob = { .cb = &_bt_mesh_dfu_srv_blob_cb }, .cb = _handlers, \ + .imgs = _imgs, .img_count = _img_count, \ + } + +/** + * + * @brief Firmware Update Server model entry. + * + * @param _srv Pointer to a @ref bt_mesh_dfu_srv instance. + */ +#define BT_MESH_MODEL_DFU_SRV(_srv) \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->blob), \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFU_SRV, _bt_mesh_dfu_srv_op, NULL, \ + _srv, &_bt_mesh_dfu_srv_cb) + +/** @brief Firmware Update Server event callbacks. */ +struct bt_mesh_dfu_srv_cb { + /** @brief Transfer check callback. + * + * The transfer check can be used to validate the incoming transfer + * before it starts. The contents of the metadata is implementation + * specific, and should contain all the information the application + * needs to determine whether this image should be accepted, and what + * the effect of the transfer would be. + * + * If applying the image will have an effect on the provisioning state + * of the mesh stack, this can be communicated through the @c effect + * return parameter. + * + * The metadata check can be performed both as part of starting a new + * transfer and as a separate procedure. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image the metadata check is performed on. + * @param metadata Image metadata. + * @param effect Return parameter for the image effect on the + * provisioning state of the mesh stack. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*check)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + enum bt_mesh_dfu_effect *effect); + + /** @brief Transfer start callback. + * + * Called when the Firmware Update Server is ready to start a new DFU transfer. + * The application must provide an initialized BLOB stream to be used + * during the DFU transfer. + * + * The following error codes are treated specially, and should be used + * to communicate these issues: + * - @c -ENOMEM: The device cannot fit this image. + * - @c -EBUSY: The application is temporarily unable to accept the + * transfer. + * - @c -EALREADY: The device has already received and verified this + * image, and there's no need to transfer it again. The Firmware Update model + * will skip the transfer phase, and mark the image as verified. + * + * This handler is mandatory. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param metadata Image metadata. + * @param io BLOB stream return parameter. Must be set to a + * valid BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code otherwise. Return + * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to + * the updater, other error codes are reported as internal + * errors. + */ + int (*start)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + const struct bt_mesh_blob_io **io); + + /** @brief Transfer end callback. + * + * This handler is optional. + * + * If the transfer is successful, the application should verify the + * firmware image, and call either @ref bt_mesh_dfu_srv_verified or + * @ref bt_mesh_dfu_srv_rejected depending on the outcome. + * + * If the transfer fails, the Firmware Update Server will be available for new + * transfers immediately after this function returns. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that failed the update. + * @param success Whether the DFU transfer was successful. + */ + void (*end)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, bool success); + + /** @brief Transfer recovery callback. + * + * If the device reboots in the middle of a transfer, the Firmware Update Server + * calls this function when the Bluetooth Mesh subsystem is started. + * + * This callback is optional, but transfers will not be recovered after + * a reboot without it. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param io BLOB stream return parameter. Must be set to a valid BLOB + * stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + const struct bt_mesh_blob_io **io); + + /** @brief Transfer apply callback. + * + * Called after a transfer has been validated, and the updater sends an + * apply message to the Target nodes. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that should be applied. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*apply)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img); +}; + +/** @brief Firmware Update Server instance. + * + * Should be initialized with @ref BLE_MESH_DFU_SRV_INIT. + */ +struct bt_mesh_dfu_srv { + /** Underlying BLOB Transfer Server. */ + struct bt_mesh_blob_srv blob; + /** Callback structure. */ + const struct bt_mesh_dfu_srv_cb *cb; + /** List of updatable images. */ + const struct bt_mesh_dfu_img *imgs; + /** Number of updatable images. */ + size_t img_count; + + /* Runtime state */ + const struct bt_mesh_model *mod; + struct { + /* Effect of transfer, @see bt_mesh_dfu_effect. */ + uint8_t effect; + /* Current phase, @see bt_mesh_dfu_phase. */ + uint8_t phase; + uint8_t ttl; + uint8_t idx; + uint16_t timeout_base; + uint16_t meta; + } update; +}; + +/** @brief Accept the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if the image is ready to be applied. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv); + +/** @brief Reject the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if one of the checks fail. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv); + +/** @brief Cancel the ongoing DFU transfer. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv); + +/** @brief Confirm that the received DFU transfer was applied. + * + * Should be called as a result of the @ref bt_mesh_dfu_srv_cb.apply callback. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv); + +/** @brief Check if the Firmware Update Server is busy processing a transfer. + * + * @param srv Firmware Update Server instance. + * + * @return true if a DFU procedure is in progress, false otherwise. + */ +bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv); + +/** @brief Get the progress of the current DFU procedure, in percent. + * + * @param srv Firmware Update Server instance. + * + * @return The current transfer progress in percent. + */ +uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb; +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_DFU_SRV_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h new file mode 100644 index 000000000000..29199360a4e1 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h @@ -0,0 +1,272 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_BLOB_H__ +#define _BLE_MESH_v11_BLOB_H__ + +#include +#include "mesh/types.h" +#include "mesh/utils.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" +#include "mesh_v1.1/mbt/blob.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob Bluetooth Mesh BLOB model API + * @ingroup bt_mesh + * @{ + */ + +#ifndef CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX +#define CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX 0 +#endif + +/** BLOB transfer mode. */ +enum bt_mesh_blob_xfer_mode { + /** No valid transfer mode. */ + BT_MESH_BLOB_XFER_MODE_NONE, + /** Push mode (Push BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PUSH, + /** Pull mode (Pull BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PULL, + /** Both modes are valid. */ + BT_MESH_BLOB_XFER_MODE_ALL, +}; + +/** Transfer phase. */ +enum bt_mesh_blob_xfer_phase { + /** The BLOB Transfer Server is awaiting configuration. */ + BT_MESH_BLOB_XFER_PHASE_INACTIVE, + /** The BLOB Transfer Server is ready to receive a BLOB transfer. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, + /** The BLOB Transfer Server is waiting for the next block of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, + /** The BLOB Transfer Server is waiting for the next chunk of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, + /** The BLOB was transferred successfully. */ + BT_MESH_BLOB_XFER_PHASE_COMPLETE, + /** The BLOB transfer is paused. */ + BT_MESH_BLOB_XFER_PHASE_SUSPENDED, +}; + +/** BLOB model status codes. */ +enum bt_mesh_blob_status { + /** The message was processed successfully. */ + BT_MESH_BLOB_SUCCESS, + /** The Block Number field value is not within the range of blocks being + * transferred. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM, + /** The block size is smaller than the size indicated by the Min Block + * Size Log state or is larger than the size indicated by the Max Block + * Size Log state. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, + /** The chunk size exceeds the size indicated by the Max Chunk Size + * state, or the number of chunks exceeds the number specified by the + * Max Total Chunks state. + */ + BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, + /** The operation cannot be performed while the server is in the current + * phase. + */ + BT_MESH_BLOB_ERR_WRONG_PHASE, + /** A parameter value in the message cannot be accepted. */ + BT_MESH_BLOB_ERR_INVALID_PARAM, + /** The message contains a BLOB ID value that is not expected. */ + BT_MESH_BLOB_ERR_WRONG_BLOB_ID, + /** There is not enough space available in memory to receive the BLOB. + */ + BT_MESH_BLOB_ERR_BLOB_TOO_LARGE, + /** The transfer mode is not supported by the BLOB Transfer Server + * model. + */ + BT_MESH_BLOB_ERR_UNSUPPORTED_MODE, + /** An internal error occurred on the node. */ + BT_MESH_BLOB_ERR_INTERNAL, + /** The requested information cannot be provided while the server is in + * the current phase. + */ + BT_MESH_BLOB_ERR_INFO_UNAVAILABLE, +}; + +/** BLOB transfer data block. */ +struct bt_mesh_blob_block { + /** Block size in bytes */ + size_t size; + /** Offset in bytes from the start of the BLOB. */ + off_t offset; + /** Block number */ + uint16_t number; + /** Number of chunks in block. */ + uint16_t chunk_count; + /** Bitmap of missing chunks. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, + 8)]; +}; + +/** BLOB data chunk. */ +struct bt_mesh_blob_chunk { + /** Offset of the chunk data from the start of the block. */ + off_t offset; + /** Chunk data size. */ + size_t size; + /** Chunk data. */ + uint8_t *data; +}; + +/** BLOB transfer. */ +struct bt_mesh_blob_xfer { + /** BLOB ID. */ + uint64_t id; + /** Total BLOB size in bytes. */ + size_t size; + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** BLOB stream interaction mode. */ +enum bt_mesh_blob_io_mode { + /** Read data from the stream. */ + BT_MESH_BLOB_READ, + /** Write data to the stream. */ + BT_MESH_BLOB_WRITE, +}; + +/** BLOB stream. */ +struct bt_mesh_blob_io { + /** @brief Open callback. + * + * Called when the reader is opened for reading. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param mode Direction of the stream (read/write). + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*open)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + enum bt_mesh_blob_io_mode mode); + + /** @brief Close callback. + * + * Called when the reader is closed. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + */ + void (*close)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer); + + /** @brief Block start callback. + * + * Called when a new block is opened for sending. Each block is only + * sent once, and are always sent in increasing order. The data chunks + * inside a single block may be requested out of order and multiple + * times. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that was started. + */ + int (*block_start)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); + + /** @brief Block end callback. + * + * Called when the current block has been transmitted in full. + * No data from this block will be requested again, and the application + * data associated with this block may be discarded. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that finished sending. + */ + void (*block_end)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); + + /** @brief Chunk data write callback. + * + * Used by the BLOB Transfer Server on incoming data. + * + * Each block is divided into chunks of data. This callback is called + * when a new chunk of data is received. Chunks may be received in + * any order within their block. + * + * If the callback returns successfully, this chunk will be marked as + * received, and will not be received again unless the block is + * restarted due to a transfer suspension. If the callback returns a + * non-zero value, the chunk remains unreceived, and the BLOB Transfer + * Client will attempt to resend it later. + * + * Note that the Client will only perform a limited number of attempts + * at delivering a chunk before dropping a Target node from the transfer. + * The number of retries performed by the Client is implementation + * specific. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Received chunk. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*wr)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); + + /** @brief Chunk data read callback. + * + * Used by the BLOB Transfer Client to fetch outgoing data. + * + * The Client calls the chunk data request callback to populate a chunk + * message going out to the Target nodes. The data request callback + * may be called out of order and multiple times for each offset, and + * cannot be used as an indication of progress. + * + * Returning a non-zero status code on the chunk data request callback + * results in termination of the transfer. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Chunk to get the data of. The buffer pointer to by the + * @c data member should be filled by the callback. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*rd)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_BLOB_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h new file mode 100644 index 000000000000..59b216937025 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h @@ -0,0 +1,467 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_BLOB_CLI_H_ +#define _BLE_MESH_v11_BLOB_CLI_H_ + +#include + +#include "mesh/access.h" +#include "mesh/utils.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" +#include "mesh_v1.1/mbt/blob.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob_cli Bluetooth Mesh BLOB Transfer Client model API + * @ingroup bt_mesh + * @{ + */ + +struct bt_mesh_blob_cli; + +/** + * + * @brief BLOB Transfer Client model Composition Data entry. + * + * @param _cli Pointer to a @ref bt_mesh_blob_cli instance. + */ +#define BT_MESH_MODEL_BLOB_CLI(_cli) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_BLOB_CLI, _bt_mesh_blob_cli_op, \ + NULL, _cli, &_bt_mesh_blob_cli_cb) + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +struct bt_mesh_blob_target_pull { + /** Timestamp when the Block Report Timeout Timer expires for this Target node. */ + int64_t block_report_timestamp; + + /** Missing chunks reported by this Target node. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; +}; + +/** BLOB Transfer Client Target node. */ +struct bt_mesh_blob_target { + /** Linked list node */ + sys_snode_t n; + + /** Target node address. */ + uint16_t addr; + + /** Target node's Pull mode context. + * Needs to be initialized when sending a BLOB in Pull mode. + */ + struct bt_mesh_blob_target_pull *pull; + + /** BLOB transfer status, see @ref bt_mesh_blob_status. */ + uint8_t status; + + uint8_t procedure_complete: 1, /* Procedure has been completed. */ + acked: 1, /* Message has been acknowledged. Not used when sending. */ + timedout: 1, /* Target node didn't respond after specified timeout. */ + skip: 1; /* Skip Target node from broadcast. */ +}; + +/** BLOB transfer information. + * + * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_INACTIVE, + * the fields below @c phase are not initialized. + * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, + * the fields below @c id are not initialized. + */ +struct bt_mesh_blob_xfer_info { + /** BLOB transfer status. */ + enum bt_mesh_blob_status status; + + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; + + /** BLOB transfer phase. */ + enum bt_mesh_blob_xfer_phase phase; + + /** BLOB ID. */ + uint64_t id; + + /** BLOB size in octets. */ + uint32_t size; + + /** Logarithmic representation of the block size. */ + uint8_t block_size_log; + + /** MTU size in octets. */ + uint16_t mtu_size; + + /** Bit field indicating blocks that were not received. */ + const uint8_t *missing_blocks; +}; + +/** BLOB Transfer Client transfer inputs. */ +struct bt_mesh_blob_cli_inputs { + /** Linked list of Target nodes. Each node should point to @ref + * bt_mesh_blob_target::n. + */ + sys_slist_t targets; + + /** AppKey index to send with. */ + uint16_t app_idx; + + /** Group address destination for the BLOB transfer, or @ref + * BLE_MESH_ADDR_UNASSIGNED to send every message to each Target + * node individually. + */ + uint16_t group; + + /** Time to live value of BLOB transfer messages. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** Transfer capabilities of a Target node. */ +struct bt_mesh_blob_cli_caps { + /** Max BLOB size. */ + size_t max_size; + + /** Logarithmic representation of the minimum block size. */ + uint8_t min_block_size_log; + + /** Logarithmic representation of the maximum block size. */ + uint8_t max_block_size_log; + + /** Max number of chunks per block. */ + uint16_t max_chunks; + + /** Max chunk size. */ + uint16_t max_chunk_size; + + /** Max MTU size. */ + uint16_t mtu_size; + + /** Supported transfer modes. */ + enum bt_mesh_blob_xfer_mode modes; +}; + +/** BLOB Transfer Client state. */ +enum bt_mesh_blob_cli_state { + /** No transfer is active. */ + BT_MESH_BLOB_CLI_STATE_NONE, + /** Retrieving transfer capabilities. */ + BT_MESH_BLOB_CLI_STATE_CAPS_GET, + /** Sending transfer start. */ + BT_MESH_BLOB_CLI_STATE_START, + /** Sending block start. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_START, + /** Sending block chunks. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_SEND, + /** Checking block status. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK, + /** Checking transfer status. */ + BT_MESH_BLOB_CLI_STATE_XFER_CHECK, + /** Cancelling transfer. */ + BT_MESH_BLOB_CLI_STATE_CANCEL, + /** Transfer is suspended. */ + BT_MESH_BLOB_CLI_STATE_SUSPENDED, + /** Checking transfer progress. */ + BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, +}; + +/** Event handler callbacks for the BLOB Transfer Client model. + * + * All handlers are optional. + */ +struct bt_mesh_blob_cli_cb { + /** @brief Capabilities retrieval completion callback. + * + * Called when the capabilities retrieval procedure completes, indicating that + * a common set of acceptable transfer parameters have been established + * for the given list of Target nodes. All compatible Target nodes have + * status code @ref BT_MESH_BLOB_SUCCESS. + * + * @param cli BLOB Transfer Client instance. + * @param caps Safe transfer capabilities if the transfer capabilities + * of at least one Target node has satisfied the Client, or NULL otherwise. + */ + void (*caps)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_caps *caps); + + /** @brief Target node loss callback. + * + * Called whenever a Target node has been lost due to some error in the + * transfer. Losing a Target node is not considered a fatal error for + * the Client until all Target nodes have been lost. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that was lost. + * @param reason Reason for the Target node loss. + */ + void (*lost_target)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason); + + /** @brief Transfer is suspended. + * + * Called when the transfer is suspended due to response timeout from all Target nodes. + * + * @param cli BLOB Transfer Client instance. + */ + void (*suspended)(struct bt_mesh_blob_cli *cli); + + /** @brief Transfer end callback. + * + * Called when the transfer ends. + * + * @param cli BLOB Transfer Client instance. + * @param xfer Completed transfer. + * @param success Status of the transfer. + * Is @c true if at least one Target + * node received the whole transfer. + */ + void (*end)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer, bool success); + + /** @brief Transfer progress callback + * + * The content of @c info is invalidated upon exit from the callback. + * Therefore it needs to be copied if it is planned to be used later. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that responded to the request. + * @param info BLOB transfer information. + */ + void (*xfer_progress)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + const struct bt_mesh_blob_xfer_info *info); + + /** @brief End of Get Transfer Progress procedure. + * + * Called when all Target nodes have responded or the procedure timed-out. + * + * @param cli BLOB Transfer Client instance. + */ + void (*xfer_progress_complete)(struct bt_mesh_blob_cli *cli); +}; + +/** @cond INTERNAL_HIDDEN */ +struct blob_cli_broadcast_ctx { + /** Called for every Target node in unicast mode, or once in case of multicast mode. */ + void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ + void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ + void (*next)(struct bt_mesh_blob_cli *cli); + /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before + * @ref blob_cli_broadcast_ctx::next is called. + */ + bool acked; + /** If true, the message is always sent in a unicast way. */ + bool force_unicast; + /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ + bool optional; + /** Set to true by the BLOB Transfer Client between blob_cli_broadcast + * and broadcast_complete calls. + */ + bool is_inited; + /* Defines a time in ms by which the broadcast API postpones sending the message to a next + * target or completing the broadcast. + */ + uint32_t post_send_delay_ms; +}; +/** INTERNAL_HIDDEN @endcond */ + +/** BLOB Transfer Client model instance. */ +struct bt_mesh_blob_cli { + /** Event handler callbacks */ + const struct bt_mesh_blob_cli_cb *cb; + + /* Runtime state */ + const struct bt_mesh_model *mod; + + struct { + struct bt_mesh_blob_target *target; + struct blob_cli_broadcast_ctx ctx; + struct k_work_delayable retry; + /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ + int64_t cli_timestamp; + struct k_work_delayable complete; + uint16_t pending; + uint8_t retries; + uint8_t sending : 1, + cancelled : 1; + } tx; + + const struct bt_mesh_blob_io *io; + const struct bt_mesh_blob_cli_inputs *inputs; + const struct bt_mesh_blob_xfer *xfer; + uint32_t chunk_interval_ms; + uint16_t block_count; + uint16_t chunk_idx; + uint16_t mtu_size; + enum bt_mesh_blob_cli_state state; + struct bt_mesh_blob_block block; + struct bt_mesh_blob_cli_caps caps; +}; + +/** @brief Retrieve transfer capabilities for a list of Target nodes. + * + * Queries the availability and capabilities of all Target nodes, producing a + * cumulative set of transfer capabilities for the Target nodes, and returning + * it through the @ref bt_mesh_blob_cli_cb::caps callback. + * + * Retrieving the capabilities may take several seconds, depending on the + * number of Target nodes and mesh network performance. The end of the procedure + * is indicated through the @ref bt_mesh_blob_cli_cb::caps callback. + * + * This procedure is not required, but strongly recommended as a + * preparation for a transfer to maximize performance and the chances of + * success. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs); + +/** @brief Perform a BLOB transfer. + * + * Starts sending the transfer to the Target nodes. Only Target nodes with a + * @c status of @ref BT_MESH_BLOB_SUCCESS will be considered. + * + * The transfer will keep going either until all Target nodes have been dropped, or + * the full BLOB has been sent. + * + * The BLOB transfer may take several minutes, depending on the number of + * Target nodes, size of the BLOB and mesh network performance. The end of the + * transfer is indicated through the @ref bt_mesh_blob_cli_cb::end callback. + * + * A Client only supports one transfer at the time. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * @param xfer Statically allocated transfer parameters. + * @param io BLOB stream to read the transfer from. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io); + +/** @brief Suspend the active transfer. + * + * @param cli BLOB Transfer Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli); + +/** @brief Resume the suspended transfer. + * + * @param cli BLOB Transfer Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli); + +/** @brief Cancel an ongoing transfer. + * + * @param cli BLOB Transfer Client instance. + */ +void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli); + +void bt_mesh_blob_cli_send_cancel(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer); + +/** @brief Get the progress of BLOB transfer. + * + * This function can only be used if the BLOB Transfer Client is currently + * not performing a BLOB transfer. + * To get progress of the active BLOB transfer, use the + * @ref bt_mesh_blob_cli_xfer_progress_active_get function. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs); + +/** @brief Get the current progress of the active transfer in percent. + * + * @param cli BLOB Transfer Client instance. + * + * @return The current transfer progress, or 0 if no transfer is active. + */ +uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli); + +/** @brief Get the current state of the BLOB Transfer Client. + * + * @param cli BLOB Transfer Client instance. + * + * @return true if the BLOB Transfer Client is currently participating in a transfer or + * retrieving the capabilities and false otherwise. + */ +bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli); + +/** @brief Set chunk sending interval in ms + * + * This function is optional, and can be used to define how fast chunks are sent in the BLOB Client + * Model. + * Without an added delay, for example a Bluetooth Mesh DFU can cause network blockage by + * constantly sending the next chunks, especially if the chunks are sent to group addresses or + * multiple unicast addresses. + * + * @note: Big intervals may cause timeouts. Increasing the @c timeout_base accordingly can + * circumvent this. + * + * @param cli BLOB Transfer Client instance. + * @param interval_ms the delay before each chunk is sent out in ms. + */ +void bt_mesh_blob_cli_set_chunk_interval_ms(struct bt_mesh_blob_cli *cli, uint32_t interval_ms); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb; +/** @endcond */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_BLOB_CLI_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h new file mode 100644 index 000000000000..c2a6e4876590 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h @@ -0,0 +1,229 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLE_MESH_v11_BLOB_SRV_H_ +#define _BLE_MESH_v11_BLOB_SRV_H_ + +#include "mesh/access.h" +#include "mesh/utils.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob_srv Bluetooth Mesh BLOB Transfer Server model API + * @ingroup bt_mesh + * @{ + */ + +struct bt_mesh_blob_srv; + +/** + * + * @brief Max number of blocks in a single transfer. + */ +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define BT_MESH_BLOB_BLOCKS_MAX \ + (DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_SIZE_MAX, CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN)) +#else +#define BT_MESH_BLOB_BLOCKS_MAX 1 +#endif + +/** + * + * @brief BLOB Transfer Server model composition data entry. + * + * @param _srv Pointer to a @ref bt_mesh_blob_srv instance. + */ +#define BT_MESH_MODEL_BLOB_SRV(_srv) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_BLOB_SRV, _bt_mesh_blob_srv_op, \ + NULL, _srv, &_bt_mesh_blob_srv_cb) + +/** @brief BLOB Transfer Server model event handlers. + * + * All callbacks are optional. + */ +struct bt_mesh_blob_srv_cb { + /** @brief Transfer start callback. + * + * Called when the transfer has started with the prepared BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param ctx Message context for the incoming start message. The + * entire transfer will be sent from the same source + * address. + * @param xfer Transfer parameters. + * + * @return 0 on success, or (negative) error code to reject the + * transfer. + */ + int (*start)(struct bt_mesh_blob_srv *srv, struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_blob_xfer *xfer); + + /** @brief Transfer end callback. + * + * Called when the transfer ends, either because it was cancelled, or + * because it finished successfully. A new transfer may be prepared. + * + * @note The transfer may end before it's started if the start + * parameters are invalid. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID of the cancelled transfer. + * @param success Whether the transfer was successful. + */ + void (*end)(struct bt_mesh_blob_srv *srv, uint64_t id, bool success); + + /** @brief Transfer suspended callback. + * + * Called if the Server timed out while waiting for a transfer packet. + * A suspended transfer may resume later from the start of the current + * block. Any received chunks in the current block should be discarded, + * they will be received again if the transfer resumes. + * + * The transfer will call @c resumed again when resuming. + * + * @note The BLOB Transfer Server does not run a timer in the suspended state, + * and it's up to the application to determine whether the + * transfer should be permanently cancelled. Without interaction, + * the transfer will be suspended indefinitely, and the BLOB Transfer + * Server will not accept any new transfers. + * + * @param srv BLOB Transfer Server instance. + */ + void (*suspended)(struct bt_mesh_blob_srv *srv); + + /** @brief Transfer resume callback. + * + * Called if the transfer is resumed after being suspended. + * + * @param srv BLOB Transfer Server instance. + */ + void (*resume)(struct bt_mesh_blob_srv *srv); + + /** @brief Transfer recovery callback. + * + * Called when the Bluetooth Mesh subsystem is started if the device is rebooted + * in the middle of a transfer. + * + * Transfers will not be resumed after a reboot if this callback is not + * defined. + * + * @param srv BLOB Transfer Server instance. + * @param xfer Transfer to resume. + * @param io BLOB stream return parameter. Must be set to a valid + * BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_blob_srv *srv, + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io); +}; + +/** @brief BLOB Transfer Server model instance. */ +struct bt_mesh_blob_srv { + /** Event handler callbacks. */ + const struct bt_mesh_blob_srv_cb *cb; + + /* Runtime state: */ + const struct bt_mesh_blob_io *io; + struct k_work_delayable rx_timeout; + struct bt_mesh_blob_block block; + const struct bt_mesh_model *mod; + enum bt_mesh_blob_xfer_phase phase; + + struct bt_mesh_blob_srv_state { + struct bt_mesh_blob_xfer xfer; + uint16_t cli; + uint16_t app_idx; + uint16_t timeout_base; + uint16_t mtu_size; + uint8_t ttl; + + /* Bitfield of pending blocks. */ + BLE_MESH_ATOMIC_DEFINE(blocks, BT_MESH_BLOB_BLOCKS_MAX); + } state; + + /* Pull mode (Pull BLOB Transfer Mode) behavior. */ + struct { + uint16_t chunk_idx; + struct k_work_delayable report; + } pull; +}; + +/** @brief Prepare BLOB Transfer Server for an incoming transfer. + * + * Before a BLOB Transfer Server can receive a transfer, the transfer must be prepared + * through some application level mechanism. The BLOB Transfer Server will only accept + * incoming transfers with a matching BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID to accept. + * @param io BLOB stream to write the incoming BLOB to. + * @param ttl Time to live value to use in responses to the BLOB Transfer Client. + * @param timeout_base Extra time for the Client to respond in addition to the + * base 10 seconds, in 10-second increments. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base); + +/** @brief Cancel the current BLOB transfer. + * + * Tells the BLOB Transfer Client to drop this device from the list of Targets for the + * current transfer. Note that the client may continue sending the transfer to + * other Targets. + * + * @param srv BLOB Transfer Server instance. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_blob_srv_cancel(struct bt_mesh_blob_srv *srv); + +/** @brief Get the current state of the BLOB Transfer Server. + * + * @param srv BLOB Transfer Server instance. + * + * @return true if the BLOB Transfer Server is currently participating in a transfer, + * false otherwise. + */ +bool bt_mesh_blob_srv_is_busy(const struct bt_mesh_blob_srv *srv); + +/** @brief Get the current progress of the active transfer in percent. + * + * @param srv BLOB Transfer Server instance. + * + * @return The current transfer progress, or 0 if no transfer is active. + */ +uint8_t bt_mesh_blob_srv_progress(const struct bt_mesh_blob_srv *srv); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_blob_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb; +/** @endcond */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_v11_BLOB_SRV_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h new file mode 100644 index 000000000000..c539219d9e75 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#if CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV + +#include "mesh/utils.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#define BT_MESH_BLOB_OP_XFER_GET BLE_MESH_MODEL_OP_2(0x83, 0x00) +#define BT_MESH_BLOB_OP_XFER_START BLE_MESH_MODEL_OP_2(0x83, 0x01) +#define BT_MESH_BLOB_OP_XFER_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x02) +#define BT_MESH_BLOB_OP_XFER_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x03) +#define BT_MESH_BLOB_OP_BLOCK_GET BLE_MESH_MODEL_OP_2(0x83, 0x05) +#define BT_MESH_BLOB_OP_BLOCK_START BLE_MESH_MODEL_OP_2(0x83, 0x04) +#define BT_MESH_BLOB_OP_CHUNK BLE_MESH_MODEL_OP_1(0x66) +#define BT_MESH_BLOB_OP_BLOCK_STATUS BLE_MESH_MODEL_OP_1(0x67) +#define BT_MESH_BLOB_OP_BLOCK_REPORT BLE_MESH_MODEL_OP_1(0x68) +#define BT_MESH_BLOB_OP_INFO_GET BLE_MESH_MODEL_OP_2(0x83, 0x06) +#define BT_MESH_BLOB_OP_INFO_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x07) + +#define BLOB_BLOCK_NOT_SET 0xffff + +#define BLOB_CHUNK_SDU_OVERHEAD \ + (BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK) + 2 + BLE_MESH_MIC_SHORT) + +#define BLOB_CHUNK_SIZE_MAX(sdu_max) ((sdu_max) - BLOB_CHUNK_SDU_OVERHEAD) +#define BLOB_CHUNK_SDU_LEN(chunk_size) (BLOB_CHUNK_SDU_OVERHEAD + (chunk_size)) + +#if CONFIG_BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BLE_MESH_RX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BLE_MESH_RX_SDU_MAX) +#define BLOB_RX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BLE_MESH_RX_SDU_MAX) +#else +#define BLOB_RX_CHUNK_SIZE CONFIG_BLE_MESH_RX_BLOB_CHUNK_SIZE +#endif + +#if CONFIG_BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BLE_MESH_TX_SDU_MAX) +#define BLOB_TX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BLE_MESH_TX_SDU_MAX) +#else +#define BLOB_TX_CHUNK_SIZE CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE +#endif + +/* Utility macros for calculating log2 of a number at compile time. + * Used to determine the log2 representation of the block size, which + * is configured as a raw number, but encoded as log2. + * + * The macros expand to a series of ternary expressions, effectively + * searching through power of twos until a match is found. + * According to MshMBTv1.0, the block size cannot be larger than 2^20, + * so we'll stop the search at 20. + */ +#define _BLOB_LOG_2_CEIL(l, x) ((x) <= (1U << l)) ? l : +#define _BLOB_LOG_2_FLOOR(l, x) ((x) < (1U << (l + 1))) ? l : + +#define BLOB_BLOCK_SIZE_LOG_CEIL(x) (LISTIFY(20, _BLOB_LOG_2_CEIL, (), x) 20) +#define BLOB_BLOCK_SIZE_LOG_FLOOR(x) (LISTIFY(20, _BLOB_LOG_2_FLOOR, (), x) 20) + +/* Log2 representation of the minimum block size */ +#define BLOB_BLOCK_SIZE_LOG_MIN BLOB_BLOCK_SIZE_LOG_CEIL(CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN) +/* Log2 representation of the maximum block size */ +#define BLOB_BLOCK_SIZE_LOG_MAX BLOB_BLOCK_SIZE_LOG_FLOOR(CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MAX) + +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN ( \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#else +#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN sizeof(((struct bt_mesh_blob_srv *)0)->block.missing) +#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + sizeof(((struct bt_mesh_blob_srv *)0)->block.missing)) +#endif + +#define BLOB_XFER_STATUS_MSG_MAXLEN (17 + sizeof(((struct bt_mesh_blob_srv *)0)->state.blocks)) + +enum bt_mesh_blob_chunks_missing { + BT_MESH_BLOB_CHUNKS_MISSING_ALL, + BT_MESH_BLOB_CHUNKS_MISSING_NONE, + BT_MESH_BLOB_CHUNKS_MISSING_SOME, + BT_MESH_BLOB_CHUNKS_MISSING_ENCODED, +}; + +static inline size_t blob_block_size(size_t xfer_size, uint8_t block_size_log, + uint32_t idx) +{ + if (((idx + 1U) << block_size_log) <= xfer_size) { + return (1U << block_size_log); + } + + return xfer_size & BIT_MASK(block_size_log); +} + +static inline void blob_chunk_missing_set(uint8_t *missing_chunks, + int idx, bool missing) +{ + WRITE_BIT(missing_chunks[idx / 8], idx % 8, missing); +} + +static inline bool +blob_chunk_missing_get(const uint8_t *missing_chunks, int idx) +{ + return !!(missing_chunks[idx / 8] & BIT(idx % 8)); +} + +static inline void blob_chunk_missing_set_all(struct bt_mesh_blob_block *block) +{ + size_t bytes = block->chunk_count / 8; + + memset(block->missing, 0xff, bytes); + if (block->chunk_count % 8) { + block->missing[bytes] = BIT_MASK(block->chunk_count % 8); + } +} + +static inline void blob_chunk_missing_set_none(struct bt_mesh_blob_block *block) +{ + memset(block->missing, 0, sizeof(block->missing)); +} + +#if CONFIG_BLE_MESH_BLOB_CLI +/** @brief Perform a message broadcast to all BLOB Transfer Client Target nodes. + * + * Will send to a group or each Target node individually, repeating until + * all Target nodes have responded or the retry time has run out. + * + * @param cli BLOB Transfer Client instance + * @param ctx Broadcast context + */ +void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, + const struct blob_cli_broadcast_ctx *ctx); + +/** @brief Register that a Target node responded to a broadcast. + * + * @param cli BLOB Transfer Client instance + * @param target Target node that responded. + */ +void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target); + +/** @brief Notify the BLOB Transfer Client that the requested transmission is complete. + * + * Should be called once for each call to the @ref blob_cli_broadcast_ctx.send + * callback. + * + * @param cli BLOB Transfer Client instance. + */ +void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli); + +/** @brief Aborts any ongoing BLOB Transfer Client operations. + * + * @param cli BLOB Transfer Client instance. + */ +void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli); +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#endif /* CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c new file mode 100644 index 000000000000..9132829a2336 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c @@ -0,0 +1,1693 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "blob.h" +#include "net.h" +#include "transport.h" +#include "mesh/common.h" +#include "mesh/slist.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh/buf.h" + +#if CONFIG_BLE_MESH_BLOB_CLI + +#define TARGETS_FOR_EACH(cli, target) \ + SYS_SLIST_FOR_EACH_CONTAINER((sys_slist_t *)&(cli)->inputs->targets, \ + target, n) + +/* The Maximum BLOB Poll Interval - T_MBPI */ +#define BLOB_POLL_TIME_MAX_SECS 30 + +#define CLIENT_TIMEOUT_MSEC(cli) (10 * MSEC_PER_SEC * (cli->inputs->timeout_base + 2) + \ + 100 * cli->inputs->ttl) +#define BLOCK_REPORT_TIME_MSEC ((BLOB_POLL_TIME_MAX_SECS * 2 + 7) * 1000) + +/* BLOB Client is running Send Data State Machine from section 6.2.4.2. */ +#define SENDING_CHUNKS_IN_PULL_MODE(cli) ((cli)->state == BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && \ + (cli)->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) +#define UNICAST_MODE(cli) ((cli)->inputs->group == BLE_MESH_ADDR_UNASSIGNED || \ + (cli)->tx.ctx.force_unicast) + +_Static_assert((BLOB_XFER_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum incoming SDU size."); + +_Static_assert((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_RX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum incoming SDU " + "size."); + +_Static_assert((BLOB_BLOCK_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum incoming SDU size."); + +NET_BUF_SIMPLE_DEFINE_STATIC(chunk_buf, BLE_MESH_TX_SDU_MAX); + +struct block_status { + enum bt_mesh_blob_status status; + enum bt_mesh_blob_chunks_missing missing; + struct bt_mesh_blob_block block; +}; + +static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target **current); +static void transfer_cancel(struct bt_mesh_blob_cli *cli); + +static void start_retry_timer(struct bt_mesh_blob_cli *cli) +{ + k_timeout_t next_timeout; + + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + int64_t next_timeout_ms = cli->tx.cli_timestamp; + struct bt_mesh_blob_target *target = NULL; + + TARGETS_FOR_EACH(cli, target) { + if (!target->procedure_complete && + target->status == BT_MESH_BLOB_SUCCESS && + target->pull->block_report_timestamp < next_timeout_ms) { + next_timeout_ms = target->pull->block_report_timestamp; + } + } + + /* cli_timestamp and block_report_timestamp represent absolute time, while + * k_work_* functions use relative time. + */ + next_timeout_ms -= k_uptime_get(); + next_timeout = next_timeout_ms <= 0 ? K_NO_WAIT : K_MSEC(next_timeout_ms); + } else { + next_timeout = K_MSEC(CLIENT_TIMEOUT_MSEC(cli) / + CONFIG_BLE_MESH_BLOB_CLI_BLOCK_RETRIES); + } + + (void)k_work_reschedule(&cli->tx.retry, next_timeout); +} + +static void cli_state_reset(struct bt_mesh_blob_cli *cli) +{ + k_work_cancel_delayable(&cli->tx.retry); + cli->xfer = NULL; + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + cli->tx.ctx.is_inited = 0; + cli->tx.cli_timestamp = 0ll; + cli->tx.sending = 0; +} + +static struct bt_mesh_blob_target *target_get(struct bt_mesh_blob_cli *cli, + uint16_t addr) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->addr == addr) { + return target; + } + } + + BT_ERR("Unknown target 0x%04x", addr); + return NULL; +} + +static void target_drop(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason) +{ + BT_WARN("Dropping 0x%04x: %u", target->addr, reason); + + target->status = reason; + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target, reason); + } +} + +static uint32_t targets_reset(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + uint32_t count = 0; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + target->acked = 0U; + count++; + } + } + + return count; +} + +static bool targets_active(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + return true; + } + } + + return false; +} + +static bool targets_timedout(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + return true; + } + } + + return false; +} + +static int io_open(struct bt_mesh_blob_cli *cli) +{ + if (!cli->io->open) { + return 0; + } + + return cli->io->open(cli->io, cli->xfer, BT_MESH_BLOB_READ); +} + +static void io_close(struct bt_mesh_blob_cli *cli) +{ + if (!cli->io->close) { + return; + } + + cli->io->close(cli->io, cli->xfer); +} + +static uint16_t next_missing_chunk(struct bt_mesh_blob_cli *cli, + const uint8_t *missing_chunks, + uint16_t idx) +{ + do { + if (blob_chunk_missing_get(missing_chunks, idx)) { + break; + } + } while (++idx < cli->block.chunk_count); + + return idx; +} + +/* Used in Pull mode to collect all missing chunks from each target in cli->block.missing. */ +static void update_missing_chunks(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + memset(cli->block.missing, 0, sizeof(cli->block.missing)); + + TARGETS_FOR_EACH(cli, target) { + if (target->procedure_complete || target->timedout) { + continue; + } + + for (size_t idx = 0; idx < cli->block.chunk_count; idx++) { + bool missing = blob_chunk_missing_get(cli->block.missing, idx) || + blob_chunk_missing_get(target->pull->missing, idx); + blob_chunk_missing_set(cli->block.missing, idx, missing); + } + } +} + +static inline size_t chunk_size(const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + uint16_t chunk_idx) +{ + if ((chunk_idx == block->chunk_count - 1) && + (block->size % xfer->chunk_size)) { + return block->size % xfer->chunk_size; + } + + return xfer->chunk_size; +} + +static int chunk_idx_decode(struct net_buf_simple *buf) +{ + uint16_t data; + uint8_t byte; + + if (buf->len == 0) { + return -EINVAL; + } + + byte = net_buf_simple_pull_u8(buf); + + /* utf-8 decoding */ + if ((byte & 0xf0) == 0xe0) { /* 0x800 - 0xffff */ + if (buf->len < 2) { + return -EINVAL; + } + + data = (byte & 0x0f) << 12; + data |= (net_buf_simple_pull_u8(buf) & 0x3f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else if ((byte & 0xe0) == 0xc0) { /* 0x80 - 0x7ff */ + if (buf->len < 1) { + return -EINVAL; + } + + data = (byte & 0x1f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else { /* 0x00 - 0x7f */ + data = byte & 0x7f; + } + + return data; +} + +static void block_set(struct bt_mesh_blob_cli *cli, uint16_t block_idx) +{ + cli->block.number = block_idx; + cli->block.offset = block_idx * (1UL << cli->xfer->block_size_log); + cli->block.size = blob_block_size(cli->xfer->size, cli->xfer->block_size_log, + block_idx); + cli->block.chunk_count = + DIV_ROUND_UP(cli->block.size, cli->xfer->chunk_size); + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set_all(&cli->block); + } else { + struct bt_mesh_blob_target *target; + + /* In pull mode, the server will tell us which blocks are missing. */ + memset(cli->block.missing, 0, sizeof(cli->block.missing)); + + TARGETS_FOR_EACH(cli, target) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + } + } + + BT_DBG("%u size: %u chunks: %u", block_idx, cli->block.size, + cli->block.chunk_count); +} + +static void suspend(struct bt_mesh_blob_cli *cli) +{ + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } +} + +static void end(struct bt_mesh_blob_cli *cli, bool success) +{ + const struct bt_mesh_blob_xfer *xfer = cli->xfer; + + BT_DBG("%u", success); + + io_close(cli); + cli_state_reset(cli); + if (cli->cb && cli->cb->end) { + cli->cb->end(cli, xfer, success); + } +} + +static enum bt_mesh_blob_status caps_adjust(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_caps *in) +{ + if (!(in->modes & cli->caps.modes)) { + return BT_MESH_BLOB_ERR_UNSUPPORTED_MODE; + } + + if ((in->min_block_size_log > cli->caps.max_block_size_log) || + (in->max_block_size_log < cli->caps.min_block_size_log)) { + return BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + } + + cli->caps.min_block_size_log = + MAX(cli->caps.min_block_size_log, in->min_block_size_log); + cli->caps.max_block_size_log = + MIN(cli->caps.max_block_size_log, in->max_block_size_log); + cli->caps.max_chunks = MIN(cli->caps.max_chunks, in->max_chunks); + cli->caps.mtu_size = MIN(cli->caps.mtu_size, in->mtu_size); + cli->caps.max_chunk_size = MIN(cli->caps.max_chunk_size, in->max_chunk_size); + cli->caps.modes &= in->modes; + cli->caps.max_size = MIN(cli->caps.max_size, in->max_size); + + return BT_MESH_BLOB_SUCCESS; +} + +/******************************************************************************* + * TX State machine + * + * All messages in the transfer are going out to all the targets, either through + * group messaging or directly to each. The TX state machine implements this + * pattern for the transfer state machine to use. It will send the messages to + * all devices (through the group or directly), repeating until it receives a + * response from each device, or the attempts run out. Messages may also be + * marked as unacked if they require no response. + ******************************************************************************/ + +static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target **current) +{ + if (*current) { + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } else { + *current = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *)&cli->inputs->targets, *current, n); + } + + while (*current) { + if ((*current)->acked || (*current)->procedure_complete || + (*current)->status != BT_MESH_BLOB_SUCCESS || (*current)->timedout || + (*current)->skip) { + goto next; + } + + if (SENDING_CHUNKS_IN_PULL_MODE(cli) && + (k_uptime_get() < (*current)->pull->block_report_timestamp || + !blob_chunk_missing_get((*current)->pull->missing, cli->chunk_idx))) { + /* Skip targets that didn't time out or timed out, but confirmed + * the currently transmitted chunk (cli->chunk_idx). + */ + goto next; + } + + break; + +next: + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } + + return *current; +} + +static void send(struct bt_mesh_blob_cli *cli) +{ + cli->tx.sending = 1U; + if (UNICAST_MODE(cli)) { + cli->tx.ctx.send(cli, cli->tx.target->addr); + } else { + cli->tx.ctx.send(cli, cli->inputs->group); + } +} + +static void broadcast_complete(struct bt_mesh_blob_cli *cli) +{ + BT_DBG("%s", cli->tx.cancelled ? "cancelling" : "continuing"); + + cli->tx.ctx.is_inited = 0; + k_work_cancel_delayable(&cli->tx.retry); + + if (cli->tx.cancelled) { + transfer_cancel(cli); + } else { + __ASSERT(cli->tx.ctx.next, "No next callback"); + cli->tx.ctx.next(cli); + } +} + +static void tx_complete(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_blob_cli *cli = CONTAINER_OF(dwork, struct bt_mesh_blob_cli, tx.complete); + + if (!cli->tx.ctx.is_inited || !cli->tx.sending) { + return; + } + + cli->tx.sending = 0U; + + if (cli->tx.cancelled) { + broadcast_complete(cli); + return; + } + + if (cli->tx.ctx.send_complete) { + cli->tx.ctx.send_complete(cli, cli->tx.target->addr); + } + + if (UNICAST_MODE(cli) && next_target(cli, &cli->tx.target)) { + send(cli); + return; + } + + if (cli->tx.ctx.acked && cli->tx.pending) { + start_retry_timer(cli); + return; + } + + broadcast_complete(cli); +} + +static void drop_remaining_targets(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + BT_DBG(""); + + cli->tx.pending = 0; + + TARGETS_FOR_EACH(cli, target) { + if (!target->acked && !target->timedout && !target->procedure_complete && + !target->skip) { + target->timedout = 1U; + target_drop(cli, target, BT_MESH_BLOB_ERR_INTERNAL); + } + } + + /* Update missing chunks to exclude chunks from dropped targets. */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + update_missing_chunks(cli); + } +} + +static void retry_timeout(struct k_work *work) +{ + struct bt_mesh_blob_cli *cli = + CONTAINER_OF(work, struct bt_mesh_blob_cli, tx.retry.work); + + /* When sending chunks in Pull mode, timeout is handled differently. Client will drop all + * non-responsive servers by cli_timestamp. By calling broadcast_complete(), client will + * either retransmit the missing chunks (if any), or proceed to the next block, or suspend + * the transfer if all targets timed out. All this is handled in block_check_end(). + * Retry logic for all other procedures in Pull mode is handled as in Push mode. + */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (k_uptime_get() >= cli->tx.cli_timestamp) { + BT_DBG("Transfer timed out."); + + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } + } + + broadcast_complete(cli); + return; + } + + BT_DBG("%u", cli->tx.retries); + + cli->tx.retries--; + cli->tx.target = NULL; + + __ASSERT(!cli->tx.sending, "still sending"); + __ASSERT(cli->tx.ctx.is_inited, "ctx is not initialized"); + + if (!cli->tx.retries) { + BT_DBG("Transfer timed out."); + + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } + + broadcast_complete(cli); + return; + } + + if (!cli->tx.ctx.acked || !next_target(cli, &cli->tx.target) || cli->tx.cancelled) { + broadcast_complete(cli); + return; + } + + send(cli); +} + +void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, + const struct blob_cli_broadcast_ctx *ctx) +{ + if (cli->tx.ctx.is_inited || cli->tx.sending) { + BT_ERR("BLOB cli busy"); + return; + } + + cli->tx.cancelled = 0U; + cli->tx.retries = CONFIG_BLE_MESH_BLOB_CLI_BLOCK_RETRIES; + cli->tx.ctx = *ctx; + cli->tx.ctx.is_inited = 1U; + + cli->tx.pending = targets_reset(cli); + + BT_DBG("%u targets", cli->tx.pending); + + cli->tx.target = NULL; + if (!next_target(cli, &cli->tx.target)) { + BT_DBG("No active targets"); + broadcast_complete(cli); + return; + } + + send(cli); +} + +void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli) +{ + k_work_schedule(&cli->tx.complete, K_MSEC(cli->tx.ctx.post_send_delay_ms)); +} + +void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target) +{ + if (target->acked) { + return; + } + + BT_DBG("0x%04x, pending: %d", target->addr, cli->tx.pending); + + target->acked = 1U; + + if (!--cli->tx.pending && !cli->tx.sending) { + broadcast_complete(cli); + } +} + +void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli) +{ + if (!cli->tx.ctx.is_inited) { + return; + } + + if ((cli)->state >= BT_MESH_BLOB_CLI_STATE_START) { + io_close(cli); + } + + cli_state_reset(cli); +} + +static void send_start(uint16_t duration, int err, void *cb_data); +static void send_end(int err, void *user_data); + +static int tx(struct bt_mesh_blob_cli *cli, uint16_t addr, + struct net_buf_simple *buf) +{ + static const struct bt_mesh_send_cb end_cb = { + .start = send_start, + .end = send_end, + }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = cli->inputs->app_idx, + .addr = addr, + .send_ttl = cli->inputs->ttl, + }; + int err; + + err = bt_mesh_model_send((struct bt_mesh_model *)cli->mod, &ctx, buf, &end_cb, cli); + if (err) { + BT_ERR("Send err: %d", err); + send_end(err, cli); + return err; + } + + return 0; +} + +static void send_start(uint16_t duration, int err, void *cb_data) +{ + if (err) { + BT_ERR("TX Start failed: %d", err); + send_end(err, cb_data); + } +} + +static void send_end(int err, void *user_data) +{ + struct bt_mesh_blob_cli *cli = user_data; + + if (!cli->tx.ctx.is_inited) { + return; + } + + blob_cli_broadcast_tx_complete(cli); +} + +/******************************************************************************* + * TX + ******************************************************************************/ + +static void info_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_INFO_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_INFO_GET); + + tx(cli, dst, &buf); +} + +static void xfer_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_START, 16); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_START); + net_buf_simple_add_u8(&buf, cli->xfer->mode << 6); + net_buf_simple_add_le64(&buf, cli->xfer->id); + net_buf_simple_add_le32(&buf, cli->xfer->size); + net_buf_simple_add_u8(&buf, cli->xfer->block_size_log); + net_buf_simple_add_le16(&buf, BLE_MESH_TX_SDU_MAX); + + tx(cli, dst, &buf); +} + +static void xfer_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_GET); + + tx(cli, dst, &buf); +} + +static void xfer_cancel_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_CANCEL, 8); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_CANCEL); + net_buf_simple_add_le64(&buf, cli->xfer->id); + + tx(cli, dst, &buf); +} + +static void block_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_START, 4); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_START); + net_buf_simple_add_le16(&buf, cli->block.number); + net_buf_simple_add_le16(&buf, cli->xfer->chunk_size); + + tx(cli, dst, &buf); +} + +static void chunk_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + struct bt_mesh_blob_chunk chunk; + int err; + + BT_DBG("Chunk will send to 0x%04x", dst); + + /* Changed by Espressif: + * Use static chunk buf to avoid taking up large stack space */ + bt_mesh_model_msg_init(&chunk_buf, BT_MESH_BLOB_OP_CHUNK); + net_buf_simple_add_le16(&chunk_buf, cli->chunk_idx); + + chunk.size = chunk_size(cli->xfer, &cli->block, cli->chunk_idx); + chunk.offset = cli->xfer->chunk_size * cli->chunk_idx; + chunk.data = net_buf_simple_add(&chunk_buf, chunk.size); + + err = cli->io->rd(cli->io, cli->xfer, &cli->block, &chunk); + if (err || cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + bt_mesh_blob_cli_cancel(cli); + return; + } + + tx(cli, dst, &chunk_buf); +} + +static void block_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_GET); + + tx(cli, dst, &buf); +} + +/************************************************************************************************** + * State machine + * + * The BLOB Client state machine walks through the steps in the BLOB transfer in the following + * fashion: + * + * .---------------------------------------. + * V | + * xfer_start -> block_set -> block_start -> chunk_send -> chunk_send_end | + * A | | + * | V | + * | [more missing chunks?]-----[Yes]-----+ + * | | | + * | [No] | + * | | | + * | V | + * | [mode?] | + * | .---[Push]---' '---[Pull]---. | + * | | | | + * | V V | + * | block_check block_report_wait | + * | | | | + * | '-----------. .-------------' | + * | | | | + * | V V | + * | block_check_end | + * | | | + * | V | + * | [block completed?]------[No]------' + * | | + * | [Yes] + * | | + * | V + * '-------------------[No]------------[last block sent?] + * | + * [Yes] + * | + * V + * confirm_transfer + * | + * V + * transfer_complete + * + * In each state, the Client transmits a message to all target nodes. In each state, except when + * sending chunks (chunk_send), the Client expects a response from all target nodes, before + * proceeding to the next state. + * + * When a target node responds, the Client calls @ref blob_cli_broadcast_rsp for the corresponding + * target. Once all target nodes has responded, the Client proceeds to the next state. + * + * When sending chunks in Push mode, the Client will proceed to the next state (block_check) after + * transmitting all missing chunks. In the block_check state, the Client will request a block status + * from all target nodes. If any targets have missing chunks, the Client will resend them. + * + * When sending chunks in Pull mode, the Client addresses each target node individually using + * @ref bt_mesh_blob_target_pull structure. The Client uses @ref bt_mesh_blob_cli::block::missing + * to keep all missing chunks for the current block. Missing chunks for an individual target + * is kept in @ref bt_mesh_blob_target_pull::missing. The Client uses @ref + * bt_mesh_blob_target_pull::block_report_timeout to decide if it can send a chunk to this target. + * + * After sending all reported missing chunks to each target, the Client updates + * @ref bt_mesh_blob_target_pull::block_report_timestamp value for every target individually in + * chunk_tx_complete. The Client then proceeds to block_report_wait state and uses the earliest of + * all block_report_timestamp and cli_timestamp to schedule the retry timer. When the retry + * timer expires, the Client proceeds to the block_check_end state. + * + * In Pull mode, target nodes send a Partial Block Report message to the Client to inform about + * missing chunks. The Client doesn't control when these messages are sent by target nodes, and + * therefore it can't use @ref blob_cli_broadcast_rsp when it receives them. When the Client + * receives the Partial Block Report message, it updates missing chunks, resets + * block_report_timestamp, and explicitly calls @ref broadcast_complete to proceed to + * block_check_end state. + * + **************************************************************************************************/ +static void caps_collected(struct bt_mesh_blob_cli *cli); +static void block_start(struct bt_mesh_blob_cli *cli); +static void chunk_send(struct bt_mesh_blob_cli *cli); +static void block_check(struct bt_mesh_blob_cli *cli); +static void block_check_end(struct bt_mesh_blob_cli *cli); +static void block_report_wait(struct bt_mesh_blob_cli *cli); +static void chunk_send_end(struct bt_mesh_blob_cli *cli); +static void confirm_transfer(struct bt_mesh_blob_cli *cli); +static void transfer_complete(struct bt_mesh_blob_cli *cli); + +static void caps_get(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = info_get_tx, + .next = caps_collected, + .acked = true, + }; + + cli->state = BT_MESH_BLOB_CLI_STATE_CAPS_GET; + blob_cli_broadcast(cli, &ctx); +} + +static void caps_collected(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + bool success = false; + + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + + cli_state_reset(cli); + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + success = true; + break; + } + } + + while (success && + (1UL << cli->caps.max_block_size_log) > + (cli->caps.max_chunk_size * cli->caps.max_chunks)) { + cli->caps.max_block_size_log--; + } + + if (cli->cb && cli->cb->caps) { + cli->cb->caps(cli, success ? &cli->caps : NULL); + } +} + +static int xfer_start(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_start_tx, + .next = block_start, + .acked = true, + }; + int err; + + err = io_open(cli); + if (err) { + return -EIO; + } + + cli->state = BT_MESH_BLOB_CLI_STATE_START; + + blob_cli_broadcast(cli, &ctx); + return 0; +} + +static void block_start(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = block_start_tx, + .next = chunk_send, + .acked = true, + }; + struct bt_mesh_blob_target *target; + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + BT_DBG("%u (%u chunks, %u/%u)", cli->block.number, + cli->block.chunk_count, cli->block.number + 1, cli->block_count); + + cli->chunk_idx = 0; + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_START; + /* Client Timeout Timer in Send Data State Machine is initialized initially after + * transmitting the first bunch of chunks (see block_report_wait()). Next time it will be + * updated after every Partial Block Report message. + */ + cli->tx.cli_timestamp = 0ll; + + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + target->pull->block_report_timestamp = 0ll; + } + } + + if (cli->io->block_start) { + cli->io->block_start(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } + + blob_cli_broadcast(cli, &ctx); +} + +static void chunk_tx_complete(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + if (cli->xfer->mode != BT_MESH_BLOB_XFER_MODE_PULL) { + return; + } + + /* Update Block Report Timer individually for each target after sending out the last chunk + * in current iteration. + */ + uint16_t chunk_idx = next_missing_chunk(cli, cli->tx.target->pull->missing, + cli->chunk_idx + 1); + if (chunk_idx < cli->block.chunk_count) { + /* Will send more chunks to this target in this iteration. */ + return; + } + + /* This was the last chunk sent for this target. Now start the Block Report Timeout Timer. + */ + struct bt_mesh_blob_target *target; + int64_t timestamp = k_uptime_get() + BLOCK_REPORT_TIME_MSEC; + + if (!UNICAST_MODE(cli)) { + /* If using group addressing, reset timestamp for all targets after all chunks are + * sent to the group address + */ + TARGETS_FOR_EACH(cli, target) { + target->pull->block_report_timestamp = timestamp; + } + return; + } + + cli->tx.target->pull->block_report_timestamp = timestamp; +} + +static void chunk_send(struct bt_mesh_blob_cli *cli) +{ + struct blob_cli_broadcast_ctx ctx = { + .send = chunk_tx, + .next = chunk_send_end, + .acked = false, + .post_send_delay_ms = cli->chunk_interval_ms, + }; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + ctx.send_complete = chunk_tx_complete; + } + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + BT_DBG("%u / %u size: %u", cli->chunk_idx + 1, cli->block.chunk_count, + chunk_size(cli->xfer, &cli->block, cli->chunk_idx)); + + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_SEND; + blob_cli_broadcast(cli, &ctx); +} + +static void chunk_send_end(struct bt_mesh_blob_cli *cli) +{ + /* In pull mode, the partial block reports are used to confirm which + * chunks have been received, while in push mode, we just assume that a + * sent chunk has been received. + */ + + BT_DBG("A Chunk sent finished"); + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set(cli->block.missing, cli->chunk_idx, false); + } + + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, cli->chunk_idx + 1); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + block_check(cli); + } else { + block_report_wait(cli); + } +} + +/* The block checking pair(block_check - block_check_end) + * is relevant only for Push mode. + */ +static void block_check(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = block_get_tx, + .next = block_check_end, + .acked = true, + }; + + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK; + + BT_DBG(""); + + blob_cli_broadcast(cli, &ctx); +} + +static void block_report_wait(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .next = block_check_end, + .acked = false, + }; + + /* Check if all servers already confirmed all chunks during the transmission. */ + if (next_missing_chunk(cli, cli->block.missing, 0) >= cli->block.chunk_count) { + block_check_end(cli); + return; + } + + BT_DBG("Waiting for partial block report..."); + cli->tx.ctx = ctx; + + /* Start Client Timeout Timer in Send Data sub-procedure for the first time. */ + if (!cli->tx.cli_timestamp) { + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + } + + start_retry_timer(cli); +} + +static void block_check_end(struct bt_mesh_blob_cli *cli) +{ + BT_DBG(""); + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, 0); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } + + BT_DBG("No more missing chunks for block %u", cli->block.number); + + if (cli->io->block_end) { + cli->io->block_end(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } + + if (cli->block.number == cli->block_count - 1) { + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; + } + + confirm_transfer(cli); + return; + } + + block_set(cli, cli->block.number + 1); + block_start(cli); +} + +static void confirm_transfer(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = transfer_complete, + .acked = true, + }; + + BT_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + + blob_cli_broadcast(cli, &ctx); +} + +static void progress_checked(struct bt_mesh_blob_cli *cli) +{ + BT_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + + if (cli->cb && cli->cb->end) { + cli->cb->xfer_progress_complete(cli); + } +} + +static void check_transfer(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = progress_checked, + .acked = true, + }; + + BT_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET; + + blob_cli_broadcast(cli, &ctx); +} + +static void transfer_cancel(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_cancel_tx, + .next = transfer_complete, + .acked = true, + }; + + BT_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; + + blob_cli_broadcast(cli, &ctx); +} + +static void transfer_complete(struct bt_mesh_blob_cli *cli) +{ + bool success = targets_active(cli) && + cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + + end(cli, success); +} + +/******************************************************************************* + * RX + ******************************************************************************/ + +static void rx_block_status(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + struct block_status *block) +{ + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + BT_WARN("Invalid state %u", cli->state); + return; + } + + BT_WARN("0x%04x: block: %u status: %u", target->addr, block->block.number, block->status); + + if (block->status != BT_MESH_BLOB_SUCCESS && + /** + * Changed by Espressif. + * This behavior is not allowed by spec! + * + * BT_MESH_BLOB_ERR_INFO_UNAVAILABLE will caused + * by blob server suspend, and the suspend state + * will be resume in most scenes. + * + * so let blob client try to resume blob server. + */ + block->status != BT_MESH_BLOB_ERR_INFO_UNAVAILABLE) { + target_drop(cli, target, block->status); + blob_cli_broadcast_rsp(cli, target); + return; + } + + if (block->block.number != cli->block.number) { + BT_DBG("Invalid block num (expected %u)", cli->block.number); + return; + } + + if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_NONE) { + target->procedure_complete = 1U; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + update_missing_chunks(cli); + } + + BT_DBG("Target 0x%04x received all chunks", target->addr); + } else if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_ALL) { + blob_chunk_missing_set_all(&cli->block); + } else if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memcpy(target->pull->missing, block->block.missing, sizeof(block->block.missing)); + + BT_DBG("Missing: %s", bt_hex(target->pull->missing, cli->block.chunk_count)); + + update_missing_chunks(cli); + + /* Target has responded. Reset the timestamp so that client can start transmitting + * missing chunks to it. + */ + target->pull->block_report_timestamp = 0ll; + } else { + for (int i = 0; i < ARRAY_SIZE(block->block.missing); ++i) { + cli->block.missing[i] |= block->block.missing[i]; + } + } + + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (!cli->tx.sending) { + /* If not sending, then the retry timer is running. Call + * broadcast_complete() to proceed to block_check_end() and start + * transmitting missing chunks. + */ + broadcast_complete(cli); + } + + /* When sending chunks in Pull mode, we don't confirm transaction when receiving + * Partial Block Report message. + */ + return; + } + + blob_cli_broadcast_rsp(cli, target); +} + +static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + enum bt_mesh_blob_xfer_phase expected_phase; + struct bt_mesh_blob_target *target; + struct bt_mesh_blob_xfer_info info = { 0 }; + uint8_t status_and_mode; + + status_and_mode = net_buf_simple_pull_u8(buf); + info.status = status_and_mode & BIT_MASK(4); + info.mode = status_and_mode >> 6; + info.phase = net_buf_simple_pull_u8(buf); + + if (buf->len) { + info.id = net_buf_simple_pull_le64(buf); + } + + if (buf->len >= 7) { + info.size = net_buf_simple_pull_le32(buf); + info.block_size_log = net_buf_simple_pull_u8(buf); + info.mtu_size = net_buf_simple_pull_le16(buf); + info.missing_blocks = net_buf_simple_pull(buf, buf->len); + } + + BT_DBG("status: %u %s phase: %u %s", info.status, + info.mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull", + info.phase, bt_hex(&info.id, 8)); + + if (cli->state != BT_MESH_BLOB_CLI_STATE_START && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_CHECK && + cli->state != BT_MESH_BLOB_CLI_STATE_CANCEL && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + BT_WARN("Wrong state: %d", cli->state); + return -EBUSY; + } + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + if (cli->state == BT_MESH_BLOB_CLI_STATE_START) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK; + } else if (cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_COMPLETE; + } else if (cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_INACTIVE; + } else { /* cli->state == BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET */ + blob_cli_broadcast_rsp(cli, target); + if (cli->cb && cli->cb->xfer_progress) { + cli->cb->xfer_progress(cli, target, &info); + } + return 0; + } + + if (info.status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, info.status); + } else if (info.phase != expected_phase) { + BT_WARN("Wrong phase: %u != %u", expected_phase, info.phase); + return -EINVAL; + } else if (info.phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + info.id != cli->xfer->id) { + target_drop(cli, target, BT_MESH_BLOB_ERR_WRONG_BLOB_ID); + } + + blob_cli_broadcast_rsp(cli, target); + + return 0; +} + +static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + struct block_status status = { + .status = BT_MESH_BLOB_SUCCESS, + .block.number = cli->block.number, + .missing = (buf->len ? BT_MESH_BLOB_CHUNKS_MISSING_ENCODED : + BT_MESH_BLOB_CHUNKS_MISSING_NONE), + }; + struct bt_mesh_blob_target *target; + + if (!cli->xfer) { + return -EINVAL; + } + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + BT_WARN("Unexpected encoded block report in push mode"); + return -EINVAL; + } + + BT_DBG(""); + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + while (buf->len) { + int idx; + + idx = chunk_idx_decode(buf); + if (idx < 0) { + return idx; + } + + blob_chunk_missing_set(status.block.missing, idx, true); + } + + /* If all chunks were already confirmed by this target, Send Data State Machine is in Final + * state for this target. Therefore, the message should be ignored. + */ + if (next_missing_chunk(cli, target->pull->missing, 0) >= cli->block.chunk_count) { + BT_DBG("All chunks already confirmed"); + return 0; + } + + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + + rx_block_status(cli, target, &status); + + return 0; +} + +static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_target *target; + struct block_status status = { 0 }; + uint8_t status_and_format; + uint16_t chunk_size; + size_t len; + int idx; + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + status_and_format = net_buf_simple_pull_u8(buf); + status.status = status_and_format & BIT_MASK(4); + status.missing = status_and_format >> 6; + status.block.number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); + status.block.chunk_count = + DIV_ROUND_UP(cli->block.size, chunk_size); + + BT_DBG("status: %u block: %u encoding: %u", status.status, + status.block.number, status.missing); + + switch (status.missing) { + case BT_MESH_BLOB_CHUNKS_MISSING_ALL: + blob_chunk_missing_set_all(&status.block); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_NONE: + break; + case BT_MESH_BLOB_CHUNKS_MISSING_SOME: + if (buf->len > sizeof(status.block.missing)) { + return -EINVAL; + } + + len = buf->len; + memcpy(status.block.missing, net_buf_simple_pull_mem(buf, len), + len); + + BT_DBG("Missing: %s", bt_hex(status.block.missing, len)); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_ENCODED: + /** MshMBTv1.0: 5.3.8: An empty Missing Chunks field entails that there are no + * missing chunks for this block. + */ + if (!buf->len) { + status.missing = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } + + while (buf->len) { + idx = chunk_idx_decode(buf); + if (idx < 0 || idx >= status.block.chunk_count) { + BT_ERR("Invalid encoding"); + return -EINVAL; + } + + BT_DBG("Missing %d", idx); + + blob_chunk_missing_set(status.block.missing, idx, true); + } + break; + } + + rx_block_status(cli, target, &status); + + return 0; +} + +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli_caps caps; + enum bt_mesh_blob_status status; + struct bt_mesh_blob_target *target; + + if (cli->state != BT_MESH_BLOB_CLI_STATE_CAPS_GET) { + return -EBUSY; + } + + caps.min_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_chunks = net_buf_simple_pull_le16(buf); + caps.max_chunk_size = net_buf_simple_pull_le16(buf); + caps.max_size = net_buf_simple_pull_le32(buf); + caps.mtu_size = net_buf_simple_pull_le16(buf); + caps.modes = net_buf_simple_pull_u8(buf); + + if (caps.min_block_size_log < 0x06 || + caps.max_block_size_log > 0x20 || + caps.max_block_size_log < caps.min_block_size_log || + caps.max_chunks == 0 || caps.max_chunk_size < 8 || + caps.max_size == 0 || caps.mtu_size < 0x14) { + return -EINVAL; + } + + BT_DBG("0x%04x\n\tblock size: %u - %u\n\tchunks: %u\n\tchunk size: %u\n" + "\tblob size: %u\n\tmtu size: %u\n\tmodes: %x", + ctx->addr, caps.min_block_size_log, caps.max_block_size_log, + caps.max_chunks, caps.max_chunk_size, caps.max_size, + caps.mtu_size, caps.modes); + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + status = caps_adjust(cli, &caps); + if (status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, status); + } + + blob_cli_broadcast_rsp(cli, target); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_blob_cli_op[] = { + { BT_MESH_BLOB_OP_XFER_STATUS, 2, (void *)handle_xfer_status }, + { BT_MESH_BLOB_OP_BLOCK_REPORT, 0, (void *)handle_block_report }, + { BT_MESH_BLOB_OP_BLOCK_STATUS, 5, (void *)handle_block_status }, + { BT_MESH_BLOB_OP_INFO_STATUS, 13, (void *)handle_info_status }, + BLE_MESH_MODEL_OP_END, +}; + +static int blob_cli_init(struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + + cli->mod = mod; + + bt_mesh_blob_cli_set_chunk_interval_ms(cli, CONFIG_BLE_MESH_TX_BLOB_CHUNK_SEND_INTERVAL); + cli->tx.cli_timestamp = 0ll; + k_work_init_delayable(&cli->tx.retry, retry_timeout); + k_work_init_delayable(&cli->tx.complete, tx_complete); + + return 0; +} + +static void blob_cli_reset(struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_cli *cli = mod->user_data; + + cli_state_reset(cli); +} + +static int blob_cli_deinit(struct bt_mesh_model *mod) +{ + blob_cli_reset(mod); + return 0; +} + +const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb = { + .init = blob_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = blob_cli_deinit, +#endif +}; + +int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->inputs = inputs; + + cli->caps.min_block_size_log = 0x06; + cli->caps.max_block_size_log = 0x20; + cli->caps.max_chunks = CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX; + cli->caps.max_chunk_size = BLOB_TX_CHUNK_SIZE; + cli->caps.max_size = 0xffffffff; + cli->caps.mtu_size = 0xffff; + cli->caps.modes = BT_MESH_BLOB_XFER_MODE_ALL; + + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } + + caps_get(cli); + + return 0; +} + +int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + BT_ERR("BLOB Client is busy"); + return -EBUSY; + } + + if (!(xfer->mode & BT_MESH_BLOB_XFER_MODE_ALL) || xfer->block_size_log < 0x06 || + xfer->block_size_log > 0x20 || xfer->chunk_size < 8 || + xfer->chunk_size > BLOB_TX_CHUNK_SIZE) { + BT_ERR("Incompatible transfer parameters"); + return -EINVAL; + } + + cli->xfer = xfer; + cli->inputs = inputs; + cli->io = io; + + if (cli->xfer->block_size_log == 0x20) { + cli->block_count = 1; + } else { + cli->block_count = DIV_ROUND_UP(cli->xfer->size, (1U << cli->xfer->block_size_log)); + } + + block_set(cli, 0); + + if (cli->block.chunk_count > CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX) { + BT_ERR("Too many chunks"); + return -EINVAL; + } + + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } + + BT_INFO("block size log: %u chunk size: %u blob size: %u tmode: %x", + cli->xfer->block_size_log, cli->xfer->chunk_size, + cli->xfer->size, cli->xfer->mode); + + return xfer_start(cli); +} + +int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli) +{ + if (cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + return 0; + } + + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + BT_WARN("BLOB xfer not started: %d", cli->state); + return -EINVAL; + } + + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + (void)k_work_cancel_delayable(&cli->tx.retry); + cli->tx.ctx.is_inited = 0; + cli->tx.sending = 0; + cli->tx.cli_timestamp = 0ll; + return 0; +} + +int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + if (cli->state != BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + BT_WARN("Not suspended"); + return -EINVAL; + } + + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + target->status = BT_MESH_BLOB_SUCCESS; + target->timedout = 0U; + } + } + + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } + + block_set(cli, 0); + return xfer_start(cli); +} + +void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli) +{ + if (!bt_mesh_blob_cli_is_busy(cli)) { + BT_WARN("BLOB xfer already cancelled"); + return; + } + + BT_DBG(""); + + if (cli->state == BT_MESH_BLOB_CLI_STATE_CAPS_GET || + cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + cli_state_reset(cli); + return; + } + + cli->tx.cancelled = 1U; + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; +} + +void bt_mesh_blob_cli_send_cancel(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer) +{ + cli->xfer = xfer; + + transfer_cancel(cli); +} + +int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->inputs = inputs; + + check_transfer(cli); + + return 0; +} + +uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli) +{ + if (cli->state < BT_MESH_BLOB_CLI_STATE_START) { + return 0; + } + + return (100U * cli->block.number) / cli->block_count; +} + +bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli) +{ + return cli->state != BT_MESH_BLOB_CLI_STATE_NONE; +} + +void bt_mesh_blob_cli_set_chunk_interval_ms(struct bt_mesh_blob_cli *cli, uint32_t interval_ms) +{ + cli->chunk_interval_ms = interval_ms; +} + +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c new file mode 100644 index 000000000000..3540a6abeac3 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c @@ -0,0 +1,1073 @@ +/* + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "net.h" +#include "access.h" +#include "transport.h" +#include "lpn.h" +#include "mesh/main.h" +#include "mesh/utils.h" +#include "mesh/common.h" +#include "mesh/slist.h" +#include "blob.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#if CONFIG_BLE_MESH_SETTINGS +#include "settings.h" +#endif + +#if CONFIG_BLE_MESH_BLOB_SRV + +#define MTU_SIZE_MAX (BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT) + +/* The Receive BLOB Timeout Timer */ +#define SERVER_TIMEOUT_SECS(srv) (10 * (1 + (srv)->state.timeout_base)) +/* The initial timer value used by an instance of the Pull BLOB State machine - T_BPI */ +#define REPORT_TIMER_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_BLOB_REPORT_TIMEOUT) + +_Static_assert(BLOB_BLOCK_SIZE_LOG_MIN <= BLOB_BLOCK_SIZE_LOG_MAX, + "The must be at least one number between the min and " + "max block size that is the power of two."); + +_Static_assert((BLOB_XFER_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum outgoing SDU size."); + +_Static_assert((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_TX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum outgoing SDU " + "size."); + +_Static_assert((BLOB_BLOCK_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum outgoing SDU size."); + +static void cancel(struct bt_mesh_blob_srv *srv); +static void suspend(struct bt_mesh_blob_srv *srv); + +static inline uint32_t block_count_get(const struct bt_mesh_blob_srv *srv) +{ + return DIV_ROUND_UP(srv->state.xfer.size, + (1U << srv->state.xfer.block_size_log)); +} + +static inline uint32_t max_chunk_size(const struct bt_mesh_blob_srv *srv) +{ + return MIN((srv->state.mtu_size - 2 - BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK)), + BLOB_RX_CHUNK_SIZE); +} + +static inline uint32_t max_chunk_count(const struct bt_mesh_blob_srv *srv) +{ + return MIN(8 * (srv->state.mtu_size - 6), + CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX); +} + +static inline uint32_t missing_chunks(const struct bt_mesh_blob_block *block) +{ + int i; + uint32_t count = 0; + + for (i = 0; i < ARRAY_SIZE(block->missing); ++i) { + count += popcount(block->missing[i]); + } + + return count; +} + +static void store_state(const struct bt_mesh_blob_srv *srv) +{ +#if CONFIG_BLE_MESH_SETTINGS + /* Convert bit count to byte count: */ + uint32_t block_len = DIV_ROUND_UP(block_count_get(srv), 8); + + bt_mesh_model_data_store( + srv->mod, false, NULL, &srv->state, + offsetof(struct bt_mesh_blob_srv_state, blocks) + block_len); +#endif +} + +static void erase_state(struct bt_mesh_blob_srv *srv) +{ +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#endif +} + +static int io_open(struct bt_mesh_blob_srv *srv) +{ + if (!srv->io->open) { + return 0; + } + + return srv->io->open(srv->io, &srv->state.xfer, BT_MESH_BLOB_WRITE); +} + +static void io_close(struct bt_mesh_blob_srv *srv) +{ + if (!srv->io->close) { + return; + } + + srv->io->close(srv->io, &srv->state.xfer); +} + +static void reset_timer(struct bt_mesh_blob_srv *srv) +{ + uint32_t timeout_secs = + srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL ? + MAX(SERVER_TIMEOUT_SECS(srv), + CONFIG_BLE_MESH_BLOB_REPORT_TIMEOUT + 1) : + SERVER_TIMEOUT_SECS(srv); + BT_DBG("Next Msg should be arrive in %ds", timeout_secs); + k_work_reschedule(&srv->rx_timeout, K_SECONDS(timeout_secs)); +} + +static void buf_chunk_index_add(struct net_buf_simple *buf, uint16_t chunk) +{ + /* utf-8 encoded: */ + if (chunk < 0x80) { + net_buf_simple_add_u8(buf, chunk); + } else if (chunk < 0x8000) { + net_buf_simple_add_u8(buf, 0xc0 | chunk >> 6); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } else { + net_buf_simple_add_u8(buf, 0xe0 | chunk >> 12); + net_buf_simple_add_u8(buf, 0x80 | ((chunk >> 6) & BIT_MASK(6))); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } +} + +static int pull_req_max(const struct bt_mesh_blob_srv *srv) +{ + int count = CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT; + +#if defined(CONFIG_BLE_MESH_LOW_POWER) + /* No point in requesting more than the friend node can hold: */ + if (bt_mesh_lpn_established()) { + uint32_t segments_per_chunk = DIV_ROUND_UP( + BLOB_CHUNK_SDU_LEN(srv->state.xfer.chunk_size), + BLE_MESH_APP_SEG_SDU_MAX); + + count = MIN(CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT, + bt_mesh.lpn.queue_size / segments_per_chunk); + } +#endif + + return MIN(count, missing_chunks(&srv->block)); +} + +static void report_sent(int err, void *cb_data) +{ + struct bt_mesh_blob_srv *srv = cb_data; + + BT_DBG(""); + + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && bt_mesh_lpn_established()) { + bt_mesh_lpn_poll(); + } + + if (k_work_delayable_is_pending(&srv->rx_timeout)) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } +} + +static void block_report(struct bt_mesh_blob_srv *srv) +{ + static const struct bt_mesh_send_cb report_cb = { .end = report_sent }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = srv->state.app_idx, + .send_ttl = srv->state.ttl, + .addr = srv->state.cli, + }; + int count; + int i; + + BT_DBG("rx BLOB Timeout Timer: %i", k_work_delayable_is_pending(&srv->rx_timeout)); + + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_REPORT, + BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_REPORT); + + count = pull_req_max(srv); + + for (i = 0; i < srv->block.chunk_count && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + buf_chunk_index_add(&buf, i); + count--; + } + } + + (void)bt_mesh_model_send(srv->mod, &ctx, &buf, &report_cb, srv); +} + +static void phase_set(struct bt_mesh_blob_srv *srv, + enum bt_mesh_blob_xfer_phase phase) +{ + srv->phase = phase; + BT_INFO("Phase: %u", phase); +} + +static void cancel(struct bt_mesh_blob_srv *srv) +{ + /* TODO: Could this state be preserved instead somehow? Wiping the + * entire transfer state is a bit overkill + */ + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + srv->state.xfer.chunk_size = 0xffff; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); + + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, false); + } +} + +static void suspend(struct bt_mesh_blob_srv *srv) +{ + BT_DBG("%s", __func__); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + if (srv->cb && srv->cb->suspended) { + srv->cb->suspended(srv); + } +} + +static void resume(struct bt_mesh_blob_srv *srv) +{ + BT_DBG("%s", __func__); + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + reset_timer(srv); +} + +static void end(struct bt_mesh_blob_srv *srv) +{ + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); + + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, true); + } +} + +static bool all_blocks_received(struct bt_mesh_blob_srv *srv) +{ + for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) { + if (srv->state.blocks[i]) { + return false; + } + } + + return true; +} + +static bool pull_mode_xfer_complete(struct bt_mesh_blob_srv *srv) +{ + return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL && + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && + all_blocks_received(srv); +} + +static void timeout(struct k_work *work) +{ + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, rx_timeout.work); + + BT_DBG("phase %d", srv->phase); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + cancel(srv); + } else if (pull_mode_xfer_complete(srv)) { + end(srv); + } else { + suspend(srv); + } +} + +static void report_timeout(struct k_work *work) +{ + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, pull.report.work); + + BT_DBG(""); + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK && + srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + return; + } + + block_report(srv); +} + +/******************************************************************************* + * Message handling + ******************************************************************************/ + +static void xfer_status_rsp(struct bt_mesh_blob_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) +{ + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_STATUS, + BLOB_XFER_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_STATUS); + + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(4)) | + (srv->state.xfer.mode << 6))); + net_buf_simple_add_u8(&buf, srv->phase); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto send; + } + + net_buf_simple_add_le64(&buf, srv->state.xfer.id); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + goto send; + } + + net_buf_simple_add_le32(&buf, srv->state.xfer.size); + net_buf_simple_add_u8(&buf, srv->state.xfer.block_size_log); + net_buf_simple_add_le16(&buf, srv->state.mtu_size); + net_buf_simple_add_mem(&buf, srv->state.blocks, + DIV_ROUND_UP(block_count_get(srv), 8)); + +send: + ctx->send_ttl = srv->state.ttl; + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static void block_status_rsp(struct bt_mesh_blob_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) +{ + enum bt_mesh_blob_chunks_missing format; + uint32_t missing; + int i; + + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_STATUS, + BLOB_BLOCK_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_STATUS); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + missing = srv->block.chunk_count; + } else if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { + missing = 0U; + } else { + missing = missing_chunks(&srv->block); + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ENCODED; + } else if (missing == srv->block.chunk_count) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ALL; + } else if (missing == 0) { + format = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } else { + format = BT_MESH_BLOB_CHUNKS_MISSING_SOME; + } + + BT_DBG("Status: %u, missing: %u/%u", status, missing, srv->block.chunk_count); + + net_buf_simple_add_u8(&buf, (status & BIT_MASK(4)) | (format << 6)); + net_buf_simple_add_le16(&buf, srv->block.number); + net_buf_simple_add_le16(&buf, srv->state.xfer.chunk_size); + + if (format == BT_MESH_BLOB_CHUNKS_MISSING_SOME) { + net_buf_simple_add_mem(&buf, srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, + 8)); + + BT_DBG("Bits: %s", + bt_hex(srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, 8))); + + } else if (format == BT_MESH_BLOB_CHUNKS_MISSING_ENCODED) { + int count = pull_req_max(srv); + + for (i = 0; (i < srv->block.chunk_count) && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + BT_DBG("Missing %u", i); + buf_chunk_index_add(&buf, i); + count--; + } + } + } + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } + + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static int handle_xfer_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + + BT_DBG(""); + + if (pull_mode_xfer_complete(srv)) { + /* The client requested transfer. If we are in Pull mode and all blocks were + * received, we should change the Transfer state here to Complete so that the client + * receives the correct state. + */ + end(srv); + } + + xfer_status_rsp(srv, ctx, BT_MESH_BLOB_SUCCESS); + + return 0; +} + +static int handle_xfer_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + enum bt_mesh_blob_status status; + enum bt_mesh_blob_xfer_mode mode; + uint64_t id; + size_t size; + uint8_t block_size_log; + uint32_t block_count; + uint16_t mtu_size; + int err; + + mode = (net_buf_simple_pull_u8(buf) >> 6); + id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + block_size_log = net_buf_simple_pull_u8(buf); + mtu_size = net_buf_simple_pull_le16(buf); + + BT_INFO("size: %u block size: %u mtu_size: %u mode: %s", + size, (1U << block_size_log), mtu_size, + mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull"); + + if (mode != BT_MESH_BLOB_XFER_MODE_PULL && + mode != BT_MESH_BLOB_XFER_MODE_PUSH) { + BT_WARN("Invalid mode 0x%x", mode); + return -EINVAL; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + BT_WARN("Uninitialized"); + goto rsp; + } + +#if 0 /* For case DFU/SR/FD/BV-59-C, workaround */ + srv->state.xfer.id = id; +#endif + + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + /* bt_hex uses static array for the resulting hex string. + * Not possible to use bt_hex in the same logging function twice. + */ + BT_WARN("Invalid ID: %s", bt_hex(&id, sizeof(uint64_t))); + BT_WARN("Expected ID: %s", bt_hex(&srv->state.xfer.id, sizeof(uint64_t))); + goto rsp; + } + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + if (srv->state.xfer.mode != mode || + srv->state.xfer.size != size || + srv->state.xfer.block_size_log != block_size_log || + srv->state.mtu_size > mtu_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + BT_WARN("Busy"); + goto rsp; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + resume(srv); + store_state(srv); + } else { + BT_DBG("Duplicate"); + } + + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } + + if (size > CONFIG_BLE_MESH_BLOB_SIZE_MAX) { + BT_WARN("Too large"); + status = BT_MESH_BLOB_ERR_BLOB_TOO_LARGE; + goto rsp; + } + + if (((1U << block_size_log) < CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN) || + ((1U << block_size_log) > CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MAX)) { + BT_WARN("Invalid block size: %u", block_size_log); + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + goto rsp; + } + + srv->state.cli = ctx->addr; + srv->state.app_idx = ctx->app_idx; + srv->state.mtu_size = MIN(mtu_size, MTU_SIZE_MAX); + srv->state.xfer.id = id; + srv->state.xfer.size = size; + srv->state.xfer.mode = mode; + srv->state.xfer.block_size_log = block_size_log; + srv->state.xfer.chunk_size = 0xffff; + srv->block.number = 0xffff; + + block_count = block_count_get(srv); + if (block_count > BT_MESH_BLOB_BLOCKS_MAX) { + BT_WARN("Invalid block count (%u)", block_count); + status = BT_MESH_BLOB_ERR_INVALID_PARAM; + cancel(srv); + goto rsp; + } + + memset(srv->state.blocks, 0, sizeof(srv->state.blocks)); + for (int i = 0; i < block_count; i++) { + bt_mesh_atomic_set_bit(srv->state.blocks, i); + } + + err = io_open(srv); + if (err) { + BT_ERR("Couldn't open stream (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } + + if (srv->cb && srv->cb->start) { + err = srv->cb->start(srv, ctx, &srv->state.xfer); + if (err) { + BT_ERR("Couldn't start transfer (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } + } + + reset_timer(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + status = BT_MESH_BLOB_SUCCESS; + +rsp: + xfer_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_xfer_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; + struct bt_mesh_blob_srv *srv = mod->user_data; + uint64_t id; + + id = net_buf_simple_pull_le64(buf); + + BT_DBG("%u", (uint32_t)id); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto rsp; + } + + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + goto rsp; + } + + cancel(srv); + +rsp: + xfer_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_blob_status status; + struct bt_mesh_blob_srv *srv = mod->user_data; + + switch (srv->phase) { + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK: + case BT_MESH_BLOB_XFER_PHASE_COMPLETE: + status = BT_MESH_BLOB_SUCCESS; + break; + case BT_MESH_BLOB_XFER_PHASE_SUSPENDED: + status = BT_MESH_BLOB_ERR_INFO_UNAVAILABLE; + break; + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START: + case BT_MESH_BLOB_XFER_PHASE_INACTIVE: + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + break; + default: + status = BT_MESH_BLOB_ERR_INTERNAL; + break; + } + + BT_DBG(""); + + block_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + enum bt_mesh_blob_status status; + uint16_t block_number, chunk_size; + int err; + + block_number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START || + srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + goto rsp; + } + + reset_timer(srv); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + if (block_number != srv->block.number || + chunk_size != srv->state.xfer.chunk_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + } else { + status = BT_MESH_BLOB_SUCCESS; + } + + goto rsp; + } + + if (block_number >= block_count_get(srv)) { + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM; + goto rsp; + } + + if (!chunk_size || chunk_size > max_chunk_size(srv) || + (DIV_ROUND_UP((1 << srv->state.xfer.block_size_log), chunk_size) > + max_chunk_count(srv))) { + BT_WARN("Invalid chunk size: (chunk size: %u, max: %u, block log: %u, count: %u)", + chunk_size, max_chunk_size(srv), + srv->state.xfer.block_size_log, + max_chunk_count(srv)); + status = BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE; + goto rsp; + } + + srv->block.size = blob_block_size( + srv->state.xfer.size, srv->state.xfer.block_size_log, block_number); + srv->block.number = block_number; + srv->block.chunk_count = DIV_ROUND_UP(srv->block.size, chunk_size); + srv->state.xfer.chunk_size = chunk_size; + srv->block.offset = block_number * (1UL << srv->state.xfer.block_size_log); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE || + !bt_mesh_atomic_test_bit(srv->state.blocks, block_number)) { + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED && srv->cb && + srv->cb->resume) { + srv->cb->resume(srv); + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + BT_INFO("Waiting nxt chunk to resume blob srv"); + } + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); + blob_chunk_missing_set_all(&srv->block); + + BT_WARN("%u: (%u/%u)\n\tsize: %u\n\tchunk size: %u\n\tchunk count: %u", + srv->block.number, srv->block.number + 1, block_count_get(srv), + srv->block.size, chunk_size, srv->block.chunk_count); + + if (srv->io->block_start) { + err = srv->io->block_start(srv->io, &srv->state.xfer, + &srv->block); + if (err) { + cancel(srv); + status = BT_MESH_BLOB_ERR_INTERNAL; + goto rsp; + } + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* Wait for the client to send the first chunk */ + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } + + status = BT_MESH_BLOB_SUCCESS; + +rsp: + block_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_chunk chunk; + size_t expected_size = 0; + uint16_t idx; + int err; + + idx = net_buf_simple_pull_le16(buf); + chunk.size = buf->len; + chunk.data = net_buf_simple_pull_mem(buf, chunk.size); + chunk.offset = idx * srv->state.xfer.chunk_size; + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK || + srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { + // This Block is already complete received. + BT_INFO("Discord chunk(%d), because the block is already received", idx); + return -EINVAL; + } + /** + * Changed by Espressif. + * This behavior is not allowed by spec! + * + * Change resason: + * If the former chunk lost and the following received chunks + * all will be drop, so this change is therefore used to + * avoid such waste. + * + */ + if ((srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && + srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED) || + idx >= srv->block.chunk_count) { + BT_ERR("Invalid phase or index (%u %u)", srv->phase, + idx); + return -EINVAL; + } + + if (idx == srv->block.chunk_count - 1) { + expected_size = srv->block.size % srv->state.xfer.chunk_size; + } + + if (expected_size == 0) { + expected_size = srv->state.xfer.chunk_size; + } + + if (chunk.size != expected_size) { + BT_ERR("Unexpected size: %u != %u", expected_size, chunk.size); + return -EINVAL; + } + + /** + * Changed By Espressif. + * + * The blob server should resume if received a new chunk + * after suspend (that's behavior is not required by spec). + * + * Change resason: + * The blob server will be suspend after a chunk missed + * and resume at next block start received. + * but a block get will be received before a block start + * sent, the blob server which in suspend state will response + * a err state to blob client,and the blob client will drop + * that blob server, causing the server couldn't receive + * complete. + */ + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); + } + + BT_INFO("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count, + chunk.size); + + reset_timer(srv); + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } + + if (!blob_chunk_missing_get(srv->block.missing, idx)) { + BT_DBG("Duplicate chunk %u", idx); + return -EALREADY; + } + + err = srv->io->wr(srv->io, &srv->state.xfer, &srv->block, &chunk); + if (err) { + return err; + } + + blob_chunk_missing_set(srv->block.missing, idx, false); + if (missing_chunks(&srv->block)) { + return 0; + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + block_report(srv); + } + + if (srv->io->block_end) { + srv->io->block_end(srv->io, &srv->state.xfer, &srv->block); + } + + bt_mesh_atomic_clear_bit(srv->state.blocks, srv->block.number); + + if (!all_blocks_received(srv)) { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + return 0; + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report + * messages "If the current block is the last block, then the server determines that + * the client knows the transfer is complete. For example, a higher-layer model may + * indicate that the client considers the transfer complete." + * + * We don't have any way for higher-layer model to indicate that the transfer is + * complete. Therefore we need to keep sending Partial Block Report messages until + * the client sends BLOB Transfer Get message or the Block Timer expires. + */ + return 0; + } + + end(srv); + return 0; +} + +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + + BT_DBG(""); + + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_BLOB_OP_INFO_STATUS, 15); + bt_mesh_model_msg_init(&rsp, BT_MESH_BLOB_OP_INFO_STATUS); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MIN); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX); + net_buf_simple_add_le16(&rsp, BLOB_RX_CHUNK_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_BLOB_SIZE_MAX); + net_buf_simple_add_le16(&rsp, MTU_SIZE_MAX); + net_buf_simple_add_u8(&rsp, BT_MESH_BLOB_XFER_MODE_ALL); + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } + + (void)bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_blob_srv_op[] = { + { BT_MESH_BLOB_OP_XFER_GET, 0, (void *)handle_xfer_get }, + { BT_MESH_BLOB_OP_XFER_START, 16, (void *)handle_xfer_start }, + { BT_MESH_BLOB_OP_XFER_CANCEL, 8, (void *)handle_xfer_cancel }, + { BT_MESH_BLOB_OP_BLOCK_GET, 0, (void *)handle_block_get }, + { BT_MESH_BLOB_OP_BLOCK_START, 4, (void *)handle_block_start }, + { BT_MESH_BLOB_OP_CHUNK, 2, (void *)handle_chunk }, + { BT_MESH_BLOB_OP_INFO_GET, 0, (void *)handle_info_get }, + BLE_MESH_MODEL_OP_END, +}; + +static int blob_srv_init(struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + + srv->mod = mod; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + k_work_init_delayable(&srv->rx_timeout, timeout); + k_work_init_delayable(&srv->pull.report, report_timeout); + + return 0; +} + +__attribute__((unused)) +static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *name, + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + ssize_t len; + + if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { + return -EINVAL; + } + + len = read_cb(cb_arg, &srv->state, sizeof(srv->state)); + if (len < 0) { + return len; + } + + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + + if (block_count_get(srv) > BT_MESH_BLOB_BLOCKS_MAX) { + BT_WARN("Loaded block count too high (%u, max: %u)", + block_count_get(srv), BT_MESH_BLOB_BLOCKS_MAX); + return 0; + } + + /* If device restarted before it handled `XFER_START` server we restore state into + * BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START phase, so `XFER_START` can be accepted + * as it would before reboot + */ + if (srv->state.cli == BLE_MESH_ADDR_UNASSIGNED) { + BT_DBG("Transfer (id=%llu) waiting for start", srv->state.xfer.id); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + } else { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + + BT_DBG("Recovered transfer from 0x%04x (%llu)", srv->state.cli, + srv->state.xfer.id); + } + + return 0; +} + +__attribute__((unused)) +static int blob_srv_start(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + int err = -ENOTSUP; + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + return 0; + } + + if (srv->cb && srv->cb->recover) { + srv->io = NULL; + err = srv->cb->recover(srv, &srv->state.xfer, &srv->io); + if (!err && srv->io) { + err = io_open(srv); + } + } + + if (err || !srv->io) { + BT_WARN("Abandoning transfer."); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + erase_state(srv); + } + + return 0; +} + +static void blob_srv_reset(struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->user_data; + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + erase_state(srv); +} + +static int blob_srv_deinit(struct bt_mesh_model *mod) +{ + blob_srv_reset(mod); + return 0; +} + +const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb = { + .init = blob_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = blob_srv_deinit, +#endif +}; + +int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base) +{ + if (bt_mesh_blob_srv_is_busy(srv)) { + return -EBUSY; + } + + if (!io || !io->wr) { + return -EINVAL; + } + + srv->state.xfer.id = id; + srv->state.ttl = ttl; + srv->state.timeout_base = timeout_base; + srv->io = io; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + store_state(srv); + + return 0; +} + +int bt_mesh_blob_srv_cancel(struct bt_mesh_blob_srv *srv) +{ + if (!bt_mesh_blob_srv_is_busy(srv)) { + return -EALREADY; + } + + cancel(srv); + + return 0; +} + +bool bt_mesh_blob_srv_is_busy(const struct bt_mesh_blob_srv *srv) +{ + return srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED && + srv->phase != BT_MESH_BLOB_XFER_PHASE_COMPLETE; +} + +uint8_t bt_mesh_blob_srv_progress(const struct bt_mesh_blob_srv *srv) +{ + uint32_t total; + uint32_t received; + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + return 0; + } + + total = block_count_get(srv); + + received = 0; + for (int i = 0; i < total; ++i) { + if (!bt_mesh_atomic_test_bit(srv->state.blocks, i)) { + received++; + } + } + + return (100U * received) / total; +} + +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 41807eedebf2..edf146769c88 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -300,6 +300,16 @@ config BT_BLE_BLUFI_ENABLE help This option can be close when the app does not require blufi function. +config BT_BLUFI_BLE_SMP_ENABLE + bool "Enable BLE SMP support for BluFi" + depends on BT_BLE_BLUFI_ENABLE && BT_BLE_SMP_ENABLE + default n + help + Enable BLE Security Manager Protocol (SMP) for BluFi. + When enabled, BluFi will support BLE pairing and encryption + before Wi-Fi provisioning, providing a more secure provisioning process. + This feature is only supported with the Bluedroid host. + config BT_GATT_MAX_SR_PROFILES int "Max GATT Server Profiles" depends on BT_GATTS_ENABLE && BT_BLUEDROID_ENABLED diff --git a/components/bt/host/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c index e75fe818c393..2e4f5ec0789c 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -1954,13 +1954,17 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { tBTA_AV_REJECT reject; - UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; + UINT8 err_code = p_data->ci_setconfig.err_code; - bta_av_adjust_seps_idx(p_scb, avdt_handle); + if (err_code == AVDT_SUCCESS) { + err_code = AVDT_ERR_UNSUP_CFG; + } + + bta_av_adjust_seps_idx(p_scb, p_scb->avdt_handle); APPL_TRACE_DEBUG("bta_av_setconfig_rej: sep_idx: %d", p_scb->sep_idx); - AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, 0); + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, err_code, 0); - bdcpy(reject.bd_addr, p_data->str_msg.bd_addr); + bdcpy(reject.bd_addr, p_scb->peer_addr); reject.hndl = p_scb->hndl; (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject); } diff --git a/components/bt/host/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c index 23c1638bca35..434dfa8b22e7 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_act.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_act.c @@ -1192,16 +1192,16 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data) } } } else { - if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { - bta_sys_conn_close(TSEP_TO_SYS_ID(p_scb->seps[p_scb->sep_idx].tsep), bta_av_cb.audio_open_cnt, p_scb->peer_addr); - /* this channel is still marked as open. decrease the count */ - bta_av_cb.audio_open_cnt--; - } - - /* clear the conned mask for this channel */ - p_cb->conn_audio &= ~mask; - p_cb->conn_video &= ~mask; if (p_scb) { + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { + bta_sys_conn_close(TSEP_TO_SYS_ID(p_scb->seps[p_scb->sep_idx].tsep), bta_av_cb.audio_open_cnt, p_scb->peer_addr); + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + /* clear the conned mask for this channel */ + p_cb->conn_audio &= ~mask; + p_cb->conn_video &= ~mask; + /* the stream is closed. * clear the peer address, so it would not mess up the AVRCP for the next round of operation */ bdcpy(p_scb->peer_addr, bd_addr_null); @@ -1693,12 +1693,23 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND); if (p_lcb) { rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx); - p_cb->rcb[rc_handle].peer_features = peer_features; - p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; - p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; + if (rc_handle < BTA_AV_NUM_RCB) { + p_cb->rcb[rc_handle].peer_features = peer_features; + p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; + p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; #if BTA_AV_CA_INCLUDED - p_cb->rcb[rc_handle].cover_art_l2cap_psm = obex_l2cap_psm; + p_cb->rcb[rc_handle].cover_art_l2cap_psm = obex_l2cap_psm; #endif + } else { + /* cannot create valid rc_handle for current device. report failure */ + APPL_TRACE_ERROR("%s: no link resources available", __func__); + p_scb->use_rc = FALSE; + bdcpy(rc_open.peer_addr, p_scb->peer_addr); + rc_open.peer_features = 0; + rc_open.sdp_disc_done = FALSE; + rc_open.status = BTA_AV_FAIL_SDP; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + } } #if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE) else { diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index c0383286a206..fd7d665acc6d 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -2348,7 +2348,7 @@ void bta_dm_search_result (tBTA_DM_MSG *p_data) /* call back if application wants name discovery or found services that application is searching */ if (( !bta_dm_search_cb.services ) - || (( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services ))) { + || ( p_data->disc_result.result.disc_res.services )) { bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); } diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c index 5c7ee9bdede2..085697acb90c 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c @@ -63,7 +63,15 @@ void bta_dm_co_security_param_init(void) bte_appl_cfg.ble_min_key_size = BTM_BLE_MIN_KEY_SIZE; bte_appl_cfg.ble_accept_auth_enable = BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE; bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE; -}; + + APPL_TRACE_DEBUG("%s: auth_req=%u, io_cap=%u, init_key=%u, resp_key=%u, " + "max_key_size=%u, min_key_size=%u, accept_auth=%u, oob=%u", + __func__, + bte_appl_cfg.ble_auth_req, bte_appl_cfg.ble_io_cap, + bte_appl_cfg.ble_init_key, bte_appl_cfg.ble_resp_key, + bte_appl_cfg.ble_max_key_size, bte_appl_cfg.ble_min_key_size, + bte_appl_cfg.ble_accept_auth_enable, bte_appl_cfg.oob_support); +} #endif #if (defined CLASSIC_BT_INCLUDED && CLASSIC_BT_INCLUDED == TRUE) @@ -379,6 +387,7 @@ void bta_dm_co_ble_set_io_cap(UINT8 ble_io_cap) #if (SMP_INCLUDED == TRUE) if(ble_io_cap < BTM_IO_CAP_MAX ) { bte_appl_cfg.ble_io_cap = ble_io_cap; + APPL_TRACE_DEBUG("%s: ble_io_cap set to %u", __func__, ble_io_cap); } else { APPL_TRACE_ERROR("%s error:Invalid io cap value.",__func__); } @@ -389,22 +398,25 @@ void bta_dm_co_ble_set_auth_req(UINT8 ble_auth_req) { #if (SMP_INCLUDED == TRUE) bte_appl_cfg.ble_auth_req = ble_auth_req; -#endif ///SMP_INCLUDED == TRUE + APPL_TRACE_DEBUG("%s: ble_auth_req set to %u", __func__, ble_auth_req); +#endif } void bta_dm_co_ble_set_init_key_req(UINT8 init_key) { #if (SMP_INCLUDED == TRUE) - init_key &= 0x0f; // 4~7bit reservd, only used the 0~3bit + init_key &= 0x0f; // 4~7bit reserved, only used the 0~3bit bte_appl_cfg.ble_init_key = init_key; -#endif ///SMP_INCLUDED == TRUE + APPL_TRACE_DEBUG("%s: init_key set to 0x%x", __func__, init_key); +#endif } void bta_dm_co_ble_set_rsp_key_req(UINT8 rsp_key) { #if (SMP_INCLUDED == TRUE) - rsp_key &= 0x0f; // 4~7bit reservd, only used the 0~3bit + rsp_key &= 0x0f; // 4~7bit reserved, only used the 0~3bit bte_appl_cfg.ble_resp_key = rsp_key; + APPL_TRACE_DEBUG("%s: rsp_key set to 0x%x", __func__, rsp_key); #endif ///SMP_INCLUDED == TRUE } @@ -413,6 +425,7 @@ void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size) #if (SMP_INCLUDED == TRUE) if(ble_key_size >= bte_appl_cfg.ble_min_key_size && ble_key_size <= BTM_BLE_MAX_KEY_SIZE) { bte_appl_cfg.ble_max_key_size = ble_key_size; + APPL_TRACE_DEBUG("%s: max_key_size set to %d", __func__, ble_key_size); } else { APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size); } @@ -424,6 +437,7 @@ void bta_dm_co_ble_set_min_key_size(UINT8 ble_key_size) #if (SMP_INCLUDED == TRUE) if(ble_key_size >= BTM_BLE_MIN_KEY_SIZE && ble_key_size <= bte_appl_cfg.ble_max_key_size) { bte_appl_cfg.ble_min_key_size = ble_key_size; + APPL_TRACE_DEBUG("%s: min_key_size set to %u", __func__, ble_key_size); } else { APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size); } @@ -437,6 +451,7 @@ void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable) enable = BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_ENABLE; } bte_appl_cfg.ble_accept_auth_enable = enable; + APPL_TRACE_DEBUG("%s: accept_auth_enable set to %u", __func__, enable); #endif ///SMP_INCLUDED == TRUE } @@ -464,6 +479,7 @@ void bta_dm_co_ble_oob_support(UINT8 enable) } else { bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE; } + APPL_TRACE_DEBUG("%s: oob_support set to %u", __func__, bte_appl_cfg.oob_support); #endif ///SMP_INCLUDED == TRUE } diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index eb2b091eae1d..f65dd43e7ca8 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -2022,7 +2022,7 @@ BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, if ( ++ p_srcb->update_count == bta_gattc_num_reg_app()) { /* not an opened connection; or connection busy */ /* search for first available clcb and start discovery */ - if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) { + if ((p_clcb == NULL) || (p_clcb->p_q_cmd != NULL)) { for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++) { if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb && diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c index b47a9d973345..18632d2dfa7c 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c @@ -523,7 +523,8 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1); memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len); } else { - APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__); + APPL_TRACE_ERROR("%s(), line = %d, alloc fail, size %d, no memory. free=%d, largest_block=%d", __func__, __LINE__, + sizeof(tBTA_GATTC_DATA) + len, heap_caps_get_free_size(MALLOC_CAP_DEFAULT), heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)); return FALSE; } } else { diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c index ad8c80b1fbf4..f3bf70e80ca1 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c @@ -1405,14 +1405,8 @@ BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb) *******************************************************************************/ BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb) { -#if (BTM_WBS_INCLUDED == TRUE ) - return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) || - (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) && - (bta_ag_cb.sco.p_curr_scb == p_scb)); -#else return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb)); -#endif } /******************************************************************************* diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c index d35ad4f7c1fc..0b02557b08db 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c @@ -404,6 +404,11 @@ void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) return; } + if (p_scb->p_disc_db) { + APPL_TRACE_ERROR("Discovery already in progress... returning."); + return; + } + /* allocate buffer for sdp database */ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BTA_AG_DISC_BUF_SIZE); if(p_scb->p_disc_db) { diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index adf3d609d047..169c14dfbf95 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -362,6 +362,10 @@ static void bta_hf_client_handle_cind_list_item(char *name, UINT32 min, UINT32 m APPL_TRACE_DEBUG("%s %u.%s <%u:%u>", __FUNCTION__, index, name, min, max); + if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) { + return; + } + /* look for a matching indicator on list of supported ones */ for (i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++) { if (strcmp(name, BTA_HF_CLIENT_INDICATOR_SERVICE) == 0) { @@ -591,7 +595,7 @@ while (*buf == ' ') buf++; buf += sizeof("\r\n") - 1; /* skip rest of AT string up to */ -#define AT_SKIP_REST(buf) while(*buf != '\r') buf++; +#define AT_SKIP_REST(buf) while((*buf != '\r') && (*buf != '\0')) buf++; static char *bta_hf_client_parse_ok(char *buffer) { @@ -1018,7 +1022,7 @@ static char *bta_hf_client_parse_clcc(char *buffer) } } - /* Skip any remaing param,as they are not defined by BT HFP spec */ + /* Skip any remaining param,as they are not defined by BT HFP spec */ AT_SKIP_REST(buffer); AT_CHECK_RN(buffer); @@ -1374,6 +1378,11 @@ void bta_hf_client_at_parse(char *buf, unsigned int len) osi_free(tmp_buff); } + /* prevent buffer overflow in cases where LEN exceeds available buffer space */ + if (len > BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset) { + return; + } + memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len); bta_hf_client_cb.scb.at_cb.offset += len; @@ -1571,7 +1580,7 @@ void bta_hf_client_send_at_xapl(char *information, UINT32 features) *vendorID: A string representation of the hex value of the vendor ID from the manufacturer, without the 0x prefix. *productID: A string representation of the hex value of the product ID from the manufacturer, without the 0x prefix. *version: The revision of the software. - *Fatures: A base-10 representation of a bit field. Available features are: + *Features: A base-10 representation of a bit field. Available features are: *Bit 0 = reserved *Bit 1 = The accessory supports battery reporting (reserved only for battery operated accessories). *Bit 2 = The accessory is docked or powered (reserved only for battery operated accessories). @@ -1827,7 +1836,7 @@ void bta_hf_client_send_at_bia(void) for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) { int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1; - at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%u,", sup); + at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%d,", sup); } buf[at_len - 1] = '\r'; diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c index 17eba5edd6d7..a49cfc91a076 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -2941,7 +2941,9 @@ void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data) if (call_init_f) { cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data); } - t->init_called = TRUE; + if (t) { + t->init_called = TRUE; + } } diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c index 741950155070..7fb74fdfa825 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -696,7 +696,7 @@ on *******************************************************************************/ int BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) { - tBTA_JV_L2CAP_READ evt_data; + tBTA_JV_L2CAP_READ evt_data = {0}; APPL_TRACE_API( "%s", __func__); diff --git a/components/bt/host/bluedroid/bta/sys/utl.c b/components/bt/host/bluedroid/bta/sys/utl.c index 94348e85f030..0c7954d45c7e 100644 --- a/components/bt/host/bluedroid/bta/sys/utl.c +++ b/components/bt/host/bluedroid/bta/sys/utl.c @@ -43,7 +43,7 @@ INT16 utl_str2int(const char *p_s) { INT32 val = 0; - for (; *p_s == ' ' && *p_s != 0; p_s++); + for (; *p_s == ' '; p_s++); if (*p_s == 0) { return -1; diff --git a/components/bt/host/bluedroid/btc/core/btc_dev.c b/components/bt/host/bluedroid/btc/core/btc_dev.c index 18cda3e0d864..424dfe93e59f 100644 --- a/components/bt/host/bluedroid/btc/core/btc_dev.c +++ b/components/bt/host/bluedroid/btc/core/btc_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/bt/host/bluedroid/btc/core/btc_dm.c b/components/bt/host/bluedroid/btc/core/btc_dm.c index 782569c2993e..02b5a16ef4c3 100644 --- a/components/bt/host/bluedroid/btc/core/btc_dm.c +++ b/components/bt/host/bluedroid/btc/core/btc_dm.c @@ -784,6 +784,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) ble_msg->pid = BTC_PID_GAP_BLE; // tBTA_SERVICE_MASK service_mask; BTC_TRACE_DEBUG("btc_dm_upstreams_cback ev: %d\n", msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTA_DM_ENABLE_EVT: { diff --git a/components/bt/host/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c index d7330cc6f7d7..593bb99e0710 100644 --- a/components/bt/host/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/bluedroid/btc/core/btc_main.c @@ -97,7 +97,7 @@ static void btc_deinit_bluetooth(void) void btc_main_call_handler(btc_msg_t *msg) { - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTC_MAIN_ACT_INIT: @@ -127,101 +127,132 @@ uint32_t btc_get_ble_status(void) return status; } - #if (BLE_INCLUDED == TRUE) +#if (BLE_INCLUDED == TRUE) // Number of active advertising extern uint8_t btm_ble_adv_active_count(void); - if (btm_ble_adv_active_count()) { + uint8_t adv_cnt = btm_ble_adv_active_count(); + if (adv_cnt) { + BTC_TRACE_WARNING("%s advertising active, cnt %d", __func__, adv_cnt); status |= BIT(BTC_BLE_STATUS_ADV); } // Number of active scanning extern uint8_t btm_ble_scan_active_count(void); - if (btm_ble_scan_active_count()) { + uint8_t scan_cnt = btm_ble_scan_active_count(); + if (scan_cnt) { + BTC_TRACE_WARNING("%s scan active, cnt %d", __func__, scan_cnt); status |= BIT(BTC_BLE_STATUS_SCAN); } // Number of active GATT tcb extern uint8_t gatt_tcb_active_count(void); - if (gatt_tcb_active_count()) { + uint8_t gatt_tcb_cnt = gatt_tcb_active_count(); + if (gatt_tcb_cnt) { + BTC_TRACE_WARNING("%s gatt tcb active, cnt %d", __func__, gatt_tcb_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Number of active ACL connection extern uint8_t btm_ble_acl_active_count(void); - if (btm_ble_acl_active_count()) { + uint8_t acl_cnt = btm_ble_acl_active_count(); + if (acl_cnt) { + BTC_TRACE_WARNING("%s acl connection active, cnt %d", __func__, acl_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Number of active L2C plcb extern uint8_t l2cu_ble_plcb_active_count(void); - if (l2cu_ble_plcb_active_count()) { + uint8_t plcb_cnt = l2cu_ble_plcb_active_count(); + if (plcb_cnt) { + BTC_TRACE_WARNING("%s l2c plcb active, cnt %d", __func__, plcb_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Address resolve status extern uint8_t btm_get_ble_addr_resolve_disable_status(void); - if (btm_get_ble_addr_resolve_disable_status()) { + uint8_t addr_resolve_disable = btm_get_ble_addr_resolve_disable_status(); + if (addr_resolve_disable) { + BTC_TRACE_WARNING("%s address resolve disabled", __func__); status |= BIT(BTC_BLE_STATUS_ADDR_RESOLVE_DISABLE); } - #if (SMP_INCLUDED == TRUE) +#if (SMP_INCLUDED == TRUE) // Number of recorded devices extern uint8_t btm_ble_sec_dev_record_count(void); - if (btm_ble_sec_dev_record_count()) { + uint8_t sec_dev_cnt = btm_ble_sec_dev_record_count(); + if (sec_dev_cnt) { + BTC_TRACE_WARNING("%s security device record count %d", __func__, sec_dev_cnt); status |= BIT(BTC_BLE_STATUS_DEVICE_REC); } // Number of saved bonded devices - if (btc_storage_get_num_ble_bond_devices()) { + int bond_cnt = btc_storage_get_num_ble_bond_devices(); + if (bond_cnt) { + BTC_TRACE_WARNING("%s bonded devices count %d", __func__, bond_cnt); status |= BIT(BTC_BLE_STATUS_BOND); } - #endif +#endif // SMP_INCLUDED - #if (BLE_PRIVACY_SPT == TRUE) +#if (BLE_PRIVACY_SPT == TRUE) // Privacy enabled extern uint8_t btm_ble_privacy_is_enabled(void); - if (btm_ble_privacy_is_enabled()) { + uint8_t privacy_en = btm_ble_privacy_is_enabled(); + if (privacy_en) { + BTC_TRACE_WARNING("%s privacy enabled", __func__); status |= BIT(BTC_BLE_STATUS_PRIVACY); } - #endif - #endif +#endif // BLE_PRIVACY_SPT + +#endif // BLE_INCLUDED - #if (BLE_50_EXTEND_ADV_EN == TRUE) +#if (BLE_50_EXTEND_ADV_EN == TRUE) // Number of active extended advertsing extern uint8_t btm_ble_ext_adv_active_count(void); - if (btm_ble_ext_adv_active_count()) { + uint8_t ext_adv_cnt = btm_ble_ext_adv_active_count(); + if (ext_adv_cnt) { + BTC_TRACE_WARNING("%s extended advertising active, cnt %d", __func__, ext_adv_cnt); status |= BIT(BTC_BLE_STATUS_EXT_ADV); } - #endif +#endif // (BLE_50_EXTEND_ADV_EN == TRUE) - #if (GATTC_INCLUDED == TRUE) +#if (GATTC_INCLUDED == TRUE) // Number of registered GATTC APP extern uint8_t bta_gattc_cl_rcb_active_count(void); - if (bta_gattc_cl_rcb_active_count()) { + uint8_t gattc_app_cnt = bta_gattc_cl_rcb_active_count(); + if (gattc_app_cnt) { + BTC_TRACE_WARNING("%s GATTC app active, cnt %d", __func__, gattc_app_cnt); status |= BIT(BTC_BLE_STATUS_GATTC_APP); } // Number of saved GATTC cache extern UINT8 bta_gattc_co_get_addr_num(void); - if (bta_gattc_co_get_addr_num()) { + uint8_t gattc_cache_cnt = bta_gattc_co_get_addr_num(); + if (gattc_cache_cnt) { + BTC_TRACE_WARNING("%s GATTC cache count %d", __func__, gattc_cache_cnt); status |= BIT(BTC_BLE_STATUS_GATTC_CACHE); } - #endif +#endif // GATTC_INCLUDED - #if (GATTS_INCLUDED == TRUE) +#if (GATTS_INCLUDED == TRUE) // Number of registered GATTS service extern uint8_t bta_gatts_srvc_active_count(void); - if (bta_gatts_srvc_active_count()) { + uint8_t gatts_srvc_cnt = bta_gatts_srvc_active_count(); + if (gatts_srvc_cnt) { + BTC_TRACE_WARNING("%s GATTS service active, cnt %d", __func__, gatts_srvc_cnt); status |= BIT(BTC_BLE_STATUS_GATTS_SRVC); } - #endif +#endif // GATTS_INCLUDED - #if SMP_INCLUDED == TRUE +#if (SMP_INCLUDED == TRUE) extern uint8_t smp_get_state(void); - if (smp_get_state()) { + uint8_t smp_state = smp_get_state(); + if (smp_state) { + BTC_TRACE_WARNING("%s SMP state active, state=%d", __func__, smp_state); status |= BIT(BTC_BLE_STATUS_SMP_STATE); } - #endif +#endif // SMP_INCLUDED + + BTC_TRACE_WARNING("%s exit, final status=0x%x", __func__, status); return status; } diff --git a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c index 4f359030434d..5e63dfe54c4e 100644 --- a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c +++ b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c @@ -62,6 +62,9 @@ static void queue_int_advance(void) void btc_profile_queue_handler(btc_msg_t *msg) { btc_prf_que_args_t *arg = (btc_prf_que_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_PRF_QUE_CONNECT: queue_int_add(&(arg->connect_node)); diff --git a/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c b/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c index 11126e08809a..684c4e1da766 100644 --- a/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c +++ b/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -115,7 +115,7 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) //uuid = {LEN_UUID_16, {ATT_CHAR_BUTTON_WIT}}; //start the button service after created esp_ble_gatts_start_srvc(p_data->create.service_id); - //add the frist button characteristic --> write characteristic + //add the first button characteristic --> write characteristic esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid, (GATT_PERM_WRITE | GATT_PERM_READ), (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE)); @@ -128,15 +128,15 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); //save the att handle to the env button_cb_env.button_inst.but_wirt_hdl = p_data->add_result.attr_id; - //add the frist button characteristic --> Notify characteristic + //add the first button characteristic --> Notify characteristic esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid, GATT_PERM_READ, (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY)); - } else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF) { // add the gattc config descriptor to the notify charateristic + } else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF) { // add the gattc config descriptor to the notify characteristic //tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE); uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; button_cb_env.button_inst.but_ntf_hdl = p_data->add_result.attr_id; esp_ble_gatts_add_char_descr (button_cb_env.clcb.cur_srvc_id, - (GATT_PERM_WRITE | GATT_PERM_WRITE), + GATT_PERM_WRITE, &uuid); } @@ -151,7 +151,7 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) //BTA_GATTS_Listen(button_cb_env.gatt_if, true, NULL); break; case ESP_GATTS_CONNECT_EVT: - BTC_TRACE_ERROR("############BUTTON CONNCET EVT################\n"); + BTC_TRACE_ERROR("############BUTTON CONNECT EVT################\n"); //esp_ble_stop_advertising(); //set the connection flag to true button_env_clcb_alloc(p_data->conn.conn_id, p_data->conn.remote_bda); @@ -232,7 +232,7 @@ but_clcb_t *button_env_clcb_alloc (uint16_t conn_id, BD_ADDR remote_bda) ** ** Function button_env_find_conn_id_by_bd_adddr ** -** Description The function searches all LCB with macthing bd address +** Description The function searches all LCB with matching bd address ** ** Returns total number of clcb found. ** @@ -280,7 +280,7 @@ BOOLEAN button_env_clcb_dealloc(uint16_t conn_id) ** ** Function button_init ** -** Description Initializa the GATT Service for button profiles. +** Description Initialize the GATT Service for button profiles. ** *******************************************************************************/ esp_gatt_status_t button_init (but_prf_cb_t call_back) @@ -323,7 +323,7 @@ void button_msg_notify(uint16_t len, uint8_t *button_msg) //notify rsp==false; indicate rsp==true. BOOLEAN rsp = false; if (!conn_status && button_cb_env.clcb.congest) { - BTC_TRACE_ERROR("the conneciton for button profile has been loss\n"); + BTC_TRACE_ERROR("the connection for button profile has been loss\n"); return; } diff --git a/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c b/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c index 9ba7ceed69aa..13b3998da34d 100644 --- a/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c +++ b/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c @@ -1,6 +1,6 @@ #include "wx_airsync_prf.h" /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,7 +91,7 @@ static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) airsync_cb_env.is_primery = p_data->create.is_primary; //start the airsync service after created esp_ble_gatts_start_srvc(p_data->create.service_id); - //add the frist airsync characteristic --> write characteristic + //add the first airsync characteristic --> write characteristic esp_ble_gatts_add_char(airsync_cb_env.clcb.cur_srvc_id, &uuid, (GATT_PERM_WRITE | GATT_PERM_READ), (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE)); @@ -112,7 +112,7 @@ static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; airsync_cb_env.airsync_inst.airsync_ntf_hdl = p_data->add_result.attr_id; esp_ble_gatts_add_char_descr (airsync_cb_env.clcb.cur_srvc_id, - (GATT_PERM_WRITE | GATT_PERM_WRITE), + GATT_PERM_WRITE, &uuid); uuid.uu.uuid16 = ATT_CHAR_AIRSYNC_READ; @@ -207,7 +207,7 @@ tAirSync_CLCB *airsync_env_clcb_alloc (UINT16 conn_id, BD_ADDR remote_bda) ** ** Function airsync_env_find_conn_id_by_bd_adddr ** -** Description The function searches all LCB with macthing bd address +** Description The function searches all LCB with matching bd address ** ** Returns total number of clcb found. ** @@ -231,7 +231,7 @@ UINT16 airsync_env_find_conn_id_by_bd_adddr(BD_ADDR remote_bda) ** ** Function airsync_init ** -** Description Initializa the GATT Service for airsync profiles. +** Description Initialize the GATT Service for airsync profiles. ** *******************************************************************************/ tGATT_STATUS AirSync_Init(tAIRSYNC_CBACK *call_back) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 0c690065a216..67b54deea899 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -61,6 +61,7 @@ static inline void btc_gap_ble_cb_to_app(esp_gap_ble_cb_event_t event, esp_ble_g esp_gap_ble_cb_t btc_gap_ble_cb = (esp_gap_ble_cb_t)btc_profile_cb_get(BTC_PID_GAP_BLE); if (btc_gap_ble_cb) { btc_gap_ble_cb(event, param); + BTC_TRACE_DEBUG("btc_gap_ble_cb_to_app, event=%d", event); } } @@ -1768,6 +1769,8 @@ void btc_gap_ble_cb_handler(btc_msg_t *msg) { esp_ble_gap_cb_param_t *param = (esp_ble_gap_cb_param_t *)msg->arg; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + if (msg->act < ESP_GAP_BLE_EVT_MAX) { btc_gap_ble_cb_to_app(msg->act, param); } else { @@ -2177,7 +2180,7 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_5_gap_args_t *arg_5 = (btc_ble_5_gap_args_t *)msg->arg; #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) - BTC_TRACE_DEBUG("%s act %d\n", __FUNCTION__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { #if (BLE_42_FEATURE_SUPPORT == TRUE) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c index e1278954c4ee..099bea519fd9 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -290,14 +290,14 @@ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_d /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */ switch (event) { case BTA_DM_INQ_RES_EVT: { - if (p_data->inq_res.p_eir) { + if (p_data && p_data->inq_res.p_eir) { param_len += HCI_EXT_INQ_RESPONSE_LEN; } } break; case BTA_DM_DISC_RES_EVT: { - if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { + if (p_data && p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { param_len += p_data->disc_res.raw_data_size; } } @@ -305,7 +305,7 @@ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_d } /* if remote name is available in EIR, set the flag so that stack doesn't trigger RNR */ - if (event == BTA_DM_INQ_RES_EVT) { + if (p_data && (event == BTA_DM_INQ_RES_EVT)) { p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL); } @@ -457,7 +457,7 @@ static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_S } /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */ if (event == BTA_DM_DISC_RES_EVT) { - if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { + if (p_data && p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { param_len += p_data->disc_res.raw_data_size; } } @@ -549,7 +549,7 @@ static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH switch (event) { case BTA_DM_DISC_RES_EVT: { - if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) { + if (p_data && (p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) { param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE); } } break; @@ -1063,7 +1063,9 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg) void btc_gap_bt_call_handler(btc_msg_t *msg) { btc_gap_bt_args_t *arg = (btc_gap_bt_args_t *)msg->arg; - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GAP_BT_ACT_SET_SCAN_MODE: { btc_bt_set_scan_mode(arg->set_scan_mode.c_mode, arg->set_scan_mode.d_mode); diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c index 45a2b834b52f..754878f0cb5a 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c @@ -23,7 +23,8 @@ static void btc_set_local_mtu(uint16_t mtu) void btc_gatt_com_call_handler(btc_msg_t *msg) { - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATT_ACT_SET_LOCAL_MTU: { diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c index 86221e3c895e..e8f7444368ea 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 @@ -24,6 +24,7 @@ static inline void btc_gattc_cb_to_app(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_cb_t btc_gattc_cb = (esp_gattc_cb_t )btc_profile_cb_get(BTC_PID_GATTC); if (btc_gattc_cb) { btc_gattc_cb(event, gattc_if, param); + BTC_TRACE_DEBUG("btc_gattc_cb_to_app, gattc_if %d, event=%d", gattc_if, event); } } @@ -714,6 +715,9 @@ static void btc_gattc_unreg_for_notify(btc_ble_gattc_args_t *arg) void btc_gattc_call_handler(btc_msg_t *msg) { btc_ble_gattc_args_t *arg = (btc_ble_gattc_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATTC_ACT_APP_REGISTER: btc_gattc_app_register(arg); @@ -803,6 +807,8 @@ void btc_gattc_cb_handler(btc_msg_t *msg) memset(¶m, 0, sizeof(esp_ble_gattc_cb_param_t)); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTA_GATTC_REG_EVT: { tBTA_GATTC_REG *reg_oper = &arg->reg_oper; diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c index 7eab806e2f54..e1b06cffbae7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,6 +37,7 @@ static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t { esp_gatts_cb_t btc_gatts_cb = (esp_gatts_cb_t)btc_profile_cb_get(BTC_PID_GATTS); if (btc_gatts_cb) { + BTC_TRACE_DEBUG("btc_gatts_cb_to_app, gatts_if %d, event=%d", gatts_if, event); btc_gatts_cb(event, gatts_if, param); } } @@ -616,6 +617,8 @@ void btc_gatts_call_handler(btc_msg_t *msg) { btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATTS_ACT_APP_REGISTER: { tBT_UUID uuid; @@ -764,6 +767,8 @@ void btc_gatts_cb_handler(btc_msg_t *msg) tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg; esp_gatt_if_t gatts_if; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTA_GATTS_REG_EVT: { gatts_if = p_data->reg_oper.server_if; diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c index 0e4947ee4141..b5a731f6a777 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c @@ -1134,6 +1134,8 @@ void btc_hf_call_handler(btc_msg_t *msg) { btc_hf_args_t *arg = (btc_hf_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HF_INIT_EVT: { diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c index 29019fc88135..5986943bfa4a 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c @@ -723,6 +723,9 @@ void btc_hd_call_arg_deep_free(btc_msg_t *msg) void btc_hd_call_handler(btc_msg_t *msg) { btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HD_INIT_EVT: btc_hd_init(); @@ -781,6 +784,8 @@ void btc_hd_cb_handler(btc_msg_t *msg) esp_hidd_cb_param_t param = {0}; BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event)); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (event) { case BTA_HD_ENABLE_EVT: BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status); diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c index c7adef20069b..dda5d0bf9d1d 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c @@ -1121,6 +1121,8 @@ void btc_hh_call_arg_deep_free(btc_msg_t *msg) void btc_hh_call_handler(btc_msg_t *msg) { btc_hidh_args_t *arg = (btc_hidh_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HH_INIT_EVT: btc_hh_init(); @@ -1229,6 +1231,7 @@ void btc_hh_cb_handler(btc_msg_t *msg) btc_hh_device_t *p_dev = NULL; int len, i; BTC_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(msg->act), btc_hh_cb.service_dereg_active); + switch (msg->act) { case BTA_HH_ENABLE_EVT: if (p_data->status == BTA_HH_OK) { diff --git a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c index 9155784fb852..84641f31c8fc 100644 --- a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c +++ b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c @@ -300,6 +300,7 @@ static inline void btc_l2cap_cb_to_app(esp_bt_l2cap_cb_event_t event, esp_bt_l2c { esp_bt_l2cap_cb_t btc_l2cap_cb = (esp_bt_l2cap_cb_t)btc_profile_cb_get(BTC_PID_L2CAP); if (btc_l2cap_cb) { + BTC_TRACE_DEBUG("btc_l2cap_cb_to_app, event=%d", event); btc_l2cap_cb(event, param); } } @@ -718,7 +719,7 @@ static void btc_l2cap_write(uint32_t handle) } l2cap_slot_t *slot = NULL; slot = l2cap_find_slot_by_handle(handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { if (!slot) { BTC_TRACE_ERROR("%s unable to find l2cap slot!", __func__); } else { @@ -748,7 +749,7 @@ static void btc_l2cap_disconnect(uint32_t handle) } l2cap_slot_t *slot = NULL; slot = l2cap_find_slot_by_handle(handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { if (!slot) { BTC_TRACE_ERROR("%s unable to find L2CAP slot! disconnect fail!", __func__); } else { @@ -772,6 +773,7 @@ static void btc_l2cap_disconnect(uint32_t handle) void btc_l2cap_call_handler(btc_msg_t *msg) { btc_l2cap_args_t *arg = (btc_l2cap_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTC_L2CAP_ACT_INIT: btc_l2cap_init(); @@ -809,6 +811,8 @@ void btc_l2cap_cb_handler(btc_msg_t *msg) uint8_t serial = 0; uint32_t count = 0; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (event) { case BTA_JV_ENABLE_EVT: param.init.status = p_data->status; diff --git a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c index ede18df37a3c..6bc1819872ba 100644 --- a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c +++ b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c @@ -392,7 +392,7 @@ static bool btc_pba_client_pull_vcard_listing(uint16_t handle, char *name, bool if (include_app_param) { uint8_t search_value_len = 0; - if (app_param->include_search_value) { + if (app_param->include_search_value && app_param->search_value) { search_value_len = strlen(app_param->search_value) + 1; } app_param_buff = osi_malloc(BTA_PBAP_PULL_VCARD_LISTING_APP_PARAM_BUFF_SIZE_MIN + search_value_len); diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 8607e4219121..31a71992dc80 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -713,7 +713,7 @@ static void btc_spp_disconnect(btc_spp_args_t *arg) spp_slot_t *slot = NULL; osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); slot = spp_find_slot_by_handle(arg->disconnect.handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { osi_mutex_unlock(&spp_local_param.spp_slot_mutex); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__); @@ -894,7 +894,7 @@ static void btc_spp_write(btc_spp_args_t *arg) spp_slot_t *slot = NULL; osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); slot = spp_find_slot_by_handle(arg->write.handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { osi_mutex_unlock(&spp_local_param.spp_slot_mutex); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); diff --git a/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c index 553b4eddd495..cb5ed0494706 100644 --- a/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c +++ b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c @@ -305,7 +305,6 @@ OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, return OI_CODEC_SBC_CHECKSUM_MISMATCH; } -#ifdef OI_DEBUG /* * Make sure the bitpool values are sane. */ @@ -317,7 +316,6 @@ OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo))); return OI_STATUS_INVALID_PARAMETERS; } -#endif /* * Now decode the SBC data. Partial decode is not yet implemented for an SBC diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index f91a2260d973..0baa265f2a11 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -357,7 +357,7 @@ int hci_adv_credits_prep_to_release(uint16_t num) hci_hal_env.adv_credits_to_release = credits_to_release; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); - if (credits_to_release == num && num != 0) { + if (credits_to_release == num) { osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_set(hci_hal_env.adv_flow_monitor, HCI_ADV_FLOW_MONITOR_PERIOD_MS); } diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 34bdb570938e..f87b7f7c8fca 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -618,3 +618,96 @@ const hci_t *hci_layer_get_interface(void) init_layer_interface(); return &interface; } + +#if !UC_BT_STACK_NO_LOG +/******************************************************************************* +** +** Function hci_status_code_to_string +** +** Description Converts an HCI status code to a human-readable string. +** If the code is not defined in the specification, the +** function returns "Unknown Status (0xXX)" where XX is the +** actual code value. +** Reference: BLUETOOTH CORE SPECIFICATION Version 5.4, +** Vol 1, Part F, p. 376 +** +** Parameters status : HCI status code +** +** Returns const char* : readable description of the status +** +*******************************************************************************/ +const char *hci_status_code_to_string(uint8_t status) +{ + switch (status) { + case HCI_SUCCESS: return "Success"; /* 0x00 */ + case HCI_ERR_ILLEGAL_COMMAND: return "Illegal Command"; /* 0x01 */ + case HCI_ERR_NO_CONNECTION: return "No Connection"; /* 0x02 */ + case HCI_ERR_HW_FAILURE: return "HW Failure"; /* 0x03 */ + case HCI_ERR_PAGE_TIMEOUT: return "Page Timeout"; /* 0x04 */ + case HCI_ERR_AUTH_FAILURE: return "Auth Failure"; /* 0x05 */ + case HCI_ERR_KEY_MISSING: return "Key Missing"; /* 0x06 */ + case HCI_ERR_MEMORY_FULL: return "Memory Full"; /* 0x07 */ + case HCI_ERR_CONNECTION_TOUT: return "Conn Timeout"; /* 0x08 */ + case HCI_ERR_MAX_NUM_OF_CONNECTIONS: return "Conn Limit Exceeded"; /* 0x09 */ + case HCI_ERR_MAX_NUM_OF_SCOS: return "Sync Conn Limit Exceeded"; /* 0x0A */ + case HCI_ERR_CONNECTION_EXISTS: return "Conn Exists"; /* 0x0B */ + case HCI_ERR_COMMAND_DISALLOWED: return "Cmd Disallowed"; /* 0x0C */ + case HCI_ERR_HOST_REJECT_RESOURCES: return "Rejected: Resources"; /* 0x0D */ + case HCI_ERR_HOST_REJECT_SECURITY: return "Rejected: Security"; /* 0x0E */ + case HCI_ERR_HOST_REJECT_DEVICE: return "Rejected: BD_ADDR"; /* 0x0F */ + case HCI_ERR_HOST_TIMEOUT: return "Accept Timeout"; /* 0x10 */ + case HCI_ERR_UNSUPPORTED_VALUE: return "Unsupported Value"; /* 0x11 */ + case HCI_ERR_ILLEGAL_PARAMETER_FMT: return "Invalid Param"; /* 0x12 */ + case HCI_ERR_PEER_USER: return "Terminated by Peer"; /* 0x13 */ + case HCI_ERR_PEER_LOW_RESOURCES: return "Peer Low Resources"; /* 0x14 */ + case HCI_ERR_PEER_POWER_OFF: return "Peer Power Off"; /* 0x15 */ + case HCI_ERR_CONN_CAUSE_LOCAL_HOST: return "Terminated by Host"; /* 0x16 */ + case HCI_ERR_REPEATED_ATTEMPTS: return "Repeated Attempts"; /* 0x17 */ + case HCI_ERR_PAIRING_NOT_ALLOWED: return "Pairing Not Allowed"; /* 0x18 */ + case HCI_ERR_UNKNOWN_LMP_PDU: return "Unknown LMP PDU"; /* 0x19 */ + case HCI_ERR_UNSUPPORTED_REM_FEATURE: return "Unsupported Remote Feature"; /* 0x1A */ + case HCI_ERR_SCO_OFFSET_REJECTED: return "SCO Offset Rejected"; /* 0x1B */ + case HCI_ERR_SCO_INTERVAL_REJECTED: return "SCO Interval Rejected"; /* 0x1C */ + case HCI_ERR_SCO_AIR_MODE: return "SCO Air Mode Rejected"; /* 0x1D */ + case HCI_ERR_INVALID_LMP_PARAM: return "Invalid LMP/LL Param"; /* 0x1E */ + case HCI_ERR_UNSPECIFIED: return "Unspecified Error"; /* 0x1F */ + case HCI_ERR_UNSUPPORTED_LMP_PARAMETERS: return "Unsupported LMP/LL"; /* 0x20 */ + case HCI_ERR_ROLE_CHANGE_NOT_ALLOWED: return "Role Change Not Allowed"; /* 0x21 */ + case HCI_ERR_LMP_RESPONSE_TIMEOUT: return "LMP/LL Response Timeout"; /* 0x22 */ + case HCI_ERR_LMP_ERR_TRANS_COLLISION: return "Transaction Collision"; /* 0x23 */ + case HCI_ERR_LMP_PDU_NOT_ALLOWED: return "LMP PDU Not Allowed"; /* 0x24 */ + case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: return "Encryption Not Acceptable"; /* 0x25 */ + case HCI_ERR_UNIT_KEY_USED: return "Link Key Used"; /* 0x26 */ + case HCI_ERR_QOS_NOT_SUPPORTED: return "QoS Not Supported"; /* 0x27 */ + case HCI_ERR_INSTANT_PASSED: return "Instant Passed"; /* 0x28 */ + case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: return "Pairing w/ Unit Key Not Supported"; /* 0x29 */ + case HCI_ERR_DIFF_TRANSACTION_COLLISION: return "Transaction Collision"; /* 0x2A */ + case HCI_ERR_UNDEFINED_0x2B: return "Reserved"; /* 0x2B */ + case HCI_ERR_QOS_UNACCEPTABLE_PARAM: return "QoS Unacceptable"; /* 0x2C */ + case HCI_ERR_QOS_REJECTED: return "QoS Rejected"; /* 0x2D */ + case HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED: return "Chan Classif Not Supported"; /* 0x2E */ + case HCI_ERR_INSUFFCIENT_SECURITY: return "Insufficient Security"; /* 0x2F */ + case HCI_ERR_PARAM_OUT_OF_RANGE: return "Param Out of Range"; /* 0x30 */ + case HCI_ERR_UNDEFINED_0x31: return "Reserved"; /* 0x31 */ + case HCI_ERR_ROLE_SWITCH_PENDING: return "Role Switch Pending"; /* 0x32 */ + case HCI_ERR_UNDEFINED_0x33: return "Reserved"; /* 0x33 */ + case HCI_ERR_RESERVED_SLOT_VIOLATION: return "Slot Violation"; /* 0x34 */ + case HCI_ERR_ROLE_SWITCH_FAILED: return "Role Switch Failed"; /* 0x35 */ + case HCI_ERR_INQ_RSP_DATA_TOO_LARGE: return "Inquiry Response Too Large"; /* 0x36 */ + case HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED: return "Simple Pairing Not Supported"; /* 0x37 */ + case HCI_ERR_HOST_BUSY_PAIRING: return "Host Busy"; /* 0x38 */ + case HCI_ERR_REJ_NO_SUITABLE_CHANNEL: return "No Suitable Channel"; /* 0x39 */ + case HCI_ERR_CONTROLLER_BUSY: return "Controller Busy"; /* 0x3A */ + case HCI_ERR_UNACCEPT_CONN_INTERVAL: return "Unacceptable Conn Interval"; /* 0x3B */ + case HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT: return "Adv Timeout"; /* 0x3C */ + case HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE: return "MIC Failure"; /* 0x3D */ + case HCI_ERR_CONN_FAILED_ESTABLISHMENT: return "Conn Failed"; /* 0x3E */ + case HCI_ERR_MAC_CONNECTION_FAILED: return "Previously Used"; /* 0x3F */ + default: { + static char buf[24]; + snprintf(buf, sizeof(buf), "Unknown Status (0x%02X)", status); + return buf; + } + } +} +#endif diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index c48d05655e6a..356f2c044b57 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -112,3 +112,5 @@ int hci_adv_credits_force_release(uint16_t num); #endif #endif // #if (BLE_42_SCAN_EN == TRUE) #endif /* _HCI_LAYER_H_ */ + +const char *hci_status_code_to_string(uint8_t status); diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index 9b444ab69cd6..f0ee53143301 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -26,7 +26,7 @@ #include "osi/hash_map.h" #include "osi/hash_functions.h" #include "common/bt_trace.h" - +#include "esp_log.h" #define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000) #define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000) @@ -180,7 +180,8 @@ static void reassemble_and_dispatch(BT_HDR *packet) partial_packet = (BT_HDR *)osi_calloc(full_length + sizeof(BT_HDR)); if (partial_packet == NULL) { - HCI_TRACE_WARNING("%s full_length %d no memory.\n", __func__, full_length); + HCI_TRACE_WARNING("%s full_length %d no memory, free=%d, largest_block=%d", __func__, full_length, + heap_caps_get_free_size(MALLOC_CAP_DEFAULT), heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)); assert(0); } diff --git a/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c b/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c index b83219dceb38..98dbaed809ca 100644 --- a/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c +++ b/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c @@ -86,6 +86,11 @@ static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf) AVCT_TRACE_WARNING("Got start during reassembly"); } osi_free(p_lcb->p_rx_msg); + p_lcb->p_rx_msg = NULL; + if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) { + osi_free(p_buf); + return NULL; + } /* Allocate bigger buffer for reassembly. As lower layers are * not aware of possible packet size after reassembly they * would have allocated smaller buffer. diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c index a049eee925a1..74b7b791846c 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c @@ -1279,7 +1279,7 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) UINT8 *p; UINT8 pkt_type; BT_HDR *p_ret; - UINT16 buf_len; + size_t buf_len; /* parse the message header */ p = (UINT8 *)(p_buf + 1) + p_buf->offset; @@ -1314,6 +1314,10 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) * not aware of possible packet size after reassembly, they * would have allocated smaller buffer. */ + if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) { + osi_free(p_buf); + return NULL; + } p_ccb->p_rx_msg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE); memcpy(p_ccb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len); @@ -1351,7 +1355,7 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) p_buf->len -= AVDT_LEN_TYPE_CONT; /* verify length */ - if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) { + if (((size_t)p_ccb->p_rx_msg->offset + (size_t)p_buf->len) > buf_len) { /* won't fit; free everything */ AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__); osi_free(p_ccb->p_rx_msg); diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_scb.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb.c index 43bc4452c9b3..ca1e9f4c0fd2 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_scb.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_scb.c @@ -749,14 +749,14 @@ UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_s switch (state) { case AVDT_VERIFY_OPEN: case AVDT_VERIFY_START: - if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST) { + if (p_scb && p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST) { *p_err_code = AVDT_ERR_BAD_STATE; } break; case AVDT_VERIFY_SUSPEND: case AVDT_VERIFY_STREAMING: - if (p_scb->state != AVDT_SCB_STREAM_ST) { + if (p_scb && p_scb->state != AVDT_SCB_STREAM_ST) { *p_err_code = AVDT_ERR_BAD_STATE; } break; diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c index c87e044fbcb4..5fae98eed8aa 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c @@ -252,10 +252,16 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) UINT16 offset; UINT16 ex_len; UINT8 pad_len = 0; + uint16_t len = p_data->p_pkt->len; p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset; /* parse media packet header */ + offset = 12; // AVDT_MSG_PRS_OCTET1(1) + AVDT_MSG_PRS_M_PT(1) + UINT16(2) + UINT32(4) + 4 + if (len < offset) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, offset); + goto length_error; + } AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc); AVDT_MSG_PRS_M_PT(p, m_pt, marker); BE_STREAM_TO_UINT16(seq, p); @@ -265,10 +271,16 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) UNUSED(o_v); /* skip over any csrc's in packet */ + offset += o_cc * 4; p += o_cc * 4; /* check for and skip over extension header */ if (o_x) { + offset += 4; + if (len < offset) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, offset); + goto length_error; + } p += 2; BE_STREAM_TO_UINT16(ex_len, p); p += ex_len * 4; @@ -276,18 +288,20 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) /* save our new offset */ offset = (UINT16) (p - p_start); + if (len <= offset) { + goto length_error; + } /* adjust length for any padding at end of packet */ if (o_p) { /* padding length in last byte of packet */ - pad_len = *(p_start + p_data->p_pkt->len); + pad_len = *(p_start + len - 1); } /* do sanity check */ - if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len)) { + if (pad_len >= len - offset) { AVDT_TRACE_WARNING("Got bad media packet"); - osi_free(p_data->p_pkt); - p_data->p_pkt = NULL; + goto length_error; } /* adjust offset and length and send it up */ else { @@ -303,18 +317,22 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) #if AVDT_MULTIPLEXING == TRUE if ((p_scb->cs.p_media_cback != NULL) && (p_scb->p_media_buf != NULL) - && (p_scb->media_buf_len > p_data->p_pkt->len)) { + && (p_scb->media_buf_len > len)) { /* media buffer enough length is assigned by application. Lets use it*/ memcpy(p_scb->p_media_buf, (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset, - p_data->p_pkt->len); + len); (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_scb->p_media_buf, p_scb->media_buf_len, time_stamp, seq, m_pt, marker); } #endif - osi_free(p_data->p_pkt); - p_data->p_pkt = NULL; + goto length_error; } } + return; + +length_error: + osi_free(p_data->p_pkt); + p_data->p_pkt = NULL; } #if AVDT_REPORTING == TRUE @@ -333,13 +351,18 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) UINT8 *p_start = p; UINT32 ssrc; UINT8 o_v, o_p, o_cc; + UINT32 min_len = 0; AVDT_REPORT_TYPE pt; - tAVDT_REPORT_DATA report, *p_rpt; + tAVDT_REPORT_DATA report; AVDT_TRACE_DEBUG( "avdt_scb_hdl_report"); if (p_scb->cs.p_report_cback) { - p_rpt = &report; /* parse report packet header */ + min_len += 8; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc); pt = *p++; p += 2; @@ -352,6 +375,11 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) switch (pt) { case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */ + min_len += 20; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } BE_STREAM_TO_UINT32(report.sr.ntp_sec, p); BE_STREAM_TO_UINT32(report.sr.ntp_frac, p); BE_STREAM_TO_UINT32(report.sr.rtp_time, p); @@ -360,6 +388,11 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) break; case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */ + min_len += 20; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } report.rr.frag_lost = *p; BE_STREAM_TO_UINT32(report.rr.packet_lost, p); report.rr.packet_lost &= 0xFFFFFF; @@ -370,11 +403,32 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) break; case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */ - if (*p == AVDT_RTCP_SDES_CNAME) { - p_rpt = (tAVDT_REPORT_DATA *)(p + 2); + min_len += 1; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + uint8_t sdes_type; + BE_STREAM_TO_UINT8(sdes_type, p); + if (sdes_type == AVDT_RTCP_SDES_CNAME) { + min_len += 1; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + uint8_t name_length; + BE_STREAM_TO_UINT8(name_length, p);\ + if ((name_length > len - min_len) || (name_length > AVDT_MAX_CNAME_SIZE)) { + result = AVDT_BAD_PARAMS; + } else { + BE_STREAM_TO_ARRAY(p, &(report.cname[0]), name_length); + } } else { - AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s\n", - ssrc, o_cc, *p, *(p + 1), p + 2); + if (len < min_len + 1) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d\n", ssrc, o_cc, sdes_type, *p); result = AVDT_BUSY; } break; @@ -385,10 +439,12 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) } if (result == AVDT_SUCCESS) { - (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt); + (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, &report); } } + +avdt_scb_hdl_report_exit: p_start += len; return p_start; } @@ -624,7 +680,7 @@ void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) #endif #if AVDT_MULTIPLEXING == TRUE - /* select right function in dependance of is fragmentation supported or not */ + /* select right function in dependence of is fragmentation supported or not */ if ( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)) { avdt_scb_hdl_pkt_frag(p_scb, p_data); } else diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_api.c b/components/bt/host/bluedroid/stack/avrc/avrc_api.c index f7e31022d0da..8f9646408fbd 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_api.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_api.c @@ -200,7 +200,7 @@ static void avrc_send_continue_frag(UINT8 handle, UINT8 label) if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) { int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset); p_pkt_old = p_fcb->p_fmsg; - p_pkt = (BT_HDR *)osi_malloc((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE)); + p_pkt = (BT_HDR *)osi_calloc((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE)); if (p_pkt) { p_pkt->len = AVRC_MAX_CTRL_DATA_LEN; p_pkt->offset = AVCT_MSG_OFFSET; @@ -526,7 +526,7 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr, tAVRC_MSG_VENDOR *p_msg = &msg.vendor; if (cr == AVCT_CMD && - (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len))) { + (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < p_pkt->len)) { /* Ignore the invalid AV/C command frame */ #if (BT_USE_TRACES == TRUE) p_drop_msg = "dropped - too long AV/C cmd frame size"; diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c index 72f2651397bb..80874aa39774 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c @@ -55,13 +55,27 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p if (p_msg->p_vendor_data == NULL) { return AVRC_STS_INTERNAL_ERR; } + if (p_msg->vendor_len < 4) { + AVRC_TRACE_WARNING("message length %u too short: must be at least 4", p_msg->vendor_len); + return AVRC_STS_INTERNAL_ERR; + } p = p_msg->p_vendor_data; BE_STREAM_TO_UINT8 (p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16 (len, p); AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); + + if (p_msg->vendor_len < len + 4) { + AVRC_TRACE_WARNING("message length %u too short: must be at least %u", p_msg->vendor_len, len + 4); + return AVRC_STS_INTERNAL_ERR; + } + if (p_msg->hdr.ctype == AVRC_RSP_REJ) { + if (len < 1) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 1", len); + return AVRC_STS_INTERNAL_ERR; + } p_result->rsp.status = *p; return p_result->rsp.status; } @@ -82,10 +96,18 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) + if (len < 1) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 1", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT8 (eventid, p); if (AVRC_EVT_VOLUME_CHANGE == eventid && (AVRC_RSP_CHANGED == p_msg->hdr.ctype || AVRC_RSP_INTERIM == p_msg->hdr.ctype || AVRC_RSP_REJ == p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) { + if (len < 2) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 2", len); + return AVRC_STS_INTERNAL_ERR; + } p_result->reg_notif.status = p_msg->hdr.ctype; p_result->reg_notif.event_id = eventid; BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); @@ -95,18 +117,30 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p break; #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */ + if (len < 2) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 2", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT8 (p_result->get_caps.capability_id, p); BE_STREAM_TO_UINT8 (p_result->get_caps.count, p); if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED) { if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_EVT_ID) { status = AVRC_STS_INTERNAL_ERR; } else { + if (len < 2 + p_result->get_caps.count) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least %d", len, 2 + p_result->get_caps.count); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_ARRAY(p, p_result->get_caps.param.event_id, p_result->get_caps.count); } } else if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID) { if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_COMP_ID) { status = AVRC_STS_INTERNAL_ERR; } else { + if (len < 2 + p_result->get_caps.count * 6) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least %d", len, 2 + p_result->get_caps.count * 6); + return AVRC_STS_INTERNAL_ERR; + } for (int i = 0; i < p_result->get_caps.count; ++i) { BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[i], p); } @@ -115,6 +149,10 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p break; case AVRC_PDU_GET_PLAY_STATUS: if (p_msg->hdr.ctype == AVRC_RSP_IMPL_STBL) { + if (len < 9) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 9", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p); BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p); BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p); diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c index a5fed6b2b021..cae87a2a9e0f 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c @@ -242,7 +242,11 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_ status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); - BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + if (AVRC_IS_VALID_EVENT_ID(p_result->reg_notif.event_id)) { + BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + } else { + status = AVRC_STS_BAD_PARAM; + } } break; diff --git a/components/bt/host/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c index fdce6261ff2b..6350f4ba26d8 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_acl.c @@ -792,6 +792,11 @@ void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) if (p == NULL) { return; } + /* if we are trying to drop encryption on an encrypted connection, drop the connection */ + if (!encr_enable && (p->encrypt_state == BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON)) { + btm_sec_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY); + return; + } /* Process Role Switch if active */ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) { /* if encryption turn off failed we still will try to switch role */ @@ -2300,7 +2305,7 @@ void BTM_BleGetPeriodicAdvListSize(uint8_t *size) ** Returns void ** *******************************************************************************/ -void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) +void btm_read_tx_power_complete (UINT8 *p, UINT16 evt_len, BOOLEAN is_ble) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb; tBTM_TX_POWER_RESULTS results; @@ -2313,12 +2318,23 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) btm_cb.devcb.p_tx_power_cmpl_cb = NULL; if (p_cb) { + if (evt_len < 1) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } + STREAM_TO_UINT8 (results.hci_status, p); if (results.hci_status == HCI_SUCCESS) { results.status = BTM_SUCCESS; if (!is_ble) { + if (evt_len < 1 + 3) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (results.tx_power, p); @@ -2330,6 +2346,11 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) } #if BLE_INCLUDED == TRUE else { + if (evt_len < 1 + 1) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT8 (results.tx_power, p); memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN); } @@ -2340,6 +2361,7 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) results.status = BTM_ERR_PROCESSING; } +err_out: (*p_cb)(&results); } } @@ -2411,7 +2433,7 @@ void btm_read_channel_map_complete(UINT8 *p) ** Returns void ** *******************************************************************************/ -void btm_read_rssi_complete (UINT8 *p) +void btm_read_rssi_complete (UINT8 *p, UINT16 evt_len) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb; tBTM_RSSI_RESULTS results; @@ -2424,11 +2446,21 @@ void btm_read_rssi_complete (UINT8 *p) btm_cb.devcb.p_rssi_cmpl_cb = NULL; if (p_cb) { + if (evt_len < 1) { + BTM_TRACE_ERROR("Bogus event packet, too short"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT8 (results.hci_status, p); if (results.hci_status == HCI_SUCCESS) { results.status = BTM_SUCCESS; + if (evt_len < 1 + 3) { + BTM_TRACE_ERROR("Bogus event packet, too short"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (results.rssi, p); @@ -2444,6 +2476,7 @@ void btm_read_rssi_complete (UINT8 *p) results.status = BTM_ERR_PROCESSING; } +err_out: (*p_cb)(&results); } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c index 27ebe49dcfeb..d65e6329319f 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble.c @@ -2393,7 +2393,7 @@ BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); UINT8 p_mac[BTM_CMAC_TLEN_SIZE]; - if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) { + if (p_rec == NULL || !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK)) { BTM_TRACE_ERROR("can not verify signature for unknown device"); } else if (counter < p_rec->ble.keys.counter) { BTM_TRACE_ERROR("signature received with out dated sign counter"); @@ -2959,6 +2959,15 @@ uint8_t btm_ble_sec_dev_record_count(void) for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { p_dev_rec = list_node(p_node); if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE) && (p_dev_rec->ble.key_type != BTM_LE_KEY_NONE)) { + BTM_TRACE_DEBUG("%s BLE security device #%d: bd_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + count, + p_dev_rec->bd_addr[0], + p_dev_rec->bd_addr[1], + p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], + p_dev_rec->bd_addr[4], + p_dev_rec->bd_addr[5]); count++; } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index e82d95f61eab..4b3372504e50 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -1395,6 +1395,12 @@ uint8_t btm_ble_ext_adv_active_count(void) for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++) { if (adv_record[i].enabled == true) { + BTM_TRACE_DEBUG("%s EXT ADV active #%d: instance=%d, duration=%d, max_events=%d", + __func__, + count, + adv_record[i].instance, + adv_record[i].duration, + adv_record[i].max_events); count++; } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c index 9da09143063d..7eef55e9120d 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c @@ -429,8 +429,7 @@ BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filte for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if ((p_addr_filter->in_use) && (NULL == p_bd_addr || - (NULL != p_bd_addr && - memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) { + (memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0)) { found = TRUE; memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT)); @@ -915,7 +914,7 @@ tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action, if (NULL == p_bda_filter || /* not a generic filter */ - (p_target != NULL && p_bda_filter)) { + (p_target != NULL)) { BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!"); return st; } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 973f32754a3a..e43185e72dd3 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -3744,7 +3744,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt 3. For same address and scan response, do nothing */ int same_addr = memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN); - if (same_addr != 0 || (same_addr == 0 && evt_type != BTM_BLE_SCAN_RSP_EVT)) { + if (same_addr != 0 || (evt_type != BTM_BLE_SCAN_RSP_EVT)) { btm_ble_process_last_adv_pkt(); } @@ -3795,8 +3795,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt /* new device */ if (p_i == NULL || /* assume a DUMO device, BR/EDR inquiry is always active */ - (p_i && - (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE && + ((p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE && p_i->scan_rsp)) { BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry.."); diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 39784bb11ad2..ccc7f6e0b7c4 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -227,6 +227,7 @@ void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, BOOLEAN add) void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len) { UINT8 status = 0; + STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status=%d", __func__, status); @@ -984,6 +985,10 @@ BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec) *******************************************************************************/ void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec) { + BTM_TRACE_EVENT ("%s - bd_addr=%02x:%02x:%02x:%02x:%02x:%02x", __func__, + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state; BTM_TRACE_EVENT ("%s\n", __func__); diff --git a/components/bt/host/bluedroid/stack/btm/btm_dev.c b/components/bt/host/bluedroid/stack/btm/btm_dev.c index 7e1095f4a51d..1784d4a35356 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_dev.c +++ b/components/bt/host/bluedroid/stack/btm/btm_dev.c @@ -335,7 +335,8 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr) BOOLEAN new_entry_found = FALSE; BOOLEAN old_entry_found = FALSE; BOOLEAN malloc_new_entry = FALSE; - BTM_TRACE_EVENT ("btm_sec_alloc_dev\n"); + BTM_TRACE_EVENT ("btm_sec_alloc_dev - start alloc for device %02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { p_dev_old_rec = list_node(p_node); /* look for old entry which match the bd_addr and the BTM_SEC_IN_USE is cleared */ @@ -691,6 +692,14 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) old_ts = p_dev_rec->timestamp; } } + + if (p_oldest) { + BTM_TRACE_EVENT("oldest paired device found: bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, timestamp=%u", + p_oldest->bd_addr[0], p_oldest->bd_addr[1], p_oldest->bd_addr[2], + p_oldest->bd_addr[3], p_oldest->bd_addr[4], p_oldest->bd_addr[5], + p_oldest->timestamp); + } + return (p_oldest); } /******************************************************************************* diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 2250c78bd4d6..63c26e881e78 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -1203,7 +1203,7 @@ tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb) ** Returns void ** *******************************************************************************/ -void btm_delete_stored_link_key_complete (UINT8 *p) +void btm_delete_stored_link_key_complete (UINT8 *p, UINT16 evt_len) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb; tBTM_DELETE_STORED_LINK_KEY_COMPLETE result; @@ -1215,10 +1215,16 @@ void btm_delete_stored_link_key_complete (UINT8 *p) /* Set the call back event to indicate command complete */ result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS; + if (evt_len < 3) { + BTM_TRACE_ERROR("Malformatted event packet, too short"); + result.status = BTM_ERR_PROCESSING; + goto err_out; + } /* Extract the result fields from the HCI event */ STREAM_TO_UINT8 (result.status, p); STREAM_TO_UINT16 (result.num_keys, p); +err_out: /* Call the call back and pass the result */ (*p_cb)(&result); } diff --git a/components/bt/host/bluedroid/stack/btm/btm_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c index 41a47300e729..c74f2b439617 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/host/bluedroid/stack/btm/btm_inq.c @@ -1860,7 +1860,7 @@ void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) /* new device response */ && ( p_i == NULL || /* existing device with BR/EDR info */ - (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) + ((p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) ) #endif diff --git a/components/bt/host/bluedroid/stack/btm/btm_main.c b/components/bt/host/bluedroid/stack/btm/btm_main.c index 67882af0efce..b109e5395b6c 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_main.c +++ b/components/bt/host/bluedroid/stack/btm/btm_main.c @@ -136,6 +136,15 @@ uint8_t btm_ble_acl_active_count(void) for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) { p_acl_conn = list_node(p_node); if (p_acl_conn && p_acl_conn->in_use && p_acl_conn->transport == BT_TRANSPORT_LE) { + BTM_TRACE_DEBUG("%s LE ACL active #%d: remote_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + count, + p_acl_conn->remote_addr[0], + p_acl_conn->remote_addr[1], + p_acl_conn->remote_addr[2], + p_acl_conn->remote_addr[3], + p_acl_conn->remote_addr[4], + p_acl_conn->remote_addr[5]); count++; } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_pm.c b/components/bt/host/bluedroid/stack/btm/btm_pm.c index 1c46a7446fac..de48a2dad604 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_pm.c +++ b/components/bt/host/bluedroid/stack/btm/btm_pm.c @@ -866,9 +866,7 @@ void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len) /* notify registered parties */ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) { if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_NOTIF) { - if ( p_acl) { - (*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status); - } + (*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status); } } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index ab66eb421405..35337e40a376 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -2753,11 +2753,16 @@ static void btm_sec_bond_cancel_complete (void) ** Returns void ** *******************************************************************************/ -void btm_create_conn_cancel_complete (UINT8 *p) +void btm_create_conn_cancel_complete (UINT8 *p, UINT16 evt_len) { UINT8 status; - STREAM_TO_UINT8 (status, p); + if (evt_len >= 1) { + STREAM_TO_UINT8 (status, p); + } else { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + status = BTM_ERR_PROCESSING; + } //BTM_TRACE_EVENT ("btm_create_conn_cancel_complete(): in State: %s status:%d\n", // btm_pair_state_descr(btm_cb.pairing_state), status); @@ -3792,13 +3797,27 @@ void btm_rem_oob_req (UINT8 *p) ** Returns void ** *******************************************************************************/ -void btm_read_local_oob_complete (UINT8 *p) +void btm_read_local_oob_complete (UINT8 *p, UINT16 evt_len) { tBTM_SP_LOC_OOB evt_data; - UINT8 status = *p++; + UINT8 status; + + if (evt_len < 1) { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + evt_data.status = BTM_ERR_PROCESSING; + goto err_out; + } + + STREAM_TO_UINT8(status, p); BTM_TRACE_EVENT ("btm_read_local_oob_complete:%d\n", status); if (status == HCI_SUCCESS) { + if (evt_len < 1 + 32) { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + evt_data.status = BTM_ERR_PROCESSING; + goto err_out; + } + evt_data.status = BTM_SUCCESS; STREAM_TO_ARRAY16(evt_data.c, p); STREAM_TO_ARRAY16(evt_data.r, p); @@ -3806,6 +3825,7 @@ void btm_read_local_oob_complete (UINT8 *p) evt_data.status = BTM_ERR_PROCESSING; } +err_out: if (btm_cb.api.p_sp_callback) { (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data); } @@ -4278,7 +4298,6 @@ static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle) #if (SMP_INCLUDED == TRUE) void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); UINT8 res; UINT8 sec_dev_rec_status; BOOLEAN is_pairing_device = FALSE; @@ -4287,6 +4306,8 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) btm_acl_resubmit_page(); + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + /* Commenting out trace due to obf/compilation problems. */ #if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE) @@ -4609,7 +4630,6 @@ tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason) *******************************************************************************/ BOOLEAN btm_sec_disconnected (UINT16 handle, UINT8 reason) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); UINT8 old_pairing_flags = btm_cb.pairing_flags; int result = HCI_ERR_AUTH_FAILURE; tBTM_SEC_CALLBACK *p_callback = NULL; @@ -4622,6 +4642,8 @@ BOOLEAN btm_sec_disconnected (UINT16 handle, UINT8 reason) btm_acl_resubmit_page(); #endif + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + if (!p_dev_rec) { return FALSE; } @@ -5044,6 +5066,12 @@ void btm_sec_pin_code_request (UINT8 *p_bda) btm_pair_state_descr(btm_cb.pairing_state), (p_bda[0] << 8) + p_bda[1], (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5] ); #endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE + const bt_bdaddr_t *local_bd_addr = controller_get_interface()->get_address(); + if (!memcmp(p_bda, local_bd_addr, BD_ADDR_LEN)) { + BTM_TRACE_WARNING("btm_sec_pin_code_request() rejected device with same address\n"); + btsnd_hcic_pin_code_neg_reply(p_bda); + return; + } if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) { if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) && (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) ) { diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index d5b69c6818e9..e1036b917443 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1071,9 +1071,9 @@ void btm_cont_rswitch (tACL_CONN *p, tACL_CONN *btm_handle_to_acl (UINT16 hci_handle); void btm_read_link_policy_complete (UINT8 *p); -void btm_read_rssi_complete (UINT8 *p); +void btm_read_rssi_complete (UINT8 *p, UINT16 evt_len); void btm_read_channel_map_complete (UINT8 *p); -void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble); +void btm_read_tx_power_complete (UINT8 *p, UINT16 evt_len, BOOLEAN is_ble); void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types); void btm_read_link_quality_complete (UINT8 *p); tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types); @@ -1178,7 +1178,7 @@ void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len, tBTM_CMPL_CB *p_vsc_cplt_cback); void btm_inq_db_reset (void); void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len); -void btm_delete_stored_link_key_complete (UINT8 *p); +void btm_delete_stored_link_key_complete (UINT8 *p, UINT16 evt_len); void btm_report_device_status (tBTM_DEV_STATUS status); void btm_set_afh_channels_complete (UINT8 *p); void btm_ble_set_channels_complete (UINT8 *p); @@ -1215,7 +1215,7 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_ UINT32 mx_proto_id, UINT32 mx_chan_id, tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); void btm_sec_conn_req (UINT8 *bda, UINT8 *dc); -void btm_create_conn_cancel_complete (UINT8 *p); +void btm_create_conn_cancel_complete (UINT8 *p, UINT16 evt_len); void btm_read_linq_tx_power_complete (UINT8 *p); void btm_sec_init (UINT8 sec_mode); @@ -1259,10 +1259,10 @@ tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda); #if BTM_OOB_INCLUDED == TRUE void btm_rem_oob_req (UINT8 *p); -void btm_read_local_oob_complete (UINT8 *p); +void btm_read_local_oob_complete (UINT8 *p, UINT16 evt_len); #else #define btm_rem_oob_req(p) -#define btm_read_local_oob_complete(p) +#define btm_read_local_oob_complete(p, evt_len) #endif void btm_acl_resubmit_page (void); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index eb2995b958d1..2ff53852e0f3 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1128,7 +1128,9 @@ static void btu_hcif_esco_connection_chg_evt (UINT8 *p) static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_len, void *p_cplt_cback) { +#if (BLE_INCLUDED == TRUE) uint8_t status; +#endif // (BLE_INCLUDED == TRUE) switch (opcode) { #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_INQUIRY_CANCEL: @@ -1140,7 +1142,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; case HCI_DELETE_STORED_LINK_KEY: - btm_delete_stored_link_key_complete (p); + btm_delete_stored_link_key_complete (p, evt_len); break; case HCI_GET_LINK_QUALITY: @@ -1151,24 +1153,24 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l btm_read_local_name_complete (p, evt_len); break; case HCI_READ_RSSI: - btm_read_rssi_complete (p); + btm_read_rssi_complete (p, evt_len); break; case HCI_BLE_READ_CHNL_MAP: btm_read_channel_map_complete (p); break; case HCI_READ_TRANSMIT_POWER_LEVEL: #if (BLE_HOST_READ_TX_POWER_EN == TRUE) - btm_read_tx_power_complete(p, FALSE); + btm_read_tx_power_complete(p, evt_len, FALSE); #endif // #if (BLE_HOST_READ_TX_POWER_EN == TRUE) break; #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_CREATE_CONNECTION_CANCEL: - btm_create_conn_cancel_complete(p); + btm_create_conn_cancel_complete(p, evt_len); break; #endif // #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_READ_LOCAL_OOB_DATA: #if BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE - btm_read_local_oob_complete(p); + btm_read_local_oob_complete(p, evt_len); #endif break; @@ -1240,7 +1242,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l case HCI_BLE_READ_ADV_CHNL_TX_POWER: #if (BLE_HOST_READ_TX_POWER_EN == TRUE) - btm_read_tx_power_complete(p, TRUE); + btm_read_tx_power_complete(p, evt_len, TRUE); #endif // #if (BLE_HOST_READ_TX_POWER_EN == TRUE) break; #if (BLE_42_ADV_EN == TRUE) @@ -1395,10 +1397,6 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) { btm_vsc_complete (p, opcode, evt_len, (tBTM_CMPL_CB *)p_cplt_cback); } - STREAM_TO_UINT8 (status, p); - if(status != HCI_SUCCESS) { - HCI_TRACE_ERROR("CC evt: op=0x%x, status=0x%x", opcode, status); - } break; } } @@ -1421,6 +1419,10 @@ static void btu_hcif_command_complete_evt_on_task(BT_HDR *event) uint8_t *stream = hack->response->data + hack->response->offset + 3; // 2 to skip the event headers, 1 to skip the command credits STREAM_TO_UINT16(opcode, stream); + if (*stream != HCI_SUCCESS) { + HCI_TRACE_WARNING("opcode=0x%04x, status= %02x: %s", opcode, *stream, hci_status_code_to_string(*stream)); + } + btu_hcif_hdl_command_complete( opcode, stream, @@ -1506,7 +1508,7 @@ static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_c void *p_vsc_status_cback) { if (status != HCI_SUCCESS){ - HCI_TRACE_WARNING("%s,opcode:0x%04x,status:0x%02x", __func__, opcode,status); + HCI_TRACE_WARNING("opcode=0x%04x, status= %02x: %s", opcode, status, hci_status_code_to_string(status)); } BD_ADDR bd_addr; UINT16 handle; diff --git a/components/bt/host/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c index 9b3a2507a3f8..ea7776e4c7e4 100644 --- a/components/bt/host/bluedroid/stack/gatt/att_protocol.c +++ b/components/bt/host/bluedroid/stack/gatt/att_protocol.c @@ -200,7 +200,8 @@ BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_ BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) { BT_HDR *p_buf = NULL; - UINT8 *p, i = 0; + UINT8 *p; + UINT16 i = 0; if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) { p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c index 9abe72e2853d..6236f12a9460 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c @@ -695,7 +695,7 @@ static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data) l2cu_process_peer_cfg_rsp (p_ccb, p_cfg); if (p_cfg->result != L2CAP_CFG_PENDING) { - /* TBD: When config options grow beyong minimum MTU (48 bytes) + /* TBD: When config options grow beyond minimum MTU (48 bytes) * logic needs to be added to handle responses with * continuation bit set in flags field. * 1. Send additional config request out until C-bit is cleared in response @@ -885,7 +885,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) tL2CAP_CFG_INFO *p_cfg; tL2C_CHNL_STATE tempstate; UINT8 tempcfgdone; - UINT8 cfg_result; + UINT8 cfg_result = L2CAP_PEER_CFG_DISCONNECT; #if (BT_TRACE_VERBOSE == TRUE) L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", @@ -916,7 +916,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */ /* Tell upper layer. If service guaranteed, then clear the channel */ - if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) { + if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) { (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr); } break; @@ -931,7 +931,11 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); - if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) { + if (p_cfg) { + cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg); + } + + if (cfg_result == L2CAP_PEER_CFG_OK) { (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg); } @@ -968,7 +972,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) { + if (p_data && (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) { (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data); } break; @@ -988,16 +992,20 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ - l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); - l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + if (p_data) { + l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } break; case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */ - p_ccb->chnl_state = CST_CONFIG; - p_ccb->config_done &= ~CFG_DONE_MASK; - l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); - l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); - btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + if (p_data) { + p_ccb->chnl_state = CST_CONFIG; + p_ccb->config_done &= ~CFG_DONE_MASK; + l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + } break; case L2CEVT_TIMEOUT: diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index a48eb0d1506f..97cae231f780 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -345,6 +345,15 @@ uint8_t l2cu_ble_plcb_active_count(void) for (p_node = list_begin(l2cb.p_lcb_pool); p_node; p_node = list_next(p_node)) { p_lcb = list_node(p_node); if (p_lcb && p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) { + L2CAP_TRACE_DEBUG("%s LE PLCB active #%d: remote_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + active_count, + p_lcb->remote_bd_addr[0], + p_lcb->remote_bd_addr[1], + p_lcb->remote_bd_addr[2], + p_lcb->remote_bd_addr[3], + p_lcb->remote_bd_addr[4], + p_lcb->remote_bd_addr[5]); active_count ++; } } diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_api.c b/components/bt/host/bluedroid/stack/rfcomm/port_api.c index 1aa38ff77cab..a6b5920cdbc3 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_api.c @@ -181,7 +181,7 @@ int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server, /* If the MTU is not specified (0), keep MTU decision until the * PN frame has to be send * at that time connection should be established and we - * will know for sure our prefered MTU + * will know for sure our preferred MTU */ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD; @@ -298,12 +298,12 @@ int RFCOMM_RemoveServer (UINT16 handle) ** ** Description This function is called to provide an address of the ** function which will be called when one of the events -** specified in the mask occures. +** specified in the mask occurs. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_callback - address of the callback function which should ** be called from the RFCOMM when an event -** specified in the mask occures. +** specified in the mask occurs. ** ** *******************************************************************************/ @@ -537,8 +537,7 @@ BOOLEAN PORT_IsOpening (BD_ADDR bd_addr) } } - if ((!found_port) || - (found_port && (p_port->rfc.state < RFC_STATE_OPENED))) { + if ((!found_port) || (p_port->rfc.state < RFC_STATE_OPENED)) { /* Port is not established yet. */ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN); return TRUE; @@ -641,7 +640,7 @@ int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count) ** Function PORT_GetState ** ** Description This function is called to fill tPORT_STATE structure -** with the curremt control settings for the port +** with the current control settings for the port ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_settings - Pointer to a tPORT_STATE structure in which @@ -1009,15 +1008,15 @@ int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal) ** ** Function PORT_ClearError ** -** Description This function retreives information about a communications +** Description This function retrieves information about a communications ** error and reports current status of a connection. The -** function should be called when an error occures to clear +** function should be called when an error occurs to clear ** the connection error flag and to enable additional read ** and write operations. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_errors - pointer of the variable to receive error codes -** p_status - pointer to the tPORT_STATUS structur to receive +** p_status - pointer to the tPORT_STATUS structure to receive ** connection status ** *******************************************************************************/ @@ -1090,7 +1089,7 @@ int PORT_SendError (UINT16 handle, UINT8 errors) ** Description This function reports current status of a connection. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection -** p_status - pointer to the tPORT_STATUS structur to receive +** p_status - pointer to the tPORT_STATUS structure to receive ** connection status ** *******************************************************************************/ @@ -1700,7 +1699,7 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) rc = port_write (p_port, p_buf); - /* If queue went below the threashold need to send flow control */ + /* If queue went below the threshold need to send flow control */ event |= port_flow_control_user (p_port); if (rc == PORT_SUCCESS) { diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_db.c b/components/bt/host/bluedroid/stack/sdp/sdp_db.c index f9f2f738c6ad..06f934d4a3ad 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_db.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_db.c @@ -415,6 +415,10 @@ BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type, tSDP_RECORD *p_rec = NULL; list_node_t *p_node= NULL; + if (!p_val) { + return FALSE; + } + #if (BT_TRACE_VERBOSE == TRUE) if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) { if ((attr_type == UINT_DESC_TYPE) || @@ -448,6 +452,12 @@ BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type, if (p_rec->record_handle == handle) { tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0]; + // error out early, no need to look up + if (p_rec->free_pad_ptr >= SDP_MAX_PAD_LEN) { + SDP_TRACE_ERROR("the free pad for SDP record with handle %d is full, skip adding the attribute", handle); + return (FALSE); + } + /* Found the record. Now, see if the attribute already exists */ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) { /* The attribute exists. replace it */ diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c index e1ffdf726121..82ef1548da3e 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c @@ -45,9 +45,9 @@ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /********************************************************************************/ #if SDP_CLIENT_ENABLED == TRUE -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); -static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); -static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end); static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda); static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec, @@ -189,7 +189,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) if (p_ccb->is_attr_search) { p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR; - process_service_search_attr_rsp (p_ccb, NULL); + process_service_search_attr_rsp (p_ccb, NULL, NULL); } else { /* First step is to get a list of the handles from the server. */ /* We are not searching for a specific attribute, so we will */ @@ -213,7 +213,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) *******************************************************************************/ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) { - UINT8 *p, rsp_pdu; + UINT8 *p, *p_end, rsp_pdu; BOOLEAN invalid_pdu = TRUE; #if (SDP_DEBUG_RAW == TRUE) @@ -225,7 +225,12 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) /* Got a reply!! Check what we got back */ p = (UINT8 *)(p_msg + 1) + p_msg->offset; + p_end = p + p_msg->len; + if (p_msg->len < 1) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } BE_STREAM_TO_UINT8 (rsp_pdu, p); p_msg->len--; @@ -233,21 +238,21 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) switch (rsp_pdu) { case SDP_PDU_SERVICE_SEARCH_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) { - process_service_search_rsp (p_ccb, p); + process_service_search_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) { - process_service_attr_rsp (p_ccb, p); + process_service_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_SEARCH_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) { - process_service_search_attr_rsp (p_ccb, p); + process_service_search_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; @@ -269,12 +274,17 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) ** Returns void ** *******************************************************************************/ -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT16 xx; UINT16 total, cur_handles, orig; UINT8 cont_len; + if (p_reply + 8 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_GENERIC_ERROR); + return; + } + /* Skip transaction, and param len */ p_reply += 4; BE_STREAM_TO_UINT16 (total, p_reply); @@ -282,7 +292,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) orig = p_ccb->num_handles; p_ccb->num_handles += cur_handles; - if (p_ccb->num_handles == 0) { + if ((p_ccb->num_handles == 0) || (p_ccb->num_handles < orig)) { SDP_TRACE_WARNING ("SDP - Rcvd ServiceSearchRsp, no matches\n"); sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH); return; @@ -296,6 +306,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->num_handles = sdp_cb.max_recs_per_search; } + if (p_reply + ((p_ccb->num_handles - orig) * 4) + 1 > p_reply_end) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } + for (xx = orig; xx < p_ccb->num_handles; xx++) { BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply); } @@ -306,6 +321,10 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); return; } + if (p_reply + cont_len > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); + return; + } /* stay in the same state */ sdp_snd_service_search_req(p_ccb, cont_len, p_reply); } else { @@ -313,7 +332,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->disc_state = SDP_DISC_WAIT_ATTR; /* Kick off the first attribute request */ - process_service_attr_rsp (p_ccb, NULL); + process_service_attr_rsp (p_ccb, NULL, NULL); } } @@ -392,7 +411,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset) ** Returns void ** *******************************************************************************/ -static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p_start, *p_param_len; UINT16 param_len, list_byte_count; @@ -411,6 +430,11 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (list_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("list_byte_count:%d\n", list_byte_count); @@ -426,6 +450,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, list_byte_count); #endif + + if (p_reply + list_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -502,8 +532,10 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Was this a continuation request ? */ if (cont_request_needed) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); } @@ -537,7 +569,7 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) ** Returns void ** *******************************************************************************/ -static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p, *p_start, *p_end, *p_param_len; UINT8 type; @@ -557,6 +589,11 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (lists_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("lists_byte_count:%d\n", lists_byte_count); @@ -572,6 +609,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, lists_byte_count); #endif + + if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -643,8 +686,10 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* No continuation for first request */ if (p_reply) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); } diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c index d6f98197d0e4..43e3664baf81 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_server.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_server.c @@ -179,7 +179,6 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, tSDP_RECORD *p_rec = NULL; BT_HDR *p_buf; BOOLEAN is_cont = FALSE; - UNUSED(p_req_end); p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); @@ -214,6 +213,10 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, } /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, @@ -351,6 +354,10 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { /* Free and reallocate buffer */ if (p_ccb->rsp_list) { @@ -565,7 +572,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, /* Extract the UUID sequence to search for */ p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); - if ((!p_req) || (!uid_seq.num_uids)) { + if ((!p_req) || (!uid_seq.num_uids) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST); return; } @@ -586,7 +593,16 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ; + if (max_list_len < 4) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL); + return; + } + /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { /* Free and reallocate buffer */ if (p_ccb->rsp_list) { @@ -600,7 +616,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) { + if ((*p_req++ != SDP_CONTINUATION_LEN) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; } diff --git a/components/bt/host/bluedroid/stack/smp/smp_act.c b/components/bt/host/bluedroid/stack/smp/smp_act.c index a41fbdd1b17b..b467a1c13d64 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_act.c +++ b/components/bt/host/bluedroid/stack/smp/smp_act.c @@ -869,7 +869,7 @@ void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG("%s", __func__); /* rejecting BR pairing request over non-SC BR link */ - if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { + if (p_dev_rec && !p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { reason = SMP_XTRANS_DERIVE_NOT_ALLOW; smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); return; @@ -1345,7 +1345,14 @@ void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) /* state check to prevent re-entrant */ if (smp_get_state() == SMP_STATE_BOND_PENDING) { if (p_cb->derive_lk) { - smp_derive_link_key_from_long_term_key(p_cb, NULL); + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); + if (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && + (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) { + SMP_TRACE_DEBUG("%s BREDR key is higher security than existing LE keys, " + "don't derive LK from LTK", __func__); + } else { + smp_derive_link_key_from_long_term_key(p_cb, NULL); + } p_cb->derive_lk = FALSE; } diff --git a/components/bt/host/bluedroid/stack/smp/smp_keys.c b/components/bt/host/bluedroid/stack/smp/smp_keys.c index aec6f709c560..24ef81427913 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/host/bluedroid/stack/smp/smp_keys.c @@ -549,7 +549,7 @@ void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) ** Function smp_gen_p1_4_confirm ** ** Description Generate Confirm/Compare Step1: -** p1 = pres || preq || rat' || iat' +** p1 = press || preq || rat' || iat' ** ** Returns void ** @@ -574,22 +574,22 @@ void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) UINT8_TO_STREAM(p, p_cb->addr_type); /* LSB : iat': responder's address type */ UINT8_TO_STREAM(p, addr_type); - /* concatinate preq */ + /* concatenate preq */ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ); - /* concatinate pres */ + /* concatenate press */ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP); } else { /* LSB : iat': initiator's address type */ UINT8_TO_STREAM(p, addr_type); /* LSB : rat': responder's(local) address type */ UINT8_TO_STREAM(p, p_cb->addr_type); - /* concatinate preq */ + /* concatenate preq */ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ); - /* concatinate pres */ + /* concatenate press */ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP); } #if SMP_DEBUG == TRUE - SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'\n"); + SMP_TRACE_DEBUG("p1 = press || preq || rat' || iat'\n"); smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16); #endif } @@ -654,7 +654,7 @@ void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda) tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; SMP_TRACE_DEBUG ("smp_calculate_comfirm \n"); - /* generate p1 = pres || preq || rat' || iat' */ + /* generate p1 = press || preq || rat' || iat' */ smp_gen_p1_4_confirm(p_cb, p1); /* p1 = rand XOR p1 */ @@ -2229,7 +2229,7 @@ void smp_process_new_nonce(tSMP_CB *p_cb) static void smp_rand_back(tBTM_RAND_ENC *p) { tSMP_CB *p_cb = &smp_cb; - UINT8 *pp = p->param_buf; + UINT8 *pp = NULL; UINT8 failure = SMP_PAIR_FAIL_UNKNOWN; UINT8 state = p_cb->rand_enc_proc_state & ~0x80; @@ -2247,11 +2247,13 @@ static void smp_rand_back(tBTM_RAND_ENC *p) break; case SMP_GEN_DIV_LTK: + pp = p->param_buf; STREAM_TO_UINT16(p_cb->div, pp); smp_generate_ltk_cont(p_cb, NULL); break; case SMP_GEN_DIV_CSRK: + pp = p->param_buf; STREAM_TO_UINT16(p_cb->div, pp); smp_compute_csrk(p_cb, NULL); break; diff --git a/components/bt/host/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c index 1f3db502e23e..c109b9d002c9 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -320,6 +320,12 @@ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s\n", __func__); + if (p_buf->len < 1) { + SMP_TRACE_WARNING( "Bogus l2cap packet, too short"); + osi_free(p_buf); + return; + } + STREAM_TO_UINT8(cmd, p); /* sanity check */ @@ -331,6 +337,11 @@ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd) { + if (p_buf->len != smp_cmd_size_per_spec[cmd]) { + SMP_TRACE_WARNING( "Ignore received command 0x%02x with invalid length %d", cmd, p_buf->len); + osi_free(p_buf); + return; + } if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { p_cb->role = HCI_ROLE_SLAVE; p_cb->smp_over_br = TRUE; diff --git a/components/bt/host/bluedroid/stack/smp/smp_main.c b/components/bt/host/bluedroid/stack/smp/smp_main.c index 512aca0a8c5c..fa4d5ffbe323 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_main.c +++ b/components/bt/host/bluedroid/stack/smp/smp_main.c @@ -388,7 +388,7 @@ static const UINT8 smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { static const UINT8 smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ - /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */ + /* locally calculated peer dhkey check is ready -> compare it with DHKey Check actually received from peer */ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, /* locally calculated peer dhkey check is ready -> calculate STK, go to sending */ /* HCI LE Start Encryption command */ @@ -580,7 +580,7 @@ static const UINT8 smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { static const UINT8 smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ - /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */ + /* locally calculated peer dhkey check is ready -> compare it with DHKey Check */ /* actually received from peer */ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, @@ -771,6 +771,8 @@ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) /* execute action functions */ for (i = 0; i < SMP_NUM_ACTIONS; i++) { if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION && smp_sm_action[action] != NULL) { + SMP_TRACE_DEBUG("smp action %d for state %s, event %s", + action, smp_get_state_name(curr_state), smp_get_event_name(event)); (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); } else { break; diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index eaa112fce02f..cc3b71a8f8e4 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -247,8 +247,7 @@ menu "GAP / GATT / Device Settings" config BT_NIMBLE_MAX_CONNECTIONS int "Maximum number of concurrent connections" range 1 2 if IDF_TARGET_ESP32C2 - range 1 70 if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61 - range 1 35 if IDF_TARGET_ESP32H2 + range 1 70 if SOC_ESP_NIMBLE_CONTROLLER range 1 9 default 2 if IDF_TARGET_ESP32C2 default 3 diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 1937ecbee956..c05ca87decd1 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -352,6 +352,10 @@ IRAM_ATTR static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, } } + esp_err_t ret = esp_cache_msync((void *)(new_trans.buffer), new_trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + (void)ret; + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); dw_gdma_channel_config_transfer(chan, &csi_dma_transfer_config); dw_gdma_channel_enable_ctrl(chan, true); @@ -448,6 +452,9 @@ esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle) } } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); ctlr->trans = trans; diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index 8a9df05c5615..b92404fae60c 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -177,6 +177,9 @@ static IRAM_ATTR esp_err_t esp_cam_ctlr_dvp_start_trans(esp_cam_ctlr_dvp_cam_t * assert(false && "no new buffer, and no driver internal buffer"); } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_reset(&ctlr->dma), TAG, "failed to reset DMA"); ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_start(&ctlr->dma, trans.buffer, ctlr->fb_size_in_bytes), TAG, "failed to start DMA"); diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c index ef607849d393..085a56957778 100644 --- a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -346,6 +346,9 @@ static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle) } } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); dvp_ctlr->trans = trans; @@ -469,6 +472,10 @@ IRAM_ATTR static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t cha } } + esp_err_t ret = esp_cache_msync((void *)(new_trans.buffer), new_trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + (void)ret; + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); dw_gdma_channel_config_transfer(chan, &dvp_dma_transfer_config); dw_gdma_channel_enable_ctrl(chan, true); diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index c33479cb1ccb..4a84723e2129 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -929,7 +929,9 @@ esp_err_t sdmmc_host_deinit(void) return ESP_ERR_INVALID_STATE; } for (int slot = 0; slot < SOC_SDMMC_NUM_SLOTS; slot++) { - sdmmc_host_deinit_slot_internal(slot); + if (sdmmc_host_slot_initialized(slot)) { + sdmmc_host_deinit_slot_internal(slot); + } } sdmmc_host_deinit_internal(); diff --git a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py index 987e0db89ff5..236a1076ca78 100644 --- a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py +++ b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py @@ -49,10 +49,10 @@ def test_temperature_sensor_cbs_esp32c5(dut: Dut) -> None: dut.run_all_single_board_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize('target', ['esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32c61'], indirect=['target']) def test_temperature_phy_cases(case_tester: CaseTester) -> None: # type: ignore for case in case_tester.test_menu: - if case.attributes.get('test_env', 'wifi_two_dut') == 'wifi_two_dut': + if case.attributes.get('test_env', 'two_duts') == 'two_duts': case_tester.run_all_multi_dev_cases(case=case, reset=True) diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c index 631829de9e1d..e6abe60e8bb0 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c @@ -183,7 +183,7 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se } p_usb_serial_jtag_obj->tx_ring_buf = xRingbufferCreate(usb_serial_jtag_config->tx_buffer_size, RINGBUF_TYPE_BYTEBUF); - if (p_usb_serial_jtag_obj->rx_ring_buf == NULL) { + if (p_usb_serial_jtag_obj->tx_ring_buf == NULL) { ESP_LOGE(USB_SERIAL_JTAG_TAG, "ringbuffer create error"); err = ESP_ERR_NO_MEM; goto _exit; diff --git a/components/esp_eth/test_apps/main/esp_eth_test_l2.c b/components/esp_eth/test_apps/main/esp_eth_test_l2.c index 4f88c318ba9c..6af0f19229b2 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_l2.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_l2.c @@ -220,6 +220,15 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") TEST_ESP_OK(esp_eth_update_input_path(eth_handle, l2_packet_txrx_test_cb, &s_recv_info)); + TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine + + EventBits_t bits = 0; + bits = xEventGroupWaitBits(eth_event_state_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(WAIT_FOR_CONN_TMO_MS)); + TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); + // if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch + // starts switching the associated port (e.g. it runs RSTP at first) + poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); + // --------------------------------------- printf("Enable receive all multicast\n"); // --------------------------------------- @@ -231,18 +240,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.brdcast_rx_cnt = 0; bool all_multicast = true; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_ALL_MULTICAST, &all_multicast)); - - TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine - - EventBits_t bits = 0; - bits = xEventGroupWaitBits(eth_event_state_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(WAIT_FOR_CONN_TMO_MS)); - TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); - // if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch - // starts switching the associated port (e.g. it runs RSTP at first) - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); - bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -270,11 +270,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.brdcast_rx_cnt = 0; all_multicast = false; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_ALL_MULTICAST, &all_multicast)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); - bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -297,10 +295,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_ADD_MAC_FILTER, multicast_addr_ip4)); uint8_t multicast_addr_ip6[ETH_ADDR_LEN] = {0x33, 0x33, 0x00, 0x00, 0x00, 0x00}; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_ADD_MAC_FILTER, multicast_addr_ip6)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -319,10 +316,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.multicast_rx_cnt = 0; s_recv_info.brdcast_rx_cnt = 0; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_DEL_MAC_FILTER, multicast_addr_ip4)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -355,10 +351,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") #else TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_DEL_MAC_FILTER, multicast_addr_ip6)); #endif - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -642,7 +637,7 @@ TEST_CASE("heap utilization", "[ethernet_l2]") } #define FORMAT_MAC(mac_addr, a, b, c, d, e, f) do { mac_addr[0] = a; mac_addr[1] = b; mac_addr[2] = c; mac_addr[3] = d; mac_addr[4] = e; mac_addr[5] = f; } while(0) -TEST_CASE("w5500_multicast_filter", "[ethernet_l2]") +TEST_CASE("multicast_filter", "[ethernet_l2]") { esp_eth_mac_t *mac = mac_init(NULL, NULL); TEST_ASSERT_NOT_NULL(mac); diff --git a/components/esp_eth/test_apps/pytest_esp_eth.py b/components/esp_eth/test_apps/pytest_esp_eth.py index 4a2b4003cc6c..f32e5cf7ae18 100644 --- a/components/esp_eth/test_apps/pytest_esp_eth.py +++ b/components/esp_eth/test_apps/pytest_esp_eth.py @@ -31,16 +31,18 @@ def find_target_if(self, my_if: str = '') -> None: netifs.sort(reverse=True) logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - # if no interface defined, try to find it automatically - if my_if == '': - if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - self.target_if = netif - break + if my_if == '': + if 'dut_p1' in netifs: + self.target_if = 'dut_p1' else: - if netif.find(my_if) == 0: - self.target_if = my_if - break + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + self.target_if = netif + break + elif my_if in netifs: + self.target_if = my_if + if self.target_if == '': raise RuntimeError('network interface not found') logging.info('Use %s for testing', self.target_if) @@ -132,8 +134,8 @@ def ethernet_int_emac_test(dut: IdfDut) -> None: dut.run_all_single_board_cases(group='esp_emac', timeout=240) -def ethernet_l2_test(dut: IdfDut) -> None: - target_if = EthTestIntf(ETH_TYPE) +def ethernet_l2_test(dut: IdfDut, test_if: str = '') -> None: + target_if = EthTestIntf(ETH_TYPE, test_if) dut.expect_exact('Press ENTER to see the list of tests') dut.write('\n') @@ -169,11 +171,10 @@ def ethernet_l2_test(dut: IdfDut) -> None: r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})' ) dut_mac = res.group(1).decode('utf-8') + target_if.recv_resp_poke(mac=dut_mac) for _ in range(5): - # wait for POKE msg to be sure the switch already started forwarding the port's traffic - # (there might be slight delay due to the RSTP execution) - # or wait for next POKE msg to be sure the DUT reconfigured the filter - target_if.recv_resp_poke(mac=dut_mac) + # wait to be sure the DUT reconfigured the filter + dut.expect_exact('Filter configured') target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame target_if.send_eth_packet('01:00:5e:00:00:00') # IPv4 multicast frame target_if.send_eth_packet('33:33:00:00:00:00') # IPv6 multicast frame diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c index a8bc0d5b18e7..97f6eefb0b2c 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c @@ -19,11 +19,13 @@ #include "soc/lp_clkrst_reg.h" #include "soc/lp_system_reg.h" #include "soc/pmu_reg.h" +#include "soc/chip_revision.h" #include "esp_hw_log.h" #include "sdkconfig.h" #include "esp_rom_uart.h" #include "esp_private/esp_pmu.h" #include "hal/clk_tree_ll.h" +#include "hal/efuse_hal.h" static const char *TAG = "rtc_clk_init"; @@ -71,6 +73,10 @@ void rtc_clk_init(rtc_clk_config_t cfg) pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, hp_dcmvset); SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu esp_rom_delay_us(1000); + unsigned chip_version = efuse_hal_chip_revision(); + if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { + REG_SET_FIELD(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_LP_FIB_SEL, 0xEF);// lp_fib_sel bit4 set to 0: select dig_fib_reg instead of ana_fib_reg + } pmu_ll_hp_set_regulator_xpd(&PMU, PMU_MODE_HP_ACTIVE, false); soc_xtal_freq_t xtal_freq = cfg.xtal_freq; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index cdedc68a04d4..b7f54b6e1e02 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -904,10 +904,8 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) { #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0); #endif -#endif #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1); @@ -961,10 +959,8 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint /* Unhold the SPI CS pin */ if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) { #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0); #endif -#endif #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1); #endif diff --git a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c index 2979a1365a94..cc887628f2be 100644 --- a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c +++ b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include "esp_lcd_mipi_dsi.h" #include "esp_clk_tree.h" #include "mipi_dsi_priv.h" @@ -19,7 +20,7 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc ESP_ERR_INVALID_ARG, TAG, "invalid number of data lanes %d", bus_config->num_data_lanes); ESP_RETURN_ON_FALSE(bus_config->lane_bit_rate_mbps >= MIPI_DSI_LL_MIN_PHY_MBPS && bus_config->lane_bit_rate_mbps <= MIPI_DSI_LL_MAX_PHY_MBPS, ESP_ERR_INVALID_ARG, TAG, - "invalid lane bit rate %"PRIu32, bus_config->lane_bit_rate_mbps); + "invalid lane bit rate %.2f", bus_config->lane_bit_rate_mbps); // we don't use an bus allocator here, because different DSI bus uses different PHY. // And each PHY has its own associated PINs, which is not changeable. @@ -114,9 +115,9 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc mipi_dsi_host_ll_enable_tx_eotp(hal->host, true, false); // Set the divider to get the Time Out clock, clock source is the high-speed byte clock - mipi_dsi_host_ll_set_timeout_clock_division(hal->host, bus_config->lane_bit_rate_mbps / 8 / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ); + mipi_dsi_host_ll_set_timeout_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ)); // Set the divider to get the TX Escape clock, clock source is the high-speed byte clock - mipi_dsi_host_ll_set_escape_clock_division(hal->host, bus_config->lane_bit_rate_mbps / 8 / MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ); + mipi_dsi_host_ll_set_escape_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ)); // set the timeout intervals to zero, means to disable the timeout mechanism mipi_dsi_host_ll_set_timeout_count(hal->host, 0, 0, 0, 0, 0, 0, 0); // DSI host will wait indefinitely for a read response from the DSI device diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 7430d646b8d7..74c95b4a715c 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -169,7 +169,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ esp_async_fbcpy_handle_t fbcpy_ctx = NULL; ESP_RETURN_ON_FALSE(bus && panel_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(panel_config->virtual_channel < 4, ESP_ERR_INVALID_ARG, TAG, "invalid virtual channel %d", panel_config->virtual_channel); - ESP_RETURN_ON_FALSE(panel_config->dpi_clock_freq_mhz, ESP_ERR_INVALID_ARG, TAG, "invalid DPI clock frequency %"PRIu32, panel_config->dpi_clock_freq_mhz); + ESP_RETURN_ON_FALSE(panel_config->dpi_clock_freq_mhz > 0, ESP_ERR_INVALID_ARG, TAG, "invalid DPI clock frequency %.2f", panel_config->dpi_clock_freq_mhz); #if !SOC_DMA2D_SUPPORTED ESP_RETURN_ON_FALSE(!panel_config->flags.use_dma2d, ESP_ERR_NOT_SUPPORTED, TAG, "DMA2D is not supported"); #endif // !SOC_DMA2D_SUPPORTED @@ -265,7 +265,8 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(dpi_clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &dpi_clk_src_freq_hz), err, TAG, "get clock source frequency failed"); // divide the source clock to get the final DPI clock - uint32_t dpi_div = mipi_dsi_hal_host_dpi_calculate_divider(hal, dpi_clk_src_freq_hz / 1000 / 1000, panel_config->dpi_clock_freq_mhz); + float dpi_clk_src_freq_mhz = (float)dpi_clk_src_freq_hz / 1000.0f / 1000.0f; + uint32_t dpi_div = mipi_dsi_hal_host_dpi_calculate_divider(hal, dpi_clk_src_freq_mhz, panel_config->dpi_clock_freq_mhz); ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)dpi_clk_src, true), err, TAG, "clock source enable failed"); // set the clock source, set the divider, and enable the dpi clock PERIPH_RCC_ATOMIC() { diff --git a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h index 99917c7742b2..d0c1594f2009 100644 --- a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h +++ b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h @@ -23,7 +23,7 @@ typedef struct { int bus_id; /*!< Select which DSI controller, index from 0 */ uint8_t num_data_lanes; /*!< Number of data lanes, if set to 0, the driver will fallback to use maximum number of lanes */ mipi_dsi_phy_pllref_clock_source_t phy_clk_src; /*!< The clock source for the PHY PLL */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ } esp_lcd_dsi_bus_config_t; /** @@ -82,7 +82,7 @@ esp_err_t esp_lcd_new_panel_io_dbi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_d typedef struct { uint8_t virtual_channel; /*!< Virtual channel ID, index from 0 */ mipi_dsi_dpi_clock_source_t dpi_clk_src; /*!< MIPI DSI DPI clock source */ - uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */ + float dpi_clock_freq_mhz; /*!< Pixel clock frequency in MHz */ lcd_color_rgb_pixel_format_t pixel_format; /*!< Pixel format that used by the MIPI LCD device */ lcd_color_format_t in_color_format; /*!< Format of the input data (color space and pixel format), which is the format stored in the frame buffer */ diff --git a/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h b/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h index 3a700b4e29f6..7a2346be30a2 100644 --- a/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h +++ b/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,8 @@ extern "C" { #endif -#define ETS_DIGEST_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA256_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA384_LEN 48 /* SHA-384, bytes */ typedef enum { ECDSA_CURVE_P192 = 1, diff --git a/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h b/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h index 6b7313a00b7c..cc23b3188f00 100644 --- a/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h +++ b/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,11 +12,13 @@ extern "C" { #endif -#define ETS_DIGEST_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA256_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA384_LEN 48 /* SHA-384, bytes */ typedef enum { ECDSA_CURVE_P192 = 1, - ECDSA_CURVE_P256 = 2 + ECDSA_CURVE_P256 = 2, + ECDSA_CURVE_P384 = 3 } ECDSA_CURVE; int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig, ECDSA_CURVE curve_id, const uint8_t *digest, uint8_t *verified_digest); diff --git a/components/esp_system/ld/esp32/memory.ld.in b/components/esp_system/ld/esp32/memory.ld.in index e0b2517ff874..df13722b0ce8 100644 --- a/components/esp_system/ld/esp32/memory.ld.in +++ b/components/esp_system/ld/esp32/memory.ld.in @@ -122,7 +122,7 @@ MEMORY rtc_slow_reserved_seg(RW) : org = 0x50000000 + 0x2000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM /* external memory */ - extern_ram_seg(RWX) : org = 0x3F800000, + extern_ram_seg(RW) : org = 0x3F800000, len = 0x400000 } diff --git a/components/esp_system/port/soc/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c index 896dc34e3c70..0f7991676eca 100644 --- a/components/esp_system/port/soc/esp32c61/system_internal.c +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -62,8 +62,8 @@ void esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst - CLEAR_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); // Must release mspi core reset before mspi AXI. CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + CLEAR_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); // Must release mspi core reset before mspi AXI. CLEAR_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); CLEAR_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); CLEAR_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); diff --git a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py index a01451709102..fc4dbb75423e 100644 --- a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py +++ b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py @@ -41,7 +41,7 @@ def _get_diff_th( return diff_threshold.get(target) or diff_threshold['default'] -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, config, skip_autoflash', [ diff --git a/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py b/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py index e4b87e35d323..60d6d8c35812 100644 --- a/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py +++ b/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py @@ -5,7 +5,7 @@ from pytest_embedded_idf.utils import idf_parametrize -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32c61'], indirect=['target'] @@ -14,7 +14,7 @@ def test_wifi_connect_cases(case_tester: CaseTester) -> None: # type: ignore case_tester.run_all_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -29,7 +29,7 @@ def test_wifi_connect_cases_esp32c2_xtal26m(case_tester: CaseTester) -> None: @pytest.mark.esp32c2eco4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -43,7 +43,7 @@ def test_wifi_connect_cases_esp32c2eco4_xtal26m(case_tester: CaseTester) -> None case_tester.run_all_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index 7442d8568834..c49980b98bf8 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -26,12 +26,7 @@ const static char TAG[] __attribute__((unused)) = "esp_core_dump_common"; * @brief Memory regions to dump, defined at compile time. */ #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM -#if !CONFIG_IDF_TARGET_ESP32P4 -extern int _bss_start; -extern int _bss_end; -extern int _data_start; -extern int _data_end; -#else +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 extern int _bss_start_low; extern int _bss_end_low; extern int _data_start_low; @@ -40,6 +35,11 @@ extern int _bss_start_high; extern int _bss_end_high; extern int _data_start_high; extern int _data_end_high; +#else +extern int _bss_start; +extern int _bss_end; +extern int _data_start; +extern int _data_end; #endif #endif @@ -280,14 +280,14 @@ static const struct { } s_memory_sections[COREDUMP_MEMORY_MAX] = { [COREDUMP_MEMORY_IRAM] = { &_coredump_iram_start, &_coredump_iram_end }, #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM -#if !CONFIG_IDF_TARGET_ESP32P4 - [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end }, - [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end }, -#else +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start_low, &_bss_end_low }, [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start_low, &_data_end_low }, [COREDUMP_MEMORY_DRAM_BSS_HIGH] = { &_bss_start_high, &_bss_end_high }, [COREDUMP_MEMORY_DRAM_DATA_HIGH] = { &_data_start_high, &_data_end_high }, +#else + [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end }, + [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end }, #endif #else [COREDUMP_MEMORY_DRAM] = { &_coredump_dram_start, &_coredump_dram_end }, diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index 5ed38208ee2a..b59262f3afcc 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -1122,6 +1122,8 @@ void * pvTaskGetCurrentTCBForCore( BaseType_t xCoreID ) ESP_FREERTOS_DEBUG_LIST_END_PREV, ESP_FREERTOS_DEBUG_LIST_ITEM_PREV, ESP_FREERTOS_DEBUG_LIST_ITEM_OWNER, + ESP_FREERTOS_DEBUG_TASK_COUNT_WIDTH, + ESP_FREERTOS_DEBUG_PTR_WIDTH, /* New entries must be inserted here */ ESP_FREERTOS_DEBUG_TABLE_END, }; @@ -1141,7 +1143,9 @@ void * pvTaskGetCurrentTCBForCore( BaseType_t xCoreID ) offsetof( List_t, xListEnd ), /* list_end_offset */ offsetof( List_t, xListEnd.pxPrevious ), /* list_next_offset */ offsetof( ListItem_t, pxPrevious ), /* list_elem_next_offset */ - offsetof( ListItem_t, pvOwner ) /* list_elem_content_offset */ + offsetof( ListItem_t, pvOwner ), /* list_elem_content_offset */ + sizeof( UBaseType_t ), /* task_count_width */ + sizeof( void * ) /* ptr_width */ }; #endif /* CONFIG_FREERTOS_DEBUG_OCDAWARE */ diff --git a/components/hal/include/hal/mipi_dsi_hal.h b/components/hal/include/hal/mipi_dsi_hal.h index d7f3737f523c..3c1692383bea 100644 --- a/components/hal/include/hal/mipi_dsi_hal.h +++ b/components/hal/include/hal/mipi_dsi_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,8 +30,9 @@ typedef struct dsi_brg_dev_t *mipi_dsi_bridge_soc_handle_t; typedef struct { mipi_dsi_host_soc_handle_t host; /*!< Pointer to the host controller registers */ mipi_dsi_bridge_soc_handle_t bridge; /*!< Pointer to the bridge controller registers */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ - uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float expect_dpi_clock_freq_mhz; /*!< Expected DPI clock frequency in MHz */ + float real_dpi_clock_freq_mhz; /*!< Real DPI clock frequency in MHz */ } mipi_dsi_hal_context_t; /** @@ -39,7 +40,7 @@ typedef struct { */ typedef struct { int bus_id; /*!< MIPI DSI bus ID, index from 0 */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ uint8_t num_data_lanes; /*!< Number of data lanes */ } mipi_dsi_hal_config_t; @@ -67,7 +68,7 @@ void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal); * @param phy_clk_src_freq_hz PHY clock source frequency in Hz * @param lane_bit_rate_mbps Lane bit rate in Mbps */ -void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps); +void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, float lane_bit_rate_mbps); /** * @brief Write a value to a PHY register via internal bus (so-called test interface) @@ -175,7 +176,7 @@ void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint * @param expect_dpi_clk_mhz Expected DPI clock frequency in MHz * @return Divider value */ -uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz); +uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, float clk_src_mhz, float expect_dpi_clk_mhz); #ifdef __cplusplus diff --git a/components/hal/mipi_dsi_hal.c b/components/hal/mipi_dsi_hal.c index 8e57fab19100..5bd2f6964dfb 100644 --- a/components/hal/mipi_dsi_hal.c +++ b/components/hal/mipi_dsi_hal.c @@ -1,11 +1,13 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include +#include #include "hal/mipi_dsi_hal.h" #include "hal/mipi_dsi_ll.h" #include "hal/assert.h" @@ -38,28 +40,28 @@ void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal) hal->bridge = NULL; } -void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps) +void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, float lane_bit_rate_mbps) { // Formula: f_vco = M/N * f_ref // where the M is Feedback Multiplication Ratio, N is Input Frequency Division Ratio - uint32_t ref_freq_mhz = phy_clk_src_freq_hz / 1000 / 1000; - uint32_t vco_freq_mhz = lane_bit_rate_mbps; + float ref_freq_mhz = (float)phy_clk_src_freq_hz / 1000.0f / 1000.0f; + float vco_freq_mhz = lane_bit_rate_mbps; uint8_t pll_N = 1; uint16_t pll_M = 0; // 5MHz <= f_ref/N <= 40MHz - uint8_t min_N = MAX(1, ref_freq_mhz / 40); - uint8_t max_N = ref_freq_mhz / 5; - uint16_t min_delta = UINT16_MAX; + uint8_t min_N = MAX(1, (uint8_t)(ref_freq_mhz / 40.0f)); + uint8_t max_N = (uint8_t)(ref_freq_mhz / 5.0f); + float min_delta = INFINITY; for (uint8_t n = min_N; n <= max_N; n++) { - uint16_t m = vco_freq_mhz * n / ref_freq_mhz; + uint16_t m = (uint16_t)(vco_freq_mhz * n / ref_freq_mhz); // M must be even number if ((m & 0x01) == 0) { - uint16_t delta = vco_freq_mhz - ref_freq_mhz * m / n; + float delta = fabsf(vco_freq_mhz - ref_freq_mhz * m / n); if (delta < min_delta) { min_delta = delta; pll_M = m; pll_N = n; - if (min_delta == 0) { + if (min_delta < 0.01f) { break; } } @@ -84,8 +86,8 @@ void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_cl mipi_dsi_hal_phy_write_register(hal, 0x18, ((pll_M - 1) & 0x1F)); mipi_dsi_hal_phy_write_register(hal, 0x18, 0x80 | (((pll_M - 1) >> 5) & 0x0F)); // update the real lane bit rate - hal->lane_bit_rate_mbps = ref_freq_mhz * pll_M / pll_N; - HAL_LOGD("dsi_hal", "phy pll: ref=%" PRIu32 "Hz, lane_bit_rate=%" PRIu32 "Mbps, M=%" PRId16 ", N=%" PRId8 ", hsfreqrange=%" PRId8, + hal->lane_bit_rate_mbps = ref_freq_mhz * (float)pll_M / (float)pll_N; + HAL_LOGD("dsi_hal", "phy pll: ref=%" PRIu32 "Hz, lane_bit_rate=%.2f Mbps, M=%" PRId16 ", N=%" PRId8 ", hsfreqrange=%" PRId8, phy_clk_src_freq_hz, hal->lane_bit_rate_mbps, pll_M, pll_N, hs_freq_sel); } @@ -116,7 +118,7 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_ uint32_t payload_size = command_bytes + param_size; // merge the command and some bytes of parameters into one 32-bit word - uint32_t temp = command & ((1 << (8 * command_bytes)) - 1); + uint32_t temp = command & ((1U << (8 * command_bytes)) - 1); uint16_t merged_size = MIN(4 - command_bytes, param_size); for (int i = 0; i < merged_size; i++) { temp |= payload[i] << (8 * (i + command_bytes)); @@ -131,15 +133,17 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_ payload += merged_size; uint32_t remain_size = param_size - merged_size; while (remain_size >= 4) { - temp = *(uint32_t *)payload; + // use memcpy to avoid unaligned memory access + memcpy(&temp, payload, sizeof(uint32_t)); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); payload += 4; remain_size -= 4; } if (remain_size) { - temp = *(uint32_t *)payload; - temp &= (1 << (8 * remain_size)) - 1; + temp = 0; + // use memcpy to avoid unaligned memory access and buffer over-read + memcpy(&temp, payload, remain_size); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); } @@ -176,15 +180,17 @@ void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_ uint32_t remain_size = buffer_size; uint32_t temp = 0; while (remain_size >= 4) { - temp = *(uint32_t *)payload; + // use memcpy to avoid unaligned memory access + memcpy(&temp, payload, sizeof(uint32_t)); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); payload += 4; remain_size -= 4; } if (remain_size) { - temp = *(uint32_t *)payload; - temp &= (1 << (8 * remain_size)) - 1; + temp = 0; + // use memcpy to avoid unaligned memory access and buffer over-read + memcpy(&temp, payload, remain_size); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); } @@ -225,19 +231,30 @@ void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_ void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size) { - uint16_t header_data = command & ((1 << (8 * command_bytes)) - 1); + uint16_t header_data = command & ((1U << (8 * command_bytes)) - 1); mipi_dsi_hal_host_gen_read_short_packet(hal, vc, MIPI_DSI_DT_DCS_READ_0, header_data, ret_param, param_buf_size); } void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp) { - float dpi2lane_clk_ratio = (float)hal->lane_bit_rate_mbps / hal->dpi_clock_freq_mhz / 8; - mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, - hsw * dpi2lane_clk_ratio, - hbp * dpi2lane_clk_ratio, - active_width * dpi2lane_clk_ratio, - hfp * dpi2lane_clk_ratio); - mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp); + // set the horizontal timing based on user's expectation + uint32_t htotal = hsw + hbp + active_width + hfp; + float dpi2lane_clk_ratio = hal->lane_bit_rate_mbps / hal->expect_dpi_clock_freq_mhz / 8.0f; + uint32_t host_hsw = (uint32_t)roundf(hsw * dpi2lane_clk_ratio); + uint32_t host_hbp = (uint32_t)roundf(hbp * dpi2lane_clk_ratio); + uint32_t host_act = (uint32_t)roundf(active_width * dpi2lane_clk_ratio); + uint32_t host_hfp = (uint32_t)roundf(hfp * dpi2lane_clk_ratio); + uint32_t host_htotal = (uint32_t)roundf(htotal * dpi2lane_clk_ratio); + int compensation = (int)host_htotal - (int)(host_hsw + host_hbp + host_act + host_hfp); + mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, host_hsw, host_hbp, host_act + compensation, host_hfp); + HAL_LOGD("dsi_hal", "host video timing: hsw=%" PRIu32 ", hbp=%" PRIu32 ", act=%" PRIu32 ", hfp=%" PRIu32, + host_hsw, host_hbp, host_act + compensation, host_hfp); + + // compensate the video timing to achieve the same refresh rate as expected + compensation = (int)roundf(hal->real_dpi_clock_freq_mhz / hal->expect_dpi_clock_freq_mhz * htotal) - (int)htotal; + mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp + compensation); + HAL_LOGD("dsi_hal", "brg video timing: hsw=%" PRIu32 ", hbp=%" PRIu32 ", act=%" PRIu32 ", hfp=%" PRIu32, + hsw, hbp, active_width, hfp + compensation); } void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp) @@ -246,9 +263,12 @@ void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint mipi_dsi_brg_ll_set_vertical_timing(hal->bridge, vsw, vbp, active_height, vfp); } -uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz) +uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, float clk_src_mhz, float expect_dpi_clk_mhz) { - uint32_t div = clk_src_mhz / expect_dpi_clk_mhz; - hal->dpi_clock_freq_mhz = clk_src_mhz / div; + uint32_t div = (uint32_t)roundf(clk_src_mhz / expect_dpi_clk_mhz); + hal->expect_dpi_clock_freq_mhz = expect_dpi_clk_mhz; + hal->real_dpi_clock_freq_mhz = clk_src_mhz / (float)div; + HAL_LOGD("dsi_hal", "dpi clk: src=%.2f MHz, expect=%.2f MHz, div=%" PRIu32 ", real=%.2f MHz", + clk_src_mhz, expect_dpi_clk_mhz, div, hal->real_dpi_clock_freq_mhz); return div; } diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 0f167bdaca24..4664a3591a4a 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -78,14 +78,6 @@ static esp_err_t ieee802154_sleep_deinit(void); #define NEEDS_NEXT_OPT(a) do {s_needs_next_operation = a;} while(0) static esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca); -#if !CONFIG_IEEE802154_TEST -typedef struct { - const uint8_t *frame; - bool cca; -} pending_tx_t; -static pending_tx_t s_pending_tx = { 0 }; -#endif - static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) { // If the RX done packet is written in the stub buffer, drop it silently. @@ -383,26 +375,13 @@ static void enable_rx(void) static IRAM_ATTR void next_operation(void) { + if (ieee802154_pib_get_rx_when_idle()) { + enable_rx(); + } else { + ieee802154_set_state(IEEE802154_STATE_IDLE); #if !CONFIG_IEEE802154_TEST - if (s_pending_tx.frame) { - // Here the driver needs to recover the setting of rx aborts, see function `ieee802154_transmit`. - ieee802154_ll_disable_rx_abort_events(IEEE802154_RX_ABORT_ALL); - ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); - // Clear the RX abort event again for avoiding the risk if there are still some rx abort events created after last isr process. - ieee802154_ll_clear_events(IEEE802154_EVENT_RX_ABORT); - ieee802154_transmit_internal(s_pending_tx.frame, s_pending_tx.cca); - s_pending_tx.frame = NULL; - } else -#endif - { - if (ieee802154_pib_get_rx_when_idle()) { - enable_rx(); - } else { - ieee802154_set_state(IEEE802154_STATE_IDLE); -#if !CONFIG_IEEE802154_TEST - ieee802154_sleep(); + ieee802154_sleep(); #endif - } } } @@ -902,15 +881,12 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) ieee802154_enter_critical(); if ((s_ieee802154_state == IEEE802154_STATE_RX && ieee802154_ll_is_current_rx_frame()) || s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { - // If the current radio is processing an RX frame or sending an ACK, do not shut down the ongoing process. - // Instead, defer the transmission of the pending TX frame. - // Once the current process is completed, the pending transmit frame will be initiated. - s_pending_tx.frame = frame; - s_pending_tx.cca = cca; + if (cca) { + ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); + } else { + ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_ABORT); + } IEEE802154_TX_DEFERRED_NUMS_UPDATE(); - // Here we enable all rx interrupts due to the driver needs to know when the current RX has finished. - // Will recover the setting of rx abort in function `next_operation`. - ieee802154_ll_enable_rx_abort_events(IEEE802154_RX_ABORT_ALL); ieee802154_exit_critical(); return ESP_OK; } diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index 740775acec56..87ef813ae13a 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -71,6 +72,21 @@ typedef struct _protocomm_ble { static _protocomm_ble_internal_t *protoble_internal; +static bool protocomm_ble_transport_active(void) +{ + return (protoble_internal != NULL) && (protoble_internal->pc_ble != NULL); +} + +static void protocomm_ble_reset_prepare_write(void) +{ + if (prepare_write_env.prepare_buf) { + free(prepare_write_env.prepare_buf); + prepare_write_env.prepare_buf = NULL; + } + prepare_write_env.prepare_len = 0; + prepare_write_env.handle = 0; +} + // config adv data static esp_ble_adv_data_t adv_config = { .set_scan_rsp = false, @@ -121,6 +137,9 @@ static const uint16_t *uuid128_to_16(const uint8_t *uuid128) static const char *handle_to_handler(uint16_t handle) { + if (protoble_internal == NULL) { + return NULL; + } const uint8_t *uuid128 = simple_ble_get_uuid128(handle); if (!uuid128) { return NULL; @@ -140,6 +159,18 @@ static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t static uint16_t max_read_len = 0; esp_gatt_status_t status = ESP_OK; + if (!protocomm_ble_transport_active()) { + read_len = 0; + max_read_len = 0; + read_buf = NULL; + esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id, + param->read.trans_id, ESP_GATT_ERROR, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Send response error in read"); + } + return; + } + ESP_LOGD(TAG, "Inside read w/ session - %d on param %d %d", param->read.conn_id, param->read.handle, read_len); if (!read_len && !param->read.offset) { @@ -206,7 +237,8 @@ static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if, memcpy(prepare_write_env.prepare_buf + param->write.offset, param->write.value, param->write.len); - prepare_write_env.prepare_len += param->write.len; + int next_len = param->write.offset + param->write.len; + prepare_write_env.prepare_len = MAX(prepare_write_env.prepare_len, next_len); prepare_write_env.handle = param->write.handle; } @@ -254,6 +286,17 @@ static void transport_simple_ble_write(esp_gatts_cb_event_t event, esp_gatt_if_t ESP_LOGD(TAG, "Inside write with session - %d on attr handle = %d \nlen = %d, is_prep = %d", param->write.conn_id, param->write.handle, param->write.len, param->write.is_prep); + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring write on inactive protocomm transport"); + protocomm_ble_reset_prepare_write(); + if (param->write.need_rsp) { + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, + param->write.trans_id, ESP_GATT_ERROR, NULL); + } + esp_ble_gatts_close(gatts_if, param->write.conn_id); + return; + } + if (param->write.is_prep) { ret = prepare_write_event_env(gatts_if, param); if (ret != ESP_OK) { @@ -298,6 +341,15 @@ static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt ssize_t outlen = 0; ESP_LOGD(TAG, "Inside exec_write w/ session - %d", param->exec_write.conn_id); + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring exec write on inactive protocomm transport"); + protocomm_ble_reset_prepare_write(); + esp_ble_gatts_send_response(gatts_if, param->exec_write.conn_id, + param->exec_write.trans_id, ESP_GATT_ERROR, NULL); + esp_ble_gatts_close(gatts_if, param->exec_write.conn_id); + return; + } + if ((param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) && prepare_write_env.prepare_buf) { @@ -336,12 +388,20 @@ static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt esp_err_t ret; ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id); + /* Drop any staged prepare-write data when a connection ends */ + protocomm_ble_reset_prepare_write(); + /* Ignore BLE events received after protocomm layer is stopped */ if (protoble_internal == NULL) { ESP_LOGI(TAG,"Protocomm layer has already stopped"); return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring disconnect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->close_transport_session) { ret = protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst, @@ -368,12 +428,20 @@ static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if esp_err_t ret; ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id); + /* Start each connection with a clean prepare-write buffer */ + protocomm_ble_reset_prepare_write(); + /* Ignore BLE events received after protocomm layer is stopped */ if (protoble_internal == NULL) { ESP_LOGI(TAG,"Protocomm layer has already stopped"); return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring connect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->new_transport_session) { ret = protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst, @@ -396,6 +464,9 @@ static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if static void transport_simple_ble_set_mtu(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + if (!protocomm_ble_transport_active()) { + return; + } protoble_internal->gatt_mtu = param->mtu.mtu; return; } @@ -485,6 +556,7 @@ static ssize_t populate_gatt_db(esp_gatts_attr_db_t **gatt_db_generated) static void protocomm_ble_cleanup(void) { + protocomm_ble_reset_prepare_write(); if (protoble_internal) { if (protoble_internal->g_nu_lookup) { for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { @@ -637,20 +709,29 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con esp_err_t protocomm_ble_stop(protocomm_t *pc) { - if ((pc != NULL) && - (protoble_internal != NULL ) && - (pc == protoble_internal->pc_ble)) { - esp_err_t ret = ESP_OK; + if ((pc == NULL) || + (protoble_internal == NULL ) || + (pc != protoble_internal->pc_ble)) { + return ESP_ERR_INVALID_ARG; + } + esp_err_t ret = ESP_OK; + bool ble_callbacks_active = true; uint8_t protocomm_keep_ble_on = get_keep_ble_on(); + + protoble_internal->pc_ble = NULL; + if (protocomm_keep_ble_on) { #ifdef CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP /* Keep BT stack on, but terminate the connection after provisioning */ - ret = simple_ble_disconnect(); + ret = simple_ble_disconnect(); if (ret) { ESP_LOGE(TAG, "BLE disconnect failed"); - } - simple_ble_deinit(); + } + simple_ble_deinit(); + ble_callbacks_active = false; +#else + ESP_LOGD(TAG, "Keeping BLE stack running after protocomm stop"); #endif // CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP } else { @@ -661,10 +742,13 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) ESP_LOGE(TAG, "BLE stop failed"); } simple_ble_deinit(); + ble_callbacks_active = false; } + protocomm_ble_reset_prepare_write(); + + if (!ble_callbacks_active) { protocomm_ble_cleanup(); - return ret; } - return ESP_ERR_INVALID_ARG; + return ret; } diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c index fea2516a5aca..04f8e22326ee 100644 --- a/components/protocomm/src/transports/protocomm_nimble.c +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -73,6 +74,11 @@ typedef struct _protocomm_ble { } _protocomm_ble_internal_t; static _protocomm_ble_internal_t *protoble_internal; + +static bool protocomm_ble_transport_active(void) +{ + return (protoble_internal != NULL) && (protoble_internal->pc_ble != NULL); +} static struct ble_gap_adv_params adv_params; static char *protocomm_ble_device_name; static struct ble_hs_adv_fields adv_data, resp_data; @@ -285,6 +291,9 @@ simple_ble_gap_event(struct ble_gap_event *event, void *arg) /* Gets `g_nu_lookup name handler` from 128 bit UUID */ static const char *uuid128_to_handler(uint8_t *uuid) { + if (!protocomm_ble_transport_active()) { + return NULL; + } /* Use it to convert 128 bit UUID to 16 bit UUID.*/ uint8_t *uuid16 = uuid + 12; for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) { @@ -303,6 +312,11 @@ static int gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring descriptor access on inactive protocomm transport"); + return BLE_ATT_ERR_UNLIKELY; + } + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) { ESP_LOGE(TAG, "Invalid operation on Read-only Descriptor"); return BLE_ATT_ERR_UNLIKELY; @@ -331,6 +345,11 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, uint16_t data_len = 0; uint16_t data_buf_len = 0; + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring characteristic access on inactive protocomm transport"); + return BLE_ATT_ERR_UNLIKELY; + } + switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: ESP_LOGD(TAG, "Read attempted for characteristic UUID = %s, attr_handle = %d", @@ -595,6 +614,11 @@ static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *a return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring disconnect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->close_transport_session) { ret = @@ -628,6 +652,11 @@ static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring connect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->new_transport_session) { ret = @@ -651,6 +680,9 @@ static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg) { + if (!protocomm_ble_transport_active()) { + return; + } protoble_internal->gatt_mtu = event->mtu.value; return; } @@ -1042,16 +1074,21 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con esp_err_t protocomm_ble_stop(protocomm_t *pc) { ESP_LOGD(TAG, "protocomm_ble_stop called here..."); - if ((pc != NULL) && - (protoble_internal != NULL ) && - (pc == protoble_internal->pc_ble)) { - esp_err_t ret = ESP_OK; - - esp_err_t rc = ble_gap_adv_stop(); - if (rc) { - ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", - rc); - } + if ((pc == NULL) || + (protoble_internal == NULL ) || + (pc != protoble_internal->pc_ble)) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t ret = ESP_OK; + bool ble_callbacks_active = true; + esp_err_t rc = ble_gap_adv_stop(); + if (rc) { + ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", + rc); + } + + protoble_internal->pc_ble = NULL; if (ble_cfg_p->keep_ble_on) { #ifdef CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP @@ -1061,6 +1098,9 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) ESP_LOGI(TAG, "Error in terminating connection rc = %d",rc); } free_gatt_ble_misc_memory(ble_cfg_p); + ble_callbacks_active = false; +#else + ESP_LOGD(TAG, "Keeping BLE stack running after protocomm stop"); #endif // CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP } else { @@ -1070,10 +1110,11 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) nimble_port_deinit(); } free_gatt_ble_misc_memory(ble_cfg_p); + ble_callbacks_active = false; } + if (!ble_callbacks_active) { protocomm_ble_cleanup(); - return ret; } - return ESP_ERR_INVALID_ARG; + return ret; } diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index d14aa56e4a2c..ccf75e989d1b 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -453,11 +453,11 @@ config SOC_BRANCH_PREDICTOR_SUPPORTED config SOC_CPU_BREAKPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE hex diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 1c8d8373967d..bb696ebb35fc 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -165,8 +165,8 @@ #define SOC_INT_HW_NESTED_SUPPORTED 1 // Support for hardware interrupts nesting #define SOC_BRANCH_PREDICTOR_SUPPORTED 1 -#define SOC_CPU_BREAKPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINTS_NUM 4 +#define SOC_CPU_BREAKPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINTS_NUM 3 #define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x100 // bytes #define SOC_CPU_HAS_PMA 1 diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 8e15f46312ec..5155d3e4ea82 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -125,11 +125,11 @@ config SOC_CPU_COPROC_NUM config SOC_CPU_BREAKPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE hex diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 868180cf2320..7539f159ecc5 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -156,8 +156,8 @@ #define SOC_CPU_HAS_FPU_EXT_ILL_BUG 0 // EXT_ILL CSR doesn't support FLW/FSW #define SOC_CPU_COPROC_NUM 2 -#define SOC_CPU_BREAKPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINTS_NUM 4 +#define SOC_CPU_BREAKPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINTS_NUM 3 #define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x80000000 // bytes #define SOC_CPU_HAS_PMA 1 diff --git a/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h b/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h index 910c591aaaa0..a0485fa38d52 100644 --- a/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h +++ b/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h @@ -88,6 +88,14 @@ extern "C" { #define LP_SYSTEM_REG_ANA_FIB_M (LP_SYSTEM_REG_ANA_FIB_V << LP_SYSTEM_REG_ANA_FIB_S) #define LP_SYSTEM_REG_ANA_FIB_V 0x0000007FU #define LP_SYSTEM_REG_ANA_FIB_S 14 +/** LP_SYSTEM_REG_LP_FIB_SEL : R/W; bitpos: [28:21]; default: 255; + * This is for compatibility with hw_ver3 chips + * This field does not exist on hw_ver1 chips + */ +#define LP_SYSTEM_REG_LP_FIB_SEL 0x000000FFU +#define LP_SYSTEM_REG_LP_FIB_SEL_M (LP_SYSTEM_REG_LP_FIB_SEL_V << LP_SYSTEM_REG_LP_FIB_SEL_S) +#define LP_SYSTEM_REG_LP_FIB_SEL_V 0x000000FFU +#define LP_SYSTEM_REG_LP_FIB_SEL_S 21 /** LP_SYSTEM_REG_LP_FIB_BOD_RESET : R/W; bitpos: [22]; default: 1; * need_des */ diff --git a/components/wpa_supplicant/test_apps/main/test_offchannel.c b/components/wpa_supplicant/test_apps/main/test_offchannel.c index 0f73079e3b8f..6ccb9b843a13 100644 --- a/components/wpa_supplicant/test_apps/main/test_offchannel.c +++ b/components/wpa_supplicant/test_apps/main/test_offchannel.c @@ -265,4 +265,4 @@ static void test_wifi_roc(void) } } -TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=wifi_two_dut][timeout=90]", test_wifi_roc, test_wifi_offchan_tx); +TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=two_duts][timeout=90]", test_wifi_roc, test_wifi_offchan_tx); diff --git a/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c b/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c index df75beba460b..2bc994c8fc9b 100644 --- a/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c +++ b/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c @@ -198,6 +198,6 @@ static void test_softap_connection(void) } /* Test that wifi starts, scans and stops normally when .bss segment is allowed to move to external memory */ -TEST_CASE_MULTIPLE_DEVICES("test wifi connection for sta and softap when ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY is enabled", "[esp_wifi][test_env=wifi_two_dut]", test_station_connection, test_softap_connection); +TEST_CASE_MULTIPLE_DEVICES("test wifi connection for sta and softap when ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY is enabled", "[esp_wifi][test_env=two_duts]", test_station_connection, test_softap_connection); #endif // CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY diff --git a/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py b/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py index c8633f1fda82..e7ff601bfab2 100644 --- a/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py +++ b/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py @@ -16,7 +16,7 @@ def test_wpa_supplicant_ut(dut: Dut) -> None: dut.run_all_single_board_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count', [ @@ -31,12 +31,12 @@ def test_wpa_supplicant_ut(dut: Dut) -> None: ) def test_wpa_supplicant_ut_offchan(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) # test when external bss segment is enabled -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, config', [ @@ -50,11 +50,11 @@ def test_wpa_supplicant_ut_offchan(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32s3'], indirect=['target']) def test_wpa_supplicant_ut_psram(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c2eco4 @pytest.mark.xtal_26mhz @pytest.mark.parametrize( @@ -71,11 +71,11 @@ def test_wpa_supplicant_ut_psram(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32c2'], indirect=['target']) def test_wpa_supplicant_esp32c2eco4_xtal26mhz(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', @@ -90,5 +90,5 @@ def test_wpa_supplicant_esp32c2eco4_xtal26mhz(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32c3'], indirect=['target']) def test_wpa_supplicant_esp32c3eco7(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index a81b73bb74c3..a98157a47813 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -46,6 +46,8 @@ INPUT = \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h \ @@ -271,6 +273,7 @@ INPUT = \ $(PROJECT_PATH)/components/hal/include/hal/efuse_hal.h \ $(PROJECT_PATH)/components/hal/include/hal/eth_types.h \ $(PROJECT_PATH)/components/hal/include/hal/lp_core_types.h \ + $(PROJECT_PATH)/components/hal/include/hal/sd_types.h \ $(PROJECT_PATH)/components/hal/include/hal/uhci_types.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps_init.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps.h \ @@ -310,6 +313,9 @@ INPUT = \ $(PROJECT_PATH)/components/protocomm/include/transports/protocomm_httpd.h \ $(PROJECT_PATH)/components/protocomm/include/crypto/srp6a/esp_srp.h \ $(PROJECT_PATH)/components/pthread/include/esp_pthread.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_protocol_types.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h \ $(PROJECT_PATH)/components/sdmmc/include/sdmmc_cmd.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/adc_channel.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/clk_tree_defs.h \ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index 37601065176c..f012c2c97ce0 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -56,6 +56,4 @@ INPUT += \ $(PROJECT_PATH)/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h \ $(PROJECT_PATH)/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/bitscrambler_peri_select.h \ - $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl.h \ - $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h \ $(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h \ diff --git a/docs/en/api-guides/ble/blufi.rst b/docs/en/api-guides/ble/blufi.rst index 22f9bc8cb8e1..718f7abaabf3 100644 --- a/docs/en/api-guides/ble/blufi.rst +++ b/docs/en/api-guides/ble/blufi.rst @@ -12,6 +12,12 @@ Fragmenting, data encryption, and checksum verification in the BluFi layer are t You can customize symmetric encryption, asymmetric encryption, and checksum support customization. Here we use the DH algorithm for key negotiation, 128-AES algorithm for data encryption, and CRC16 algorithm for checksum verification. +.. note:: + + **BluFi is currently in maintenance mode, and no new features are planned.** + + For new projects or when adding Wi-Fi provisioning, we recommend using the `network_provisioning`_ component, which offers a modern, secure, and actively maintained solution. + Getting Started ----------------- @@ -665,43 +671,46 @@ The Security Implementation of {IDF_TARGET_NAME} The application layer needs to register several security-related functions to BluFi: -.. code-block:: c + .. code-block:: c - typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) + typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) -This function is for {IDF_TARGET_NAME} to receive normal data during negotiation. After processing is completed, the data will be transmitted using Output_data and Output_len. + This function is for {IDF_TARGET_NAME} to receive normal data during negotiation. After processing is completed, the data will be transmitted using Output_data and Output_len. -BluFi will send output_data from Negotiate_data_handler after Negotiate_data_handler is called. + BluFi will send output_data from Negotiate_data_handler after Negotiate_data_handler is called. -Here are two "*", which means the length of the data to be emitted is unknown. Therefore, it requires the function to allocate itself (malloc) or point to the global variable to inform whether the memory needs to be freed by NEED_FREE. + Here are two ``*``, which means the length of the data to be emitted is unknown. Therefore, it requires the function to allocate itself (malloc) or point to the global variable to inform whether the memory needs to be freed by NEED_FREE. -.. code-block:: c + .. code-block:: c - typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as a 8-bit of IV. + The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as a 8-bit of IV. -.. code-block:: c + .. code-block:: c - typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as an 8-bit of IV. + The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as an 8-bit of IV. -.. code-block:: c + .. code-block:: c - typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + + This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame. -This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame. 5. Implementing Stronger Security -The default encryption/decryption logic in this example is intended for demonstration purposes only. + The default encryption and decryption logic in this example is intended for demonstration purposes only. If your application requires stronger security guarantees, consider one of the following approaches: + + - **Custom Security Callbacks**: Implement your own encryption, decryption, authentication, and checksum algorithms by defining custom security callbacks in the Blufi framework: -If you require a higher level of security, it is recommended to implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the BluFi framework. + .. code-block:: c -.. code-block:: c + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks) + - **Network Provisioning Component (recommended)**: For a more robust, secure, and production-ready provisioning solution, consider using the `network_provisioning`_ component. GATT Related Instructions ---------------------------- @@ -714,3 +723,6 @@ BluFi Service UUID: 0xFFFF, 16 bit BluFi (the mobile > {IDF_TARGET_NAME}): 0xFF01, writable Blufi ({IDF_TARGET_NAME} > the mobile phone): 0xFF02, readable and callable + + +.. _network_provisioning: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index 595564629605..94e7cccfe682 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -29,6 +29,7 @@ Mesh Core * Private Beacon * Subnet Bridge * Minor Enhancements + * Device Firmware Update (Preview) * Multiple Client Models Run Simultaneously * Support multiple client models send packets to different nodes simultaneously @@ -132,6 +133,14 @@ Mesh Models * Light LC Server * Light LC Setup Server +* Device Firmware Update Client models + * Firmware Update Client model (Preview) + * Firmware Distribution Client model (Preview) + +* Device Firmware Update Server models + * Firmware Update Server model (Preview) + * Firmware Distribution Server model (Preview) + Mesh Examples """"""""""""" diff --git a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst index 35de1143e513..03e522c3bf4f 100644 --- a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst +++ b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst @@ -228,3 +228,12 @@ Composition and Metadata ^^^^^^^^^^^^^^^^^^^^^^^^ .. include-build-file:: inc/esp_ble_mesh_cm_data_api.inc + +Device Firmware Update + +.. include-build-file:: inc/esp_ble_mesh_dfu_model_api.inc + +Device Firmware Slots + +.. include-build-file:: inc/esp_ble_mesh_dfu_slot_api.inc + diff --git a/docs/en/api-reference/peripherals/sdmmc_host.rst b/docs/en/api-reference/peripherals/sdmmc_host.rst index 64160b824acc..76ea45e2dfd7 100644 --- a/docs/en/api-reference/peripherals/sdmmc_host.rst +++ b/docs/en/api-reference/peripherals/sdmmc_host.rst @@ -176,8 +176,8 @@ To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_co If the design does require higher speed SD modes (which only work at 1.8V IO levels), there are two options available: - - Use the on-chip programmable LDO. In this case, connect the desired LDO output channel to VDDPST_5 (SD_VREF) pin. Call :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` to initialize the SD power control driver, then set :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` to the resulting handle. - - Use an external programmable LDO. Likewise, connect the LDO output to the VDDPST_5 (SD_VREF) pin. Then implement a custom `sd_pwr_ctrl` driver to control your LDO. Finally, assign :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` to the handle of your driver instance. + - Use the on-chip programmable LDO. In this case, connect the desired LDO output channel to VDDPST_5 (SD_VREF) pin. Call :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` to initialize the SD power control driver, then set :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` to the resulting handle. + - Use an external programmable LDO. Likewise, connect the LDO output to the VDDPST_5 (SD_VREF) pin. Then implement a custom `sd_pwr_ctrl` driver to control your LDO. Finally, assign :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` to the handle of your driver instance. DDR Mode for eMMC Chips @@ -209,3 +209,7 @@ API Reference ------------- .. include-build-file:: inc/sdmmc_host.inc + +.. include-build-file:: inc/sd_pwr_ctrl.inc + +.. include-build-file:: inc/sd_pwr_ctrl_by_on_chip_ldo.inc diff --git a/docs/en/api-reference/storage/sdmmc.rst b/docs/en/api-reference/storage/sdmmc.rst index f90ba43625f5..1902d072fe30 100644 --- a/docs/en/api-reference/storage/sdmmc.rst +++ b/docs/en/api-reference/storage/sdmmc.rst @@ -130,4 +130,6 @@ API Reference .. include-build-file:: inc/sdmmc_cmd.inc +.. include-build-file:: inc/sd_protocol_types.inc + .. include-build-file:: inc/sdmmc_types.inc diff --git a/docs/zh_CN/api-guides/ble/blufi.rst b/docs/zh_CN/api-guides/ble/blufi.rst index 50a170ffae89..4629c8634d8d 100644 --- a/docs/zh_CN/api-guides/ble/blufi.rst +++ b/docs/zh_CN/api-guides/ble/blufi.rst @@ -12,6 +12,12 @@ BluFi 流程的关键部分包括数据的分片、加密以及校验和验证 用户可按需自定义用于对称加密、非对称加密以及校验的算法。此处,我们采用 DH 算法进行密钥协商,128-AES 算法用于数据加密,CRC16 算法用于校验和验证。 +.. note:: + + **BluFi 目前处于维护模式,暂不计划增加新功能。** + + 对于新项目或需要添加 Wi-Fi 配网功能的场景,建议使用 `network_provisioning`_ 组件。该组件更加现代、安全,并且仍在积极维护中。 + 快速入门 -------- @@ -665,43 +671,46 @@ ACK 帧格式 (8 bit): 应用层需向 BluFi 注册以下几个与安全相关的函数: -.. code-block:: c + .. code-block:: c - typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) + typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) -该函数用来接收协商期间的正常数据 (normal data)。数据处理完成后,需要将待发送的数据使用 output_data 和 output_len 传出。 + 该函数用来接收协商期间的正常数据 (normal data)。数据处理完成后,需要将待发送的数据使用 output_data 和 output_len 传出。 -BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler 传出的 output_data。 + BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler 传出的 output_data。 -这里的两个 “*” 是因为需要发出去的数据长度未知,所以需要函数自行分配 (malloc) 或者指向全局变量,并告知是否需要通过 NEED_FREE 释放内存。 + 这里的两个 ``*`` 是因为需要发出去的数据长度未知,所以需要函数自行分配 (malloc) 或者指向全局变量,并告知是否需要通过 NEED_FREE 释放内存。 -.. code-block:: c + .. code-block:: c - typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 + 加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 -.. code-block:: c + .. code-block:: c - typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 + 加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 -.. code-block:: c + .. code-block:: c - typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + + 该函数用来进行校验,返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。 -该函数用来进行校验,返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。 5. 实现更强的安全性 -本示例中默认的加密/解密逻辑仅用于演示目的。 + 示例中的默认加密、解密逻辑仅用于演示目的。如果你的应用需要更高的安全保障,可选择以下任一方法: + + - **自定义安全回调**:通过改写 BluFi 框架中的安全回调函数,自定义加密、解密、认证以及校验算法: -如果需要更高等级的安全性,建议通过自定义 BluFi 框架中的安全回调函数,实现您自己的加密、解密、认证以及校验算法。 + .. code-block:: c -.. code-block:: c + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks) + - **网络配网组件(推荐使用)**:使用 ESP-IDF 提供的 `network_provisioning`_ 组件,实现安全、可直接使用的配网解决方案。 GATT 相关说明 @@ -715,3 +724,6 @@ BluFi Service UUID: 0xFFFF,16 bit BluFi(手机 > {IDF_TARGET_NAME})特性:0xFF01,主要权限:可写 BluFi({IDF_TARGET_NAME} > 手机)特性:0xFF02,主要权限:可读可通知 + + +.. _network_provisioning: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index edac2c0b2c14..a383f17c3d75 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -132,6 +132,14 @@ Mesh 模型 * 灯光 LC 服务器 * 灯光 LC 设置服务器 +* 设备固件更新客户端模型 + * 固件更新客户端模型(预览) + * 固件分发客户端模型(预览) + +* 设备固件更新服务器模型 + * 固件更新服务器模型(预览) + * 固件分发服务器模型(预览) + Mesh 示例 """"""""""" diff --git a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst index 53e81d8ab725..4fcf9a5b2933 100644 --- a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst +++ b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst @@ -176,8 +176,8 @@ SDMMC 主机驱动支持以下速率模式: 如果设计需要更高速度的 SD 模式(仅在 1.8 V IO 电平下工作),则有两种可选方案: - - 使用片上可编程 LDO。将所需的 LDO 输出通道连接到 VDDPST_5 (SD_VREF) 管脚上,并调用 :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` 来初始化 SD 电源控制驱动。最后,将 :cpp:class:`sdmmc_host_t::pwr_ctl_handle` 设置为生成句柄。 - - 使用外部可编程 LDO。同样,将 LDO 输出连接到 VDDPST_5 (SD_VREF) 管脚,并自定义 `sd_pwr_ctrl` 驱动程序来控制 LDO。最后,将 :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` 分配给驱动程序实例句柄。 + - 使用片上可编程 LDO。将所需的 LDO 输出通道连接到 VDDPST_5 (SD_VREF) 管脚上,并调用 :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` 来初始化 SD 电源控制驱动。最后,将 :cpp:member:`sdmmc_host_t::pwr_ctl_handle` 设置为生成句柄。 + - 使用外部可编程 LDO。同样,将 LDO 输出连接到 VDDPST_5 (SD_VREF) 管脚,并自定义 `sd_pwr_ctrl` 驱动程序来控制 LDO。最后,将 :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` 分配给驱动程序实例句柄。 eMMC 芯片的 DDR 模式 @@ -209,3 +209,7 @@ API 参考 ------------- .. include-build-file:: inc/sdmmc_host.inc + +.. include-build-file:: inc/sd_pwr_ctrl.inc + +.. include-build-file:: inc/sd_pwr_ctrl_by_on_chip_ldo.inc diff --git a/docs/zh_CN/api-reference/storage/sdmmc.rst b/docs/zh_CN/api-reference/storage/sdmmc.rst index fa23ff479ae2..7d4d7b5fcf69 100644 --- a/docs/zh_CN/api-reference/storage/sdmmc.rst +++ b/docs/zh_CN/api-reference/storage/sdmmc.rst @@ -130,4 +130,6 @@ API 参考 .. include-build-file:: inc/sdmmc_cmd.inc +.. include-build-file:: inc/sd_protocol_types.inc + .. include-build-file:: inc/sdmmc_types.inc diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index f79848069e87..69caebef10db 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -141,6 +141,8 @@ examples/bluetooth/esp_hid_host: - if: SOC_BT_SUPPORTED != 1 depends_components+: - esp_hid + depends_filepatterns: + - examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py examples/bluetooth/hci/ble_adv_scan_combined: <<: *bt_default_depends diff --git a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c index 34b6cc1185ba..171289a8a993 100644 --- a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c @@ -695,7 +695,7 @@ void app_main(void) /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication - esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to No output No input + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to DisplayOnly uint8_t key_size = 16; //the key size should be 7~16 bytes uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py b/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py index a19cb8ed7870..d2cccabc4022 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path import time +from pathlib import Path from typing import Tuple import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize -# Case 1: gatt write throughput test(EXAMPLE_CI_ID = 2) + +CUR_DIR = Path(__file__).parent.resolve() -@pytest.mark.wifi_two_dut +# Case 1: gatt write throughput test(EXAMPLE_CI_ID = 2) +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'write', 'y', ), @@ -54,7 +56,7 @@ def test_gatt_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> Non # Case 2: gatt write throughput test for ESP32C2 26mhz xtal(EXAMPLE_CI_ID = 2) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -63,7 +65,7 @@ def test_gatt_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> Non 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'esp32c2_xtal26m_write', 'y', ), @@ -98,13 +100,13 @@ def test_c2_26mhz_xtal_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut # Case 3: gatt notify throughput test(EXAMPLE_CI_ID = 1) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'notify', 'y', ), @@ -144,7 +146,7 @@ def test_gatt_notify_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> No # Case 4: gatt notify throughput test for ESP32C2 26mhz xtal(EXAMPLE_CI_ID = 1) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -153,7 +155,7 @@ def test_gatt_notify_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> No 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'esp32c2_xtal26m_notify', 'y', ), diff --git a/examples/bluetooth/bluedroid/ble/pytest_ble_test.py b/examples/bluetooth/bluedroid/ble/pytest_ble_test.py index 7ac6ec61fc44..6210ddcd4837 100644 --- a/examples/bluetooth/bluedroid/ble/pytest_ble_test.py +++ b/examples/bluetooth/bluedroid/ble/pytest_ble_test.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pexpect @@ -8,17 +8,19 @@ from pytest_embedded import Dut from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize -# Case 1: gatt client and gatt server test -# EXAMPLE_CI_ID=3 +CUR_DIR = Path(__file__).parent.resolve() -@pytest.mark.wifi_two_dut + +# Case 1: gatt client and gatt server test +# EXAMPLE_CI_ID=3 +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'name', 'y', ), @@ -61,7 +63,7 @@ def test_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: gatt client and gatt server test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=3 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -70,7 +72,7 @@ def test_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'esp32c2_xtal26m', 'y', ), @@ -110,13 +112,13 @@ def test_c2_26mhz_xtal_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> N # Case 3: gatt security server and gatt security client test # EXAMPLE_CI_ID=5 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_security_server")}|{os.path.join(os.path.dirname(__file__), "gatt_security_client")}', + f'{str(CUR_DIR / "gatt_security_server")}|{str(CUR_DIR / "gatt_security_client")}', 'name', 'y', ), @@ -126,7 +128,7 @@ def test_c2_26mhz_xtal_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> N @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32c6', 'esp32c5', 'esp32h2', 'esp32s3', 'esp32c61'], indirect=['target'] ) -def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: Tuple) -> None: +def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: tuple) -> None: gatt_security_client = dut[1] gatt_security_server = dut[0] gatt_security_client_addr = ( @@ -143,9 +145,9 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T gatt_security_client.expect_exact('Scanning start successfully', timeout=30) gatt_security_client.expect_exact('Device found BE', timeout=30) # can not get rpa_address, so not check server address - gatt_security_client.expect_exact(f'Connected, conn_id 0, remote ', timeout=30) + gatt_security_client.expect_exact('Connected, conn_id 0, remote ', timeout=30) if target == ('esp32', 'esp32'): - gatt_security_server.expect_exact(f'Connected, conn_id 0, remote', timeout=30) + gatt_security_server.expect_exact('Connected, conn_id 0, remote', timeout=30) else: gatt_security_server.expect_exact(f'Connected, conn_id 0, remote {gatt_security_client_addr}', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) @@ -158,12 +160,12 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T gatt_security_server.expect_exact('Key exchanged, key_type ESP_LE_KEY_LID', timeout=30) gatt_security_server.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) if target == ('esp32', 'esp32'): - gatt_security_server.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_server.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) else: gatt_security_server.expect_exact( f'Authentication complete, addr_type 0, addr {gatt_security_client_addr}', timeout=30 ) - gatt_security_client.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_client.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) gatt_security_server.expect_exact('Pairing successfully', timeout=30) gatt_security_server.expect_exact('Bonded devices number 1', timeout=30) gatt_security_client.expect_exact('Pairing successfully', timeout=30) @@ -178,7 +180,7 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T # Case 4: gatt security server and gatt security client test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=5 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -187,7 +189,7 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_security_server")}|{os.path.join(os.path.dirname(__file__), "gatt_security_client")}', + f'{str(CUR_DIR / "gatt_security_server")}|{str(CUR_DIR / "gatt_security_client")}', 'esp32c2_xtal26m', 'y', ), @@ -211,7 +213,7 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD gatt_security_client.expect_exact('Scanning start successfully', timeout=30) gatt_security_client.expect_exact('Device found BE', timeout=30) # can not get rpa_address, so not check server address - gatt_security_client.expect_exact(f'Connected, conn_id 0, remote ', timeout=30) + gatt_security_client.expect_exact('Connected, conn_id 0, remote ', timeout=30) gatt_security_server.expect_exact(f'Connected, conn_id 0, remote {gatt_security_client_addr}', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_LENC', timeout=30) @@ -225,7 +227,7 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD gatt_security_server.expect_exact( f'Authentication complete, addr_type 0, addr {gatt_security_client_addr}', timeout=30 ) - gatt_security_client.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_client.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) gatt_security_server.expect_exact('Pairing successfully', timeout=30) gatt_security_server.expect_exact('Bonded devices number 1', timeout=30) gatt_security_client.expect_exact('Pairing successfully', timeout=30) @@ -239,13 +241,13 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD # Case 5: ble ibeacon test -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}|{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}', + f'{str(CUR_DIR / "ble_ibeacon")}|{str(CUR_DIR / "ble_ibeacon")}', 'sender|receiver', 'y', ), @@ -277,7 +279,7 @@ def test_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 5: ble ibeacon test for ESP32C2 26mhz xtal -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -286,7 +288,7 @@ def test_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}|{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}', + f'{str(CUR_DIR / "ble_ibeacon")}|{str(CUR_DIR / "ble_ibeacon")}', 'esp32c2_xtal26m_sender|esp32c2_xtal26m_receiver', 'y', ), @@ -316,13 +318,13 @@ def test_c2_26mhz_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> # Case 6: gatt client and gatt server config test # EXAMPLE_CI_ID=4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'cfg_test', 'y', ), @@ -365,7 +367,7 @@ def test_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 7: gatt client and gatt server config test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=3 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -374,7 +376,7 @@ def test_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'esp32c2_cfg_test', 'y', ), @@ -414,9 +416,7 @@ def test_c2_26mhz_xtal_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut # Case 8: BLE init deinit loop test @pytest.mark.generic -@pytest.mark.parametrize( - 'config, app_path', [('init_deinit', f'{os.path.join(os.path.dirname(__file__), "gatt_client")}')], indirect=True -) +@pytest.mark.parametrize('config, app_path', [('init_deinit', f'{str(CUR_DIR / "gatt_client")}')], indirect=True) @idf_parametrize( 'target', ['esp32c6', 'esp32h2', 'esp32c3', 'esp32s3', 'esp32c5', 'esp32c61', 'esp32'], indirect=['target'] ) @@ -431,12 +431,12 @@ def test_bluedroid_host_init_deinit(dut: Dut) -> None: # # Case 9: BLE init deinit loop test for ESP32C2 26mhz xtal -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'baud, app_path, config', [ - ('74880', f'{os.path.join(os.path.dirname(__file__), "gatt_client")}', 'esp32c2_init_deinit'), + ('74880', f'{str(CUR_DIR / "gatt_client")}', 'esp32c2_init_deinit'), ], indirect=True, ) diff --git a/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py b/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py index d48aef51ac08..e66757e798ef 100644 --- a/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py +++ b/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize -# Case 1: ble50 security client and ble50 security server test -# EXAMPLE_CI_ID=6 + +CUR_DIR = Path(__file__).parent.resolve() -@pytest.mark.wifi_two_dut +# Case 1: ble50 security client and ble50 security server test +# EXAMPLE_CI_ID=6 +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'name', 'y', ), @@ -52,7 +54,7 @@ def test_ble50_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: ble50 security client and ble50 security server test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=6 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -61,7 +63,7 @@ def test_ble50_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'esp32c2_xtal26m', 'y', ), @@ -96,13 +98,13 @@ def test_c2_26mhz_xtal_ble50_security_func(app_path: str, dut: Tuple[IdfDut, Idf # Case 3: period_adv and period_sync test # EXAMPLE_CI_ID=8 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "periodic_adv")}|{os.path.join(os.path.dirname(__file__), "periodic_sync")}', + f'{str(CUR_DIR / "periodic_adv")}|{str(CUR_DIR / "periodic_sync")}', 'name', 'y', ), @@ -123,14 +125,14 @@ def test_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None adv_dut.expect_exact('Periodic advertising start, status 0', timeout=30) sync_dut.expect_exact('Extended scanning params set, status 0', timeout=30) sync_dut.expect_exact('Extended scanning start, status 0', timeout=30) - sync_dut.expect_exact(f'Create sync with the peer device BE', timeout=30) + sync_dut.expect_exact('Create sync with the peer device BE', timeout=30) sync_dut.expect_exact('Periodic advertising sync establish, status 0', timeout=30) sync_dut.expect_exact('Periodic adv report, sync handle ', timeout=30) # Case 4: period_adv and period_sync test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=8 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -139,7 +141,7 @@ def test_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "periodic_adv")}|{os.path.join(os.path.dirname(__file__), "periodic_sync")}', + f'{str(CUR_DIR / "periodic_adv")}|{str(CUR_DIR / "periodic_sync")}', 'esp32c2_xtal26m', 'y', ), @@ -159,20 +161,20 @@ def test_c2_26mhz_xtal_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, Id adv_dut.expect_exact('Periodic advertising start, status 0', timeout=30) sync_dut.expect_exact('Extended scanning params set, status 0', timeout=30) sync_dut.expect_exact('Extended scanning start, status 0', timeout=30) - sync_dut.expect_exact(f'Create sync with the peer device BE', timeout=30) + sync_dut.expect_exact('Create sync with the peer device BE', timeout=30) sync_dut.expect_exact('Periodic advertising sync establish, status 0', timeout=30) sync_dut.expect_exact('Periodic adv report, sync handle ', timeout=30) # Case 5: ble50 security client and ble50 security server config test # EXAMPLE_CI_ID=7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'cfg_test', 'y', ), @@ -210,7 +212,7 @@ def test_ble50_security_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) - # Case 6: ble50 security client and ble50 security server config test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -219,7 +221,7 @@ def test_ble50_security_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) - 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'esp32c2_cfg_test', 'y', ), diff --git a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py index 74a9e40c5a87..3190035c38ca 100644 --- a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py +++ b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py @@ -1,16 +1,15 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +import os from typing import Tuple import pexpect import pytest from pytest_embedded_idf.dut import IdfDut -# Case 1: SPP - -@pytest.mark.wifi_two_dut +# Case 1: SPP +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, erase_all, config', [ @@ -45,7 +44,7 @@ def test_bt_spp_only(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: SPP_VFS -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -74,7 +73,7 @@ def test_bt_spp_vfs(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 3: A2DP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -101,7 +100,7 @@ def test_bt_a2dp(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 4: HFP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -126,7 +125,7 @@ def test_bt_hfp(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # # Case 5: HID -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -155,7 +154,7 @@ def test_bt_hid(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 6: L2CAP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ diff --git a/examples/bluetooth/blufi/README.md b/examples/bluetooth/blufi/README.md index 6a07013c7278..6534187eb957 100644 --- a/examples/bluetooth/blufi/README.md +++ b/examples/bluetooth/blufi/README.md @@ -82,3 +82,9 @@ I (1198) BLUFI_EXAMPLE: BLUFI init finish ## 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. + +## Note +BluFi is currently in maintenance mode, and no new features are planned. + +For new projects or when adding network_provisioning, we recommend using the [network_provisioning](https://github.com/espressif/idf-extra-components/tree/master/network_provisioning). + diff --git a/examples/bluetooth/blufi/main/Kconfig.projbuild b/examples/bluetooth/blufi/main/Kconfig.projbuild index b8fe9f1957db..fc1a20695b0a 100644 --- a/examples/bluetooth/blufi/main/Kconfig.projbuild +++ b/examples/bluetooth/blufi/main/Kconfig.projbuild @@ -33,4 +33,23 @@ menu "Example Configuration" bool "WAPI PSK" endchoice + config EXAMPLE_BLUFI_BLE_SMP_ENABLE + bool "Enable BLE SMP support in BLUFI" + depends on BT_BLUEDROID_ENABLED + select BT_BLUFI_BLE_SMP_ENABLE + select BT_BLE_SMP_ENABLE + default n + help + Enable BLE Security Manager Protocol (SMP) for BLUFI. + Currently, this feature is only supported with the Bluedroid host. + + If enabled: + - BLUFI will configure SMP security parameters such as + IO capabilities, authentication mode, and key size. + - After a BLE connection is established, BLUFI will + proactively initiate a security request. + - Only after the BLE pairing is successfully completed, + BLUFI can proceed with Wi-Fi provisioning. + - If the user rejects pairing or inputs an incorrect passkey, + BLUFI will not start Wi-Fi provisioning. endmenu diff --git a/examples/bluetooth/blufi/main/blufi_example_main.c b/examples/bluetooth/blufi/main/blufi_example_main.c index 9d3d05360d04..b5dbf3e7eec2 100644 --- a/examples/bluetooth/blufi/main/blufi_example_main.c +++ b/examples/bluetooth/blufi/main/blufi_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -319,6 +319,14 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para ble_is_connected = true; esp_blufi_adv_stop(); blufi_security_init(); + #ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + // Try to initiate BLE security request after connection established. + BLUFI_INFO("Try to initiate BLE security request\n"); + esp_err_t ret = esp_blufi_start_security_request(param->connect.remote_bda); + if (ret != ESP_OK) { + BLUFI_ERROR("Failed to start security request: %s\n", esp_err_to_name(ret)); + } + #endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE break; case ESP_BLUFI_EVENT_BLE_DISCONNECT: BLUFI_INFO("BLUFI ble disconnect\n"); diff --git a/examples/bluetooth/blufi/main/blufi_init.c b/examples/bluetooth/blufi/main/blufi_init.c index ea998657e9ec..2c1af14bc871 100644 --- a/examples/bluetooth/blufi/main/blufi_init.c +++ b/examples/bluetooth/blufi/main/blufi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -16,6 +16,7 @@ #ifdef CONFIG_BT_BLUEDROID_ENABLED #include "esp_bt_main.h" #include "esp_bt_device.h" +#include "esp_gap_ble_api.h" #endif #ifdef CONFIG_BT_NIMBLE_ENABLED @@ -56,6 +57,37 @@ esp_err_t esp_blufi_host_init(void) } +#ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + +void esp_blufi_set_ble_security_params(void) +{ + /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM; // Secure Connections with MITM protection (no bonding) + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; // IO capability: DisplayOnly + uint8_t key_size = 16; //the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + //set static passkey + uint32_t passkey = 123456; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + BLUFI_INFO("BLE SMP passkey: %06" PRIu32 " (WARNING: Change this default value for production or don't use static passkey!)\n", passkey); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + /* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you, + and the response key means which key you can distribute to the master; + If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you, + and the init key means which key you can distribute to the slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); +} + +#endif // #if CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + esp_err_t esp_blufi_host_deinit(void) { int ret; @@ -112,8 +144,11 @@ esp_err_t esp_blufi_host_and_cb_init(esp_blufi_callbacks_t *example_callbacks) return ret; } - return ESP_OK; + #ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + esp_blufi_set_ble_security_params(); + #endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + return ESP_OK; } #endif /* CONFIG_BT_BLUEDROID_ENABLED */ diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c index 6b816d6d846f..dcfdab25ae20 100644 --- a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -353,26 +353,22 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node node->sig_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); if (!node->sig_model_num) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto calloc_fail; } node->vnd_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); if (!node->vnd_model_num) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto vnd_model_num_fail; } node->sig_models = (uint16_t **)calloc(node->elem_num, sizeof(uint16_t*)); if (!node->sig_models) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto sig_models_fail; } node->vnd_models = (uint32_t **)calloc(node->elem_num, sizeof(uint32_t*)); - if (!node->sig_models) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + if (!node->vnd_models) { + goto vnd_models_fail; } ESP_LOGI(TAG, "********************** Composition Data Start **********************"); @@ -387,8 +383,7 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node if (nums) { node->sig_models[seq] = (uint16_t *)calloc(nums, sizeof(uint16_t)); if (!(node->sig_models[seq])) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto sig_mode_seq_fail; } } else { node->sig_models[seq] = NULL; @@ -397,8 +392,7 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node if (numv) { node->vnd_models[seq] = (uint32_t *)calloc(numv, sizeof(uint32_t)); if (!(node->vnd_models[seq])) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto vnd_model_seq_fail; } } else { node->vnd_models[seq] = NULL; @@ -422,6 +416,32 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node seq++; } ESP_LOGI(TAG, "*********************** Composition Data End ***********************"); + return; + +vnd_model_seq_fail: + free(node->sig_models[seq]); + node->sig_models[seq] = NULL; +sig_mode_seq_fail: + for (int j = 0; j < seq; j++) { + free(node->sig_models[j]); + free(node->vnd_models[j]); + node->sig_models[j] = NULL; + node->vnd_models[j] = NULL; + } + free(node->vnd_models); + node->vnd_models = NULL; +vnd_models_fail: + free(node->sig_models); + node->sig_models = NULL; +sig_models_fail: + free(node->vnd_model_num); + node->vnd_model_num = NULL; +vnd_model_num_fail: + free(node->sig_model_num); + node->sig_model_num = NULL; +calloc_fail: + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; } static bool example_ble_mesh_query_element_have_model(uint16_t elem_addr, uint16_t model_id, uint16_t company_id) @@ -435,6 +455,10 @@ static bool example_ble_mesh_query_element_have_model(uint16_t elem_addr, uint16 elem_idx = elem_addr - node->unicast; + if (node->sig_model_num == NULL) { + return false; + } + if (company_id == CID_NVAL) { model_num = node->sig_model_num[elem_idx]; for (i = 0; i < model_num; i++) { diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 deleted file mode 100644 index e30be10c13e9..000000000000 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 +++ /dev/null @@ -1,6 +0,0 @@ -# This file was generated using idf.py save-defconfig. It can be edited manually. -# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration -# -CONFIG_BT_NIMBLE_MAX_CONNECTIONS=35 -CONFIG_BT_NIMBLE_GATT_MAX_PROCS=35 -CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=50 diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 deleted file mode 100644 index f0cb07854e15..000000000000 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 +++ /dev/null @@ -1,5 +0,0 @@ -# This file was generated using idf.py save-defconfig. It can be edited manually. -# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration -# -CONFIG_BT_NIMBLE_MAX_CONNECTIONS=34 -CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=50 diff --git a/examples/bluetooth/nimble/pytest_nimble_test.py b/examples/bluetooth/nimble/pytest_nimble_test.py index 8f9d8a1e65c4..d9c5c62fdf7c 100644 --- a/examples/bluetooth/nimble/pytest_nimble_test.py +++ b/examples/bluetooth/nimble/pytest_nimble_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pexpect import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize -# Case 1: BLE power save test + +CUR_DIR = Path(__file__).parent.resolve() -@pytest.mark.wifi_two_dut +# Case 1: BLE power save test +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', ), ], indirect=True, @@ -39,7 +41,7 @@ def test_power_save_conn(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C2 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'config, count, app_path, baud', @@ -47,7 +49,7 @@ def test_power_save_conn(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c2_xtal26m', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', '74880', ), ], @@ -69,7 +71,7 @@ def test_power_save_conn_esp32c2_26mhz(dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C2ECO4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -78,7 +80,7 @@ def test_power_save_conn_esp32c2_26mhz(dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c2eco4_xtal26m', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', '74880', ), ], @@ -100,7 +102,7 @@ def test_power_save_conn_esp32c2eco4(dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C3ECO7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'config, count, app_path', @@ -108,7 +110,7 @@ def test_power_save_conn_esp32c2eco4(dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c3eco7', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', ), ], indirect=True, diff --git a/examples/network/bridge/pytest_example_bridge.py b/examples/network/bridge/pytest_example_bridge.py index 765e37c41d2d..861005a58294 100644 --- a/examples/network/bridge/pytest_example_bridge.py +++ b/examples/network/bridge/pytest_example_bridge.py @@ -11,8 +11,11 @@ import time from concurrent.futures import Future from concurrent.futures import ThreadPoolExecutor +from typing import Generator from typing import List +from typing import Match from typing import Optional +from typing import Tuple from typing import Union import netifaces @@ -276,28 +279,38 @@ def send_brcast_msg_endnode_to_host(endnode: EndnodeSsh, host_brcast_ip: str, te return nc_host_out -@pytest.mark.eth_w5500 -@pytest.mark.parametrize( - 'config', - [ - 'w5500', - ], - indirect=True, -) -@idf_parametrize('target', ['esp32'], indirect=['target']) -def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: - # ------------------------------ # - # Pre-test testbed configuration # - # ------------------------------ # - # Get switch configuration info from the hostname +def get_legacy_host_name_match() -> Optional[Match[str]]: host_name = socket.gethostname() regex = r'ethVM-(\d+)-(\d+)' - sw_info = re.search(regex, host_name, re.DOTALL) - if sw_info is None: - raise RuntimeError('Unexpected hostname') + host_name_match = re.search(regex, host_name, re.DOTALL) + return host_name_match - sw_num = int(sw_info.group(1)) - port_num = int(sw_info.group(2)) + +def get_host_info() -> Tuple[int, int]: + # Get switch configuration info from the hostname (legacy runners) + sw_info = get_legacy_host_name_match() + if sw_info is not None: + sw_num = int(sw_info.group(1)) + port_num = int(sw_info.group(2)) + return sw_num, port_num + else: + # Get switch configuration info from the IP address of the `switch` interface (new runners) + switch_if_ip = get_host_ip_by_interface('switch', netifaces.AF_INET) + # Parse IP address: x.y.. + ip_parts = switch_if_ip.split('.') + if len(ip_parts) == 4: + sw_num = int(ip_parts[2]) + port_num = int(ip_parts[3]) + return sw_num, port_num + else: + raise RuntimeError('Unexpected switch IP address') + + +def eth_bridge_test(dut: Dut, dev_user: str, dev_password: str) -> None: + # ------------------------------ # + # Pre-test testbed configuration # + # ------------------------------ # + sw_num, port_num = get_host_info() port_num_endnode = int(port_num) + 1 # endnode address is always + 1 to the host endnode = EndnodeSsh(f'10.10.{sw_num}.{port_num_endnode}', ETHVM_ENDNODE_USER) @@ -333,7 +346,10 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: host_ip = get_host_ip_by_interface(host_if, netifaces.AF_INET) logging.info('Host IP %s', host_ip) - endnode_if = host_if # endnode is a clone of the host + if get_legacy_host_name_match() is not None: + endnode_if = host_if # endnode is a clone of the host (legacy runners) + else: + endnode_if = 'dut_p2' # interface name connected to the second port of the DUT (new runners) # Endnode MAC endnode_mac = get_endnode_mac_by_interface(endnode, endnode_if) logging.info('Endnode MAC %s', endnode_mac) @@ -355,12 +371,12 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: # TEST Objective 1: Ping the devices on the network # -------------------------------------------------- # ping bridge - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('ESP bridge is not reachable') # ping the end nodes of the network - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('End node is not reachable') @@ -529,13 +545,13 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: logging.info('Drop `Endnode` MAC') dut.write('add --addr=' + endnode_mac + ' -d') dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test == 0: raise RuntimeError('End node should not be reachable') logging.info('Remove Drop `Endnode` MAC entry') dut.write('remove --addr=' + endnode_mac) dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('End node is not reachable') @@ -568,9 +584,9 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: # Remove ARP record from Test host computer. ARP is broadcasted, hence Bridge port does not reply to a request since # it does not receive it (no forward to Bridge port). As a result, Bridge is not pingable. - subprocess.call(f'sudo arp -d {br_ip}', shell=True) - subprocess.call('arp -a', shell=True) - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + subprocess.call(['sudo', 'arp', '-d', br_ip]) + subprocess.call(['arp', '-a']) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test == 0: raise RuntimeError('Bridge should not be reachable') @@ -580,7 +596,7 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: dut.expect_exact('Bridge Config OK!') dut.write('add --addr=ff:ff:ff:ff:ff:ff -p 1 -c') dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('Bridge is not reachable') @@ -591,3 +607,28 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: endnode.close() switch1.close() + + +@pytest.fixture(scope='session', autouse=True) +def setup_test_environment() -> Generator[None, None, None]: + # Fixture code to run before any tests in the session + # make sure dut_p2 is down (only for new runners) + if get_legacy_host_name_match() is None: + subprocess.call(['sudo', 'ip', 'link', 'set', 'down', 'dev', 'dut_p2']) + + yield # Tests run here + + # Optional teardown after all tests... + + +@pytest.mark.eth_w5500 +@pytest.mark.parametrize( + 'config', + [ + 'w5500', + ], + indirect=True, +) +@idf_parametrize('target', ['esp32'], indirect=['target']) +def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: + eth_bridge_test(dut, dev_user, dev_password) diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt b/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt index e205eff4b812..0eae9c4991da 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "esp_ot_sleepy_device.c" - PRIV_REQUIRES esp_event esp_timer openthread nvs_flash ulp + PRIV_REQUIRES esp_event esp_timer openthread nvs_flash INCLUDE_DIRS ".") diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults index 18d548c09c25..6c17f055c7df 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults +++ b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults @@ -42,8 +42,6 @@ CONFIG_IEEE802154_ENABLED=y # # deep sleep # -CONFIG_ULP_COPROC_ENABLED=y -CONFIG_ULP_COPROC_RESERVE_MEM=512 CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y CONFIG_RTC_CLK_SRC_INT_RC=y CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y diff --git a/examples/protocols/l2tap/pytest_example_l2tap_echo.py b/examples/protocols/l2tap/pytest_example_l2tap_echo.py index 3defccbbed46..87e1c355f726 100644 --- a/examples/protocols/l2tap/pytest_example_l2tap_echo.py +++ b/examples/protocols/l2tap/pytest_example_l2tap_echo.py @@ -20,18 +20,26 @@ @contextlib.contextmanager def configure_eth_if(eth_type: int, target_if: str = '') -> Iterator[socket.socket]: + # try to determine which interface to use + netifs = os.listdir('/sys/class/net/') + # order matters - ETH NIC with the highest number is connected to DUT on CI runner + netifs.sort(reverse=True) + logging.info('detected interfaces: %s', str(netifs)) + + if target_if == '': + if 'dut_p1' in netifs: + target_if = 'dut_p1' + else: + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + target_if = netif + break + elif target_if not in netifs: + target_if = '' + if target_if == '': - # try to determine which interface to use - netifs = os.listdir('/sys/class/net/') - # order matters - ETH NIC with the highest number is connected to DUT on CI runner - netifs.sort(reverse=True) - logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - if netif.find('eth') == 0 or netif.find('enx') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - target_if = netif - break - if target_if == '': - raise Exception('no network interface found') + raise RuntimeError('network interface not found') logging.info('Use %s for testing', target_if) so = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(eth_type)) @@ -76,7 +84,7 @@ def recv_eth_frame(eth_type: int, eth_if: str = '') -> str: return str(eth_frame.load.decode().rstrip('\x00')) -def actual_test(dut: Dut) -> None: +def actual_test(dut: Dut, test_if: str = '') -> None: # Get DUT's MAC address res = dut.expect( r'([\s\S]*)' @@ -85,17 +93,17 @@ def actual_test(dut: Dut) -> None: dut_mac = res.group(2) # Receive "ESP32 Hello frame" - recv_eth_frame(ETH_TYPE_3) + recv_eth_frame(ETH_TYPE_3, test_if) # Sent a message and receive its echo message = 'ESP32 test message with EthType ' + hex(ETH_TYPE_1) - echoed = send_recv_eth_frame(message, ETH_TYPE_1, dut_mac) + echoed = send_recv_eth_frame(message, ETH_TYPE_1, dut_mac, test_if) if echoed == message: logging.info('PASS') else: raise Exception('Echoed message does not match!') message = 'ESP32 test message with EthType ' + hex(ETH_TYPE_2) - echoed = send_recv_eth_frame(message, ETH_TYPE_2, dut_mac) + echoed = send_recv_eth_frame(message, ETH_TYPE_2, dut_mac, test_if) if echoed == message: logging.info('PASS') else: diff --git a/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py b/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py index bfe7e7072524..2f7a14bdf18d 100644 --- a/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py +++ b/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py @@ -36,14 +36,16 @@ def find_target_if(my_if: str = '') -> str: netifs.sort(reverse=True) logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - # if no interface defined, try to find it automatically - if my_if == '': - if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - return netif + if my_if == '': + if 'dut_p1' in netifs: + return 'dut_p1' else: - if netif.find(my_if) == 0: - return my_if + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + return netif + elif my_if in netifs: + return my_if raise RuntimeError('network interface not found') @@ -135,7 +137,7 @@ def test_examples_udp_multicast_proto(dut: Dut, ip_version: str = 'ipv4', nic: s try: data, recv_addr = sock.recvfrom(1024) logging.info(f'Received {len(data)} bytes from {recv_addr}') - except socket.timeout: + except TimeoutError: raise RuntimeError(f'Timeout waiting for {ip_version} multicast message from ESP32') # Check if received from expected source @@ -143,7 +145,7 @@ def test_examples_udp_multicast_proto(dut: Dut, ip_version: str = 'ipv4', nic: s raise RuntimeError(f'Received {ip_version} multicast message from unexpected source') # Send multicast message - message = '!!! Multicast test message from host !!!'.encode() + message = b'!!! Multicast test message from host !!!' logging.info(f'Sending {ip_version} multicast message to {multicast_addr}:{PORT}') sock.sendto(message, (multicast_addr, PORT)) if ip_version == 'ipv4_mapped': diff --git a/examples/wifi/getting_started/pytest_wifi_getting_started.py b/examples/wifi/getting_started/pytest_wifi_getting_started.py index 5a3ad64d27ea..e774507cf224 100644 --- a/examples/wifi/getting_started/pytest_wifi_getting_started.py +++ b/examples/wifi/getting_started/pytest_wifi_getting_started.py @@ -6,6 +6,7 @@ import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + # @pytest.mark.supported_targets # This test should support all targets, even between different target types # For now our CI only support multi dut with esp32 @@ -20,7 +21,7 @@ # ) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path', [ @@ -49,7 +50,7 @@ def test_wifi_getting_started(dut: Tuple[IdfDut, IdfDut]) -> None: softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud, app_path', @@ -80,7 +81,7 @@ def test_wifi_getting_started_esp32c2_xtal_26mhz(dut: Tuple[IdfDut, IdfDut]) -> softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -112,7 +113,7 @@ def test_wifi_getting_started_esp32c2eco4_xtal_26mhz(dut: Tuple[IdfDut, IdfDut]) softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config, app_path', diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci b/examples/wifi/getting_started/softAP/sdkconfig.ci index b416e9f87cbb..9633644b4669 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci @@ -1,2 +1,3 @@ +# build xxx_default CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 b/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 index ad055155c9bf..badfbca2bde0 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_ESP32C3_REV_MIN_101=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m index 172f022b67ea..814241b72fcf 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m index 651a6cc578b7..db99cc188f5c 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m @@ -1,3 +1,5 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y CONFIG_ESP32C2_REV_MIN_200=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk b/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk index 4fee0b0352a3..240bb635e6a3 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk @@ -1 +1,3 @@ CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=n +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/pytest_wifi_station.py b/examples/wifi/getting_started/station/pytest_wifi_station.py index 5a93da1631cc..1a27b6ed6f5a 100644 --- a/examples/wifi/getting_started/station/pytest_wifi_station.py +++ b/examples/wifi/getting_started/station/pytest_wifi_station.py @@ -7,6 +7,7 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize + # diff of esp32s2/esp32s3 ~45K, others ~50K DIFF_THRESHOLD = { @@ -16,7 +17,7 @@ } -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count, config, skip_autoflash', [(2, 'default|enable_softap', 'y')], indirect=True) @idf_parametrize( 'target', diff --git a/examples/wifi/getting_started/station/sdkconfig.ci b/examples/wifi/getting_started/station/sdkconfig.ci index b416e9f87cbb..9633644b4669 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci +++ b/examples/wifi/getting_started/station/sdkconfig.ci @@ -1,2 +1,3 @@ +# build xxx_default CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 b/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 index ad055155c9bf..badfbca2bde0 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 +++ b/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_ESP32C3_REV_MIN_101=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap b/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap index cf2d4f2434e3..57c9b877408d 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap +++ b/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap @@ -1 +1,3 @@ CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m index 172f022b67ea..814241b72fcf 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m +++ b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m index 651a6cc578b7..db99cc188f5c 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m +++ b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m @@ -1,3 +1,5 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y CONFIG_ESP32C2_REV_MIN_200=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.ft b/examples/wifi/getting_started/station/sdkconfig.ci.ft index 10169bbff279..83cd86bfbeb2 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.ft +++ b/examples/wifi/getting_started/station/sdkconfig.ci.ft @@ -1 +1,3 @@ CONFIG_ESP_WIFI_11R_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.rrm b/examples/wifi/getting_started/station/sdkconfig.ci.rrm index 61c172f52369..a7a05f2a17cb 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.rrm +++ b/examples/wifi/getting_started/station/sdkconfig.ci.rrm @@ -1,2 +1,4 @@ CONFIG_ESP_WIFI_11KV_SUPPORT=y CONFIG_ESP_WIFI_RRM_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.wnm b/examples/wifi/getting_started/station/sdkconfig.ci.wnm index 9f87bf640e19..91c8f2d58762 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.wnm +++ b/examples/wifi/getting_started/station/sdkconfig.ci.wnm @@ -1,2 +1,4 @@ CONFIG_ESP_WIFI_11KV_SUPPORT=y CONFIG_ESP_WIFI_WNM_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk b/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk index bc969e6b4de1..af2ee3f36aaf 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk +++ b/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk @@ -1 +1,3 @@ CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index c6c042b40ee1..9e1d354dffc8 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -135,7 +135,7 @@ 'openthread_bbr': 'tests should be used for openthread border router linked to Internet.', 'openthread_sleep': 'tests should be used for openthread sleepy device.', 'zigbee_multi_dut': 'zigbee runner which have multiple duts.', - 'wifi_two_dut': 'tests should be run on runners which has two wifi duts connected.', + 'two_duts': 'tests should be run on runners which has two wifi duts connected.', 'generic_multi_device': 'generic multiple devices whose corresponding gpio pins are connected to each other.', 'twai_network': 'multiple runners form a TWAI network.', 'sdio_master_slave': 'Test sdio multi board, esp32+esp32', diff --git a/tools/ci/idf_pytest/plugin.py b/tools/ci/idf_pytest/plugin.py index 77a14526cc05..c74313ac8437 100644 --- a/tools/ci/idf_pytest/plugin.py +++ b/tools/ci/idf_pytest/plugin.py @@ -337,7 +337,7 @@ def pytest_runtest_makereport(self, item: Function, call: CallInfo[None]) -> Non res.extend( [ ChildCase( - format_case_id(target, config, case.name + f' {i}', is_qemu=is_qemu), + format_case_id(target, config, case.name, is_qemu=is_qemu), self.UNITY_RESULT_MAPPINGS[case.result], ) for case in _dut.testsuite.testcases diff --git a/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py b/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py index f2fc1e87b452..e559ff14e32c 100644 --- a/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py +++ b/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py @@ -144,7 +144,7 @@ def run_phy_tsens_test_with_light_sleep(dut: Tuple[Dut, Dut]) -> None: assert 0 < float(temp_val) < 70 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize('target', ['esp32c3', 'esp32c6', 'esp32c5', 'esp32s2', 'esp32s3', 'esp32c61'], indirect=['target']) def test_phy_tsens_coexist(dut: Tuple[Dut, Dut]) -> None: @@ -163,7 +163,7 @@ def test_phy_tsens_coexist(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -189,7 +189,7 @@ def test_phy_tsens_coexist_c2_xtal26m(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -216,7 +216,7 @@ def test_phy_tsens_coexist_c2eco4_xtal26m(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', diff --git a/tools/tools.json b/tools/tools.json index 5f82060b2447..1b58a6a41792 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -672,46 +672,46 @@ "versions": [ { "linux-amd64": { - "sha256": "766293bd7a08900d3536f87a0a7ade960f07266f16e4147f95ca5ce4e15d4c5d", - "size": 2489724, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-amd64-0.12.0-esp32-20250707.tar.gz" + "sha256": "5e6ff40aeca23bdd203cde04d60bc808c0e6bff110eadcbce3d602618c880531", + "size": 2547606, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-amd64-0.12.0-esp32-20251215.tar.gz" }, "linux-arm64": { - "sha256": "34b6883c372444b49950893b2fc0101aefd10d404a88ef72c97e80199f8544d3", - "size": 2371243, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-arm64-0.12.0-esp32-20250707.tar.gz" + "sha256": "29f98e2f90cd37924b714562b876a471d444a8f2aec428c6760e82bbf3b54cca", + "size": 2399117, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-arm64-0.12.0-esp32-20251215.tar.gz" }, "linux-armel": { - "sha256": "fd48492cf3ee16577c661fdccc14c349d34a9ab93aac5039ddf72332d4f4b70b", - "size": 2517680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-armel-0.12.0-esp32-20250707.tar.gz" + "sha256": "25de2b2dd0f5b437f5d5540c505eb9d0fbb971256ab13acd19642f8acdbd5cee", + "size": 2554256, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-armel-0.12.0-esp32-20251215.tar.gz" }, "linux-armhf": { - "sha256": "a468cc108578a1f4553ac0502c814d47791ef79f5997a31e941908fa5119de9c", - "size": 2353427, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-armhf-0.12.0-esp32-20250707.tar.gz" + "sha256": "2a2e6240a688ec91eee054140cc4967afceadeb8660f23f4b55a3936f65720a8", + "size": 2392746, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-armhf-0.12.0-esp32-20251215.tar.gz" }, "macos": { - "sha256": "6267be53892a76d535938a1b044b685adc7d292f090447e8a3e3d0f0996474d1", - "size": 2585348, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-macos-0.12.0-esp32-20250707.tar.gz" + "sha256": "956dd02ccf35116d565be2b148e041bd47c135e551a1f5097eae756d7d4dd079", + "size": 2710467, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-macos-0.12.0-esp32-20251215.tar.gz" }, "macos-arm64": { - "sha256": "150e938ac48a6ee031ddbc8b31043bc7f2073ab2ee4896b658918d35899673c3", - "size": 2628741, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-macos-arm64-0.12.0-esp32-20250707.tar.gz" + "sha256": "e6414c8db2ab09b687eaf765b1e69a92aecdcfe44e073d6f47ff829777e2e823", + "size": 2535504, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-macos-arm64-0.12.0-esp32-20251215.tar.gz" }, - "name": "v0.12.0-esp32-20250707", + "name": "v0.12.0-esp32-20251215", "status": "recommended", "win32": { - "sha256": "666274b04af7f36b430b6d063006051c37b8635b5175735ad5af07a1fbc6f486", - "size": 3034680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-win32-0.12.0-esp32-20250707.zip" + "sha256": "032a3791c256c974bceced073dc8cf0e18c07a75f39592110cbe71fc8de914b2", + "size": 3109352, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-win32-0.12.0-esp32-20251215.zip" }, "win64": { - "sha256": "5186ba3f7ee29fb6ab68a4ed7bb417211bad76ecdcdf9280a9187ebfd549a3c1", - "size": 3034680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-win64-0.12.0-esp32-20250707.zip" + "sha256": "d406be70d26098ced57eefcf636c4b4c184cd8c151204a459bb6ccbe4aa47eca", + "size": 3109355, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-win64-0.12.0-esp32-20251215.zip" } } ]