From 8b1c9bbb90047a682b11728888e49051841561e2 Mon Sep 17 00:00:00 2001 From: Linyan Liu Date: Wed, 27 Aug 2025 16:11:56 +0800 Subject: [PATCH] feat(ble_mesh): Miscellaneous update for BLE Mesh --- components/bt/CMakeLists.txt | 6 +- components/bt/esp_ble_mesh/core/access.c | 72 +- components/bt/esp_ble_mesh/core/adv.c | 8 +- components/bt/esp_ble_mesh/core/adv_common.c | 896 ++++++++++++++++++ components/bt/esp_ble_mesh/core/adv_common.h | 352 +++++++ components/bt/esp_ble_mesh/core/ble_adv.c | 331 +++++++ components/bt/esp_ble_mesh/core/ext_adv.c | 454 +++++++++ components/bt/esp_ble_mesh/core/ext_adv.h | 32 + .../esp_ble_mesh/core/include/mesh/adapter.h | 4 +- .../bt/esp_ble_mesh/core/proxy_server.c | 10 + components/bt/esp_ble_mesh/core/scan.c | 16 +- components/bt/esp_ble_mesh/core/transport.c | 83 +- .../bt/esp_ble_mesh/core/transport.enh.c | 70 +- .../models/client/client_common.c | 53 +- 14 files changed, 2188 insertions(+), 199 deletions(-) create mode 100644 components/bt/esp_ble_mesh/core/adv_common.c create mode 100644 components/bt/esp_ble_mesh/core/adv_common.h create mode 100644 components/bt/esp_ble_mesh/core/ble_adv.c create mode 100644 components/bt/esp_ble_mesh/core/ext_adv.c create mode 100644 components/bt/esp_ble_mesh/core/ext_adv.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 7448e2e3f9a..84f65b94fd5 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -616,19 +616,17 @@ if(CONFIG_BT_ENABLED) "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/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() endif() - - if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) list(APPEND srcs "porting/npl/freertos/src/npl_os_freertos.c" diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 3791add9e34..b476817502e 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.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 */ @@ -112,7 +112,7 @@ static int32_t next_period(struct bt_mesh_model *mod) if (!pub) { BT_ERR("Model has no publication support"); - return -ENOTSUP; + return 0; } period = bt_mesh_model_pub_period_get(mod); @@ -1366,3 +1366,71 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) return key; } + +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; + } + + 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; +} diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index 22323ca3404..79b9c0131cf 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -264,10 +264,16 @@ static inline TickType_t K_WAIT(int32_t val) static void adv_thread(void *p) { #if CONFIG_BLE_MESH_RELAY_ADV_BUF + QueueHandle_t relay_adv_handle = NULL; QueueSetMemberHandle_t handle = NULL; #endif - bt_mesh_msg_t msg = {0}; 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); diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c new file mode 100644 index 00000000000..ec1e3b68dbc --- /dev/null +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -0,0 +1,896 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "adv_common.h" +#include "net.h" +#include "ble_adv.h" + +NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BLE_MESH_ADV_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); + +static struct bt_mesh_adv adv_pool[CONFIG_BLE_MESH_ADV_BUF_COUNT]; + +static struct bt_mesh_adv_queue adv_queue; + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +NET_BUF_POOL_DEFINE(relay_adv_buf_pool, CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); + +static struct bt_mesh_adv relay_adv_pool[CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT]; +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 + +static bt_mesh_mutex_t adv_buf_alloc_lock; +#if CONFIG_BLE_MESH_EXT_ADV +NET_BUF_POOL_DEFINE(ext_adv_buf_pool, CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); +static bt_mesh_ext_adv_t ext_adv_pool[CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT]; +#if CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT +NET_BUF_POOL_DEFINE(ext_relay_adv_buf_pool, CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); +static bt_mesh_ext_adv_t ext_relay_adv_pool[CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT]; +#endif /* CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT */ +#if CONFIG_BLE_MESH_LONG_PACKET +NET_BUF_POOL_DEFINE(ext_long_adv_buf_pool, CONFIG_BLE_MESH_LONG_PACKET_TX_SEG_CNT, + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN, BLE_MESH_ADV_USER_DATA_SIZE, NULL); +static bt_mesh_ext_adv_t ext_long_adv_pool[CONFIG_BLE_MESH_LONG_PACKET_TX_SEG_CNT]; +#if CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT +NET_BUF_POOL_DEFINE(ext_long_relay_adv_buf_pool, CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT, + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN, BLE_MESH_ADV_USER_DATA_SIZE, NULL); +static bt_mesh_ext_adv_t ext_long_relay_adv_pool[CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT]; +#endif /* CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +static inline void init_adv_with_defaults(struct bt_mesh_adv *adv, + enum bt_mesh_adv_type type) +{ + memset(adv, 0, sizeof(struct bt_mesh_adv)); + adv->type = type; + adv->adv_itvl = BLE_MESH_ADV_ITVL_DEFAULT; + adv->adv_cnt = BLE_MESH_ADV_CNT_DEFAULT; + adv->channel_map = BLE_MESH_ADV_CHAN_DEFAULT; +} + +#if CONFIG_BLE_MESH_FRIEND +/* We reserve one extra buffer for each friendship, since we need to be able + * to resend the last sent PDU, which sits separately outside of the queue. + */ +#define FRIEND_BUF_COUNT ((CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE + 1) * \ + CONFIG_BLE_MESH_FRIEND_LPN_COUNT) + +NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, NULL); + +static bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; +#endif + +struct bt_mesh_adv_task { + TaskHandle_t handle; +#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ + (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ + CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) + StaticTask_t *task; + StackType_t *stack; +#endif +}; + +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_INST] = { + .id = CONFIG_BLE_MESH_ADV_INST_ID, +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + .busy = false, +#endif + }, +#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_INST] = { + .id = CONFIG_BLE_MESH_PROXY_ADV_INST_ID, + .busy = false, + }, +#endif +#if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE + [BLE_MESH_RELAY_ADV_INST] = { + .id = CONFIG_BLE_MESH_RELAY_ADV_INST_ID, + .busy = false, + }, +#endif +#if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE + [BLE_MESH_BLE_ADV_INST] = { + .id = CONFIG_BLE_MESH_BLE_ADV_INST_ID, + .busy = false, + }, +#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ +}; + +static struct bt_mesh_adv_inst *find_adv_inst_with_inst_id(uint8_t id) +{ + for (int i = 0; i < ARRAY_SIZE(adv_insts); i++) { + if (adv_insts[i].id == id) { + return &adv_insts[i]; + } + } + + return NULL; +} + +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) +{ + return (find_adv_inst_with_inst_id(adv_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_INST_TYPES_NUM) { + BT_ERR("Invalid instance type %d", inst_type); + return -EINVAL; + } + + if (inst_id == BLE_MESH_ADV_INS_UNUSED) { + BT_ERR("Invalid instance id %d", inst_id); + 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_INST_TYPES_NUM) { + BT_ERR("Invalid instance type %d", inst_type); + return -EINVAL; + } + + bt_le_ext_adv_stop(adv_insts[inst_type].id); + + adv_insts[inst_type].id = BLE_MESH_ADV_INS_UNUSED; +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + adv_insts[inst_type].spt_mask = 0; +#endif + return 0; +} + +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + +static struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) +{ + init_adv_with_defaults(&adv_pool[id], type); + return &adv_pool[id]; +} + +#if CONFIG_BLE_MESH_EXT_ADV +struct bt_mesh_adv *ext_adv_alloc(int id, enum bt_mesh_adv_type type) +{ + init_adv_with_defaults(&ext_adv_pool[id].adv, type); + ext_adv_pool[id].primary_phy = BLE_MESH_ADV_PRI_PHY_DEFAULT; + ext_adv_pool[id].secondary_phy = BLE_MESH_ADV_SEC_PHY_DEFAULT; + ext_adv_pool[id].include_tx_power = BLE_MESH_TX_POWER_INCLUDE_DEFAULT; + ext_adv_pool[id].tx_power = BLE_MESH_TX_POWER_DEFAULT; + return &ext_adv_pool[id].adv; +} +#if CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT +struct bt_mesh_adv *ext_relay_adv_alloc(int id, enum bt_mesh_adv_type type) +{ + init_adv_with_defaults(&ext_relay_adv_pool[id].adv, type); + ext_relay_adv_pool[id].primary_phy = BLE_MESH_ADV_PRI_PHY_DEFAULT; + ext_relay_adv_pool[id].secondary_phy = BLE_MESH_ADV_SEC_PHY_DEFAULT; + ext_relay_adv_pool[id].include_tx_power = BLE_MESH_TX_POWER_INCLUDE_DEFAULT; + ext_relay_adv_pool[id].tx_power = BLE_MESH_TX_POWER_DEFAULT; + return &ext_relay_adv_pool[id].adv; +} +#endif /* CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET +struct bt_mesh_adv *ext_long_adv_alloc(int id, enum bt_mesh_adv_type type) +{ + init_adv_with_defaults(&ext_long_adv_pool[id].adv, type); + ext_long_adv_pool[id].primary_phy = BLE_MESH_ADV_PRI_PHY_DEFAULT; + ext_long_adv_pool[id].secondary_phy = BLE_MESH_ADV_SEC_PHY_DEFAULT; + ext_long_adv_pool[id].include_tx_power = BLE_MESH_TX_POWER_INCLUDE_DEFAULT; + ext_long_adv_pool[id].tx_power = BLE_MESH_TX_POWER_DEFAULT; + return &ext_long_adv_pool[id].adv; +} +#if CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT +struct bt_mesh_adv *ext_long_relay_adv_alloc(int id, enum bt_mesh_adv_type type) +{ + init_adv_with_defaults(&ext_long_relay_adv_pool[id].adv, type); + ext_long_relay_adv_pool[id].primary_phy = BLE_MESH_ADV_PRI_PHY_DEFAULT; + ext_long_relay_adv_pool[id].secondary_phy = BLE_MESH_ADV_SEC_PHY_DEFAULT; + ext_long_relay_adv_pool[id].include_tx_power = BLE_MESH_TX_POWER_INCLUDE_DEFAULT; + ext_long_relay_adv_pool[id].tx_power = BLE_MESH_TX_POWER_DEFAULT; + return &ext_long_relay_adv_pool[id].adv; +} +#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) +{ + return &adv_types[adv_type]; +} + +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) +{ + if (buf == NULL || func == NULL || flag >= BLE_MESH_BUF_REF_MAX) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (flag) { + case BLE_MESH_BUF_REF_EQUAL: + if (buf->ref != ref_cmp) { + BT_ERR("Unexpected ref %d in %s, expect to equal to %d", buf->ref, func, ref_cmp); + } + break; + case BLE_MESH_BUF_REF_SMALL: + if (buf->ref >= ref_cmp) { + BT_ERR("Unexpected ref %d in %s, expect to smaller than %d", buf->ref, func, ref_cmp); + } + break; + default: + break; + } +} + +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV +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_INST_TYPES_NUM) { + BT_ERR("Invalid instance type %d", inst_type); + return; + } + + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("Invalid adv type %d", adv_type); + return; + } + + adv_insts[inst_type].spt_mask |= BIT(adv_type); +} + +void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) +{ + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid instance type %d", inst_type); + return; + } + + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("Invalid adv type %d", adv_type); + return; + } + + 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) +{ + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { + BT_ERR("Invalid instance type %d", inst_type); + return; + } + + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("Invalid adv type %d", adv_type); + return; + } + + adv_insts[inst_type].spt_mask = 0; +} +#endif + +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) +{ + if (!adv_queue || !queue_size || !cb) { + BT_ERR("Invalid param %s", __func__); + return -EINVAL; + } + + bt_mesh_queue_init(&adv_queue->q, queue_size, sizeof(bt_mesh_msg_t)); + + adv_queue->send = cb; + + return 0; +} + +int bt_mesh_adv_queue_deinit(struct bt_mesh_adv_queue *adv_queue) +{ + if (!adv_queue) { + BT_ERR("Invalid param %s", __func__); + return -EINVAL; + } + + bt_mesh_queue_deinit(&adv_queue->q); + + adv_queue->send = NULL; + + return 0; +} + +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) +{ + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("%s Invalid adv type %d",__func__, adv_type); + return; + } + + if (!adv_queue || !buf_pool || !adv_alloc) { + BT_ERR("Invalid parameters %s", __func__); + return; + } + + adv_types[adv_type].adv_q = adv_queue; + adv_types[adv_type].pool = buf_pool; + adv_types[adv_type].pool_allocator = adv_alloc; +} + +void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) +{ + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("%s Invalid adv type %d",__func__, adv_type); + return; + } + + adv_types[adv_type].adv_q = NULL; + adv_types[adv_type].pool = NULL; + adv_types[adv_type].pool_allocator = NULL; +} + +#if CONFIG_BLE_MESH_USE_BLE_50 +int bt_mesh_adv_task_wakeup(uint32_t evt) +{ + xTaskNotify(adv_task.handle, evt, eSetBits); + return 0; +} + +bool bt_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) +{ + return (xTaskNotifyWait(wait_bits, UINT32_MAX, notify, K_WAIT(timeout)) == pdTRUE); +} +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ +bool bt_mesh_adv_task_wait(uint32_t timeout) +{ + vTaskDelay(K_WAIT(timeout)); + return true; +} +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + +uint16_t bt_mesh_pdu_duration(uint8_t xmit) +{ + uint16_t duration = 0U; + uint16_t adv_int = 0U; + + adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_TRANSMIT_INT(xmit)); + duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + + return duration; +} + +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; + + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { + BT_WARN("Refusing to allocate buffer while suspended"); + return NULL; + } + + 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(adv_types[type].pool, timeout); + if (!buf) { + 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", + adv_types[type].pool, adv_types[type].pool->buf_count, + adv_types[type].pool->uninit_count, 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) +{ + if (pool == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + for (int i = 0; i < pool->buf_count; i++) { + struct net_buf *buf = &pool->__bufs[i]; + if (buf->ref > 1U) { + buf->ref = 1U; + } + net_buf_unref(buf); + } +} + +void bt_mesh_unref_buf(bt_mesh_msg_t *msg) +{ + struct net_buf *buf = msg->arg; + + if (buf) { + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); + if (buf->ref > 1U) { + buf->ref = 1U; + } + net_buf_unref(buf); + } +} + +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) +{ + bt_mesh_msg_t msg = { + .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)); + + 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); + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_RELAY_DATA) { + msg.relay = true; + msg.src = src; + msg.dst = dst; + msg.timestamp = k_uptime_get_32(); + } +#endif + + 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 + bt_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); +#endif +} + +struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void) +{ + return &adv_queue; +} + +void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) +{ + if (adv_queue.q.handle == NULL) { + BT_ERR("Invalid adv queue"); + return; + } + + if (front) { + if (xQueueSendToFront(adv_queue.q.handle, msg, timeout) != pdTRUE) { + BT_ERR("Failed to send item to adv queue front"); + bt_mesh_unref_buf(msg); + } + } else { + if (xQueueSend(adv_queue.q.handle, msg, timeout) != pdTRUE) { + BT_ERR("Failed to send item to adv queue back"); + bt_mesh_unref_buf(msg); + } + } +} + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +bool bt_mesh_ignore_relay_packet(uint32_t timestamp) +{ + uint32_t now = k_uptime_get_32(); + uint32_t interval = 0U; + + if (now >= timestamp) { + interval = now - timestamp; + } else { + interval = BLE_MESH_MAX_TIME_INTERVAL - (timestamp - now) + 1; + } + + 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) +{ + 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]; +} + +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); + + if (relay_adv_queue.q.handle == NULL) { + BT_ERR("Invalid relay queue"); + return; + } + + if (xQueueSend(relay_adv_queue.q.handle, msg, timeout) == pdTRUE) { + return; + } + + /* If failed to send packet to the relay queue(queue is full), we will + * remove the oldest packet in the queue and put the new one into it. + */ + 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"); + bt_mesh_unref_buf(msg); + return; + } + } else { + BT_WARN("Empty queue, but failed to send the relay packet"); + bt_mesh_unref_buf(msg); + } +} + +uint16_t bt_mesh_get_stored_relay_count(void) +{ + return (uint16_t)uxQueueMessagesWaiting(relay_adv_queue.q.handle); +} + +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) +{ + 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 + bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_RELAY_DATA, &relay_adv_queue, + &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 && 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_INST, + CONFIG_BLE_MESH_RELAY_ADV_INST_ID); + 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_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); +#if CONFIG_BLE_MESH_LONG_PACKET + 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 /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + 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_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); +#if CONFIG_BLE_MESH_LONG_PACKET + 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_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 /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_USE_BLE_50 +#if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE + bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); +#if CONFIG_BLE_MESH_EXT_ADV + bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); +#if CONFIG_BLE_MESH_LONG_PACKET + bt_mesh_adv_inst_type_rm(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_INST); +#else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); +#if CONFIG_BLE_MESH_EXT_ADV + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); +#if CONFIG_BLE_MESH_LONG_PACKET + bt_mesh_adv_inst_type_rm(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)); +} +#endif /* CONFIG_BLE_MESH_DEINIT */ +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + +#if CONFIG_BLE_MESH_FRIEND +static 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; +} + +void bt_mesh_frnd_adv_init(void) +{ + 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_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_mesh_adv_type_deinit(BLE_MESH_ADV_FRIEND); + +#if CONFIG_BLE_MESH_FRIEND && CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); +#endif /* CONFIG_BLE_MESH_FRIEND */ + + bt_mesh_unref_buf_from_pool(&friend_buf_pool); + memset(frnd_adv_pool, 0, sizeof(frnd_adv_pool)); +} +#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)) +{ + if (!adv_thread) { + BT_ERR("Invalid param %s", __func__); + return; + } + +#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ + (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); + + 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); +#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_mesh_r_mutex_create(&adv_buf_alloc_lock); + 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 + +#if CONFIG_BLE_MESH_USE_BLE_50 + 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); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT + bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_RELAY_DATA, &adv_queue, &ext_relay_adv_buf_pool, ext_relay_adv_alloc); +#endif +#if CONFIG_BLE_MESH_LONG_PACKET + bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_LONG_PROV, &adv_queue, &ext_long_adv_buf_pool, ext_long_adv_alloc); + bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_LONG_DATA, &adv_queue, &ext_long_adv_buf_pool, ext_long_adv_alloc); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT + bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, &adv_queue, &ext_long_relay_adv_buf_pool, ext_long_relay_adv_alloc); +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +#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, + * 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_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_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_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); +#endif +#if CONFIG_BLE_MESH_LONG_PACKET + 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_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 */ +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ +} + +#if CONFIG_BLE_MESH_DEINIT +void bt_mesh_adv_task_deinit(void) +{ + vTaskDelete(adv_task.handle); + adv_task.handle = NULL; + +#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ + (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ + CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) + heap_caps_free(adv_task.stack); + adv_task.stack = NULL; + heap_caps_free(adv_task.task); + adv_task.task = NULL; +#endif +} + +void bt_mesh_adv_common_deinit(void) +{ + 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); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_URI); + +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + bt_mesh_adv_type_deinit(BLE_MESH_ADV_PROXY_SOLIC); +#endif + +#if CONFIG_BLE_MESH_EXT_ADV + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_PROV); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_DATA); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_RELAY_DATA); +#endif +#if CONFIG_BLE_MESH_LONG_PACKET + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_LONG_PROV); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_LONG_DATA); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF + bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_LONG_RELAY_DATA); +#endif +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#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_INST); +#endif + + 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 new file mode 100644 index 00000000000..d5172a676af --- /dev/null +++ b/components/bt/esp_ble_mesh/core/adv_common.h @@ -0,0 +1,352 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2024-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ADV_COMMON_H_ +#define _ADV_COMMON_H_ + +#include "mesh/common.h" +#include "mesh/atomic.h" +#include "mesh/access.h" +#include "mesh/adapter.h" +#include "mesh/queue.h" +#include "mesh/timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Pre-5.0 controllers enforce a minimum interval of 100ms + * whereas 5.0+ controllers can go down to 20ms. + */ +#if CONFIG_BLE_MESH_HCI_5_0 +#define ADV_ITVL_MIN 20 +#else +#define ADV_ITVL_MIN 100 +#endif + +/* Convert from ms to 0.625ms units */ +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +/* Convert from 0.625ms units to interval(ms) */ +#define ADV_SCAN_INT(val) ((val) * 5 / 8) + +/* Maximum advertising data payload for a single data type */ +#define BLE_MESH_ADV_DATA_SIZE 29 + +/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ +#define BLE_MESH_ADV_USER_DATA_SIZE 4 + +#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +#define BLE_MESH_ADV_BUSY(buf) (BLE_MESH_ADV(buf)->busy) + +#define BLE_MESH_MSG_NET_BUF(msg) ((struct net_buf *)(msg->arg)) + +#define BLE_MESH_ADV_INST_UNUSED 0xFF + +struct bt_mesh_adv { + const struct bt_mesh_send_cb *cb; + void *cb_data; + + uint8_t type; + + bt_mesh_atomic_t busy; + + uint8_t xmit; + + uint32_t adv_itvl; + uint8_t adv_cnt; + uint8_t channel_map; +}; + +#if CONFIG_BLE_MESH_USE_BLE_50 +#define EXT_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), bt_mesh_ext_adv_t, adv) +typedef struct { + struct bt_mesh_adv adv; + uint8_t primary_phy; + uint8_t secondary_phy; + uint8_t include_tx_power:1; + int8_t tx_power; +} bt_mesh_ext_adv_t; +#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 + +enum { +#if CONFIG_BLE_MESH_USE_BLE_50 + ADV_TASK_MESH_ADV_INST_EVT = BIT(CONFIG_BLE_MESH_ADV_INST_ID), + +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV +#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER + ADV_TASK_PROX_ADV_INST_EVT = BIT(CONFIG_BLE_MESH_PROXY_ADV_INST_ID), +#endif + +#if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE + ADV_TASK_RELAY_ADV_INST_EVT = BIT(CONFIG_BLE_MESH_RELAY_ADV_INST_ID), +#endif + +#if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE + 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, +}; + +uint16_t bt_mesh_pdu_duration(uint8_t xmit); + +typedef struct bt_mesh_msg { + bool relay; /* Flag indicates if the packet is a relayed one */ + void *arg; /* Pointer to the struct net_buf */ + uint16_t src; /* Source address for relay packets */ + uint16_t dst; /* Destination address for relay packets */ + uint32_t timestamp; /* Timestamp recorded when the relay packet is posted to queue */ +} bt_mesh_msg_t; + +struct bt_mesh_adv_inst { + uint8_t id; +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + bool busy; + struct net_buf *sending_buf; + + /* Indicate which adv_type is supported by this instance */ + uint32_t spt_mask; +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ +}; + +enum bt_mesh_adv_type { + BLE_MESH_ADV_PROV, + BLE_MESH_ADV_DATA, +#if CONFIG_BLE_MESH_EXT_ADV + BLE_MESH_ADV_EXT_PROV, + BLE_MESH_ADV_EXT_DATA, + BLE_MESH_ADV_EXT_RELAY_DATA, +#if CONFIG_BLE_MESH_LONG_PACKET + BLE_MESH_ADV_EXT_LONG_PROV, + BLE_MESH_ADV_EXT_LONG_DATA, + BLE_MESH_ADV_EXT_LONG_RELAY_DATA, +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +#if CONFIG_BLE_MESH_FRIEND + BLE_MESH_ADV_FRIEND, +#endif +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + BLE_MESH_ADV_RELAY_DATA, +#endif + BLE_MESH_ADV_BEACON, + BLE_MESH_ADV_URI, +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + BLE_MESH_ADV_PROXY_SOLIC, +#endif +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + BLE_MESH_ADV_BLE, +#endif + BLE_MESH_ADV_TYPES_NUM, +}; + +typedef enum { + BLE_MESH_BUF_REF_EQUAL, + BLE_MESH_BUF_REF_SMALL, + BLE_MESH_BUF_REF_MAX, +} bt_mesh_buf_ref_flag_t; + + +static const uint8_t adv_type[] = { + [BLE_MESH_ADV_PROV] = BLE_MESH_DATA_MESH_PROV, + [BLE_MESH_ADV_DATA] = BLE_MESH_DATA_MESH_MESSAGE, +#if CONFIG_BLE_MESH_EXT_ADV + [BLE_MESH_ADV_EXT_PROV] = BLE_MESH_DATA_MESH_PROV, + [BLE_MESH_ADV_EXT_RELAY_DATA] = BLE_MESH_DATA_MESH_MESSAGE, + [BLE_MESH_ADV_EXT_DATA] = BLE_MESH_DATA_MESH_MESSAGE, +#if CONFIG_BLE_MESH_LONG_PACKET + [BLE_MESH_ADV_EXT_LONG_PROV] = BLE_MESH_DATA_MESH_PROV, + [BLE_MESH_ADV_EXT_LONG_RELAY_DATA] = BLE_MESH_DATA_MESH_MESSAGE, + [BLE_MESH_ADV_EXT_LONG_DATA] = BLE_MESH_DATA_MESH_MESSAGE, +#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, +#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, +}; + +typedef struct bt_mesh_adv *(*bt_mesh_pool_allocator_t)(int id, enum bt_mesh_adv_type type); +typedef void (*bt_mesh_adv_queue_send_cb_t)(bt_mesh_msg_t *msg, uint32_t timeout, bool front); + +struct bt_mesh_adv_type_manager { + struct bt_mesh_adv_queue *adv_q; + struct net_buf_pool *pool; + bt_mesh_pool_allocator_t pool_allocator; +}; + +struct bt_mesh_adv_queue { + bt_mesh_queue_t q; + bt_mesh_adv_queue_send_cb_t send; +}; + +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); + +static inline struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int32_t timeout) +{ + return bt_mesh_adv_create_from_pool(type, timeout); +} + +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_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, + uint16_t queue_size, + bt_mesh_adv_queue_send_cb_t cb); + +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); + +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); +bool bt_mesh_is_adv_inst_used(uint8_t adv_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_type_add(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); + +void bt_mesh_adv_inst_type_rm(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 + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +void bt_mesh_relay_adv_init(void); +bool bt_mesh_ignore_relay_packet(uint32_t timestamp); + +static inline void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, + uint16_t src, uint16_t dst, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + bt_mesh_generic_adv_send(buf, xmit, cb, cb_data, src, dst, false); +}; + +uint16_t bt_mesh_get_stored_relay_count(void); + +#if CONFIG_BLE_MESH_DEINIT +void bt_mesh_relay_adv_deinit(void); +#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + +#if CONFIG_BLE_MESH_FRIEND +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 */ + +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 +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 +bool bt_mesh_adv_task_wait(uint32_t timeout); +#endif + +#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); + +int bt_mesh_stop_ble_advertising(uint8_t index); +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ADV_COMMON_H_ */ diff --git a/components/bt/esp_ble_mesh/core/ble_adv.c b/components/bt/esp_ble_mesh/core/ble_adv.c new file mode 100644 index 00000000000..e27109c0471 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/ble_adv.c @@ -0,0 +1,331 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "ble_adv.h" +#include "mesh/common.h" +#include "mesh/buf.h" + +#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; + +/* 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); + +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 + +static struct bt_mesh_adv *ble_adv_alloc(int id, enum bt_mesh_adv_type type) +{ + memset(&ble_adv_pool[id], 0, sizeof(struct bt_mesh_adv)); + ble_adv_pool[id].type = type; + return &ble_adv_pool[id]; +} + +#if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE +/* 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__); + + if (p_ble_adv_queue->q.handle == NULL) { + BT_ERR("Invalid adv queue"); + return; + } + + if (front) { + if (xQueueSendToFront(p_ble_adv_queue->q.handle, msg, timeout) != pdTRUE) { + BT_ERR("Failed to send item to adv queue front"); + bt_mesh_unref_buf(msg); + } + } else { + if (xQueueSend(p_ble_adv_queue->q.handle, msg, timeout) != pdTRUE) { + BT_ERR("Failed to send item to adv queue back"); + bt_mesh_unref_buf(msg); + } + } +} +#endif + +static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) +{ + if (tx->buf == NULL) { + return; + } + + if (bt_mesh_atomic_test_bit(tx->flags, TIMER_INIT)) { + k_delayed_work_free(&tx->resend); + } + bt_mesh_atomic_set(tx->flags, 0); + memset(&tx->param, 0, sizeof(tx->param)); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0); + if (unref) { + net_buf_unref(tx->buf); + } + tx->buf = NULL; +} + +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); + + /* If failed to send BLE adv packet, and param->count is not 0 + * which means the timer has been initialized, here we need to + * free the timer. + */ + if (err) { + ble_adv_tx_reset(tx, true); + } +} + +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); + + if (err) { + ble_adv_tx_reset(tx, true); + return; + } + + if (tx->param.count) { + if (tx->param.period) { + k_delayed_work_submit(&tx->resend, tx->param.period); + } else { + k_work_submit(&tx->resend.work); + } + } else { + ble_adv_tx_reset(tx, true); + } +} + +static struct bt_mesh_send_cb ble_adv_send_cb = { + .start = ble_adv_send_start, + .end = ble_adv_send_end, +}; + +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; + + if (tx->buf == NULL) { + /* The advertising has been cancelled */ + return; + } + + 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) { + /* Send the BLE advertising packet infinitely */ + return; + } + + if (tx->param.count > 0U) { + tx->param.count--; + } +} + +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) +{ + struct bt_mesh_ble_adv_tx *tx = NULL; + struct net_buf *buf = NULL; + bool front = false; + + if (param == NULL || index == NULL) { + BT_ERR("%s, Invalid parameter", __func__); + return -EINVAL; + } + + if (param->adv_type != BLE_MESH_ADV_DIRECT_IND && + (param->interval < 0x20 || param->interval > 0x4000)) { + BT_ERR("Invalid adv interval 0x%04x", param->interval); + return -EINVAL; + } + + if (param->adv_type > BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) { + BT_ERR("Invalid adv type 0x%02x", param->adv_type); + return -EINVAL; + } + + if (param->own_addr_type > BLE_MESH_ADDR_RANDOM_ID) { + BT_ERR("Invalid own addr type 0x%02x", param->own_addr_type); + return -EINVAL; + } + + if ((param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || + param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || + param->adv_type == BLE_MESH_ADV_DIRECT_IND || + param->adv_type == BLE_MESH_ADV_DIRECT_IND_LOW_DUTY) && + param->peer_addr_type > BLE_MESH_ADDR_RANDOM) { + BT_ERR("Invalid peer addr type 0x%02x", param->peer_addr_type); + return -EINVAL; + } + + if (data && (data->adv_data_len > 31 || data->scan_rsp_data_len > 31)) { + BT_ERR("Invalid adv data length (adv %d, scan rsp %d)", + data->adv_data_len, data->scan_rsp_data_len); + return -EINVAL; + } + + if (param->priority > BLE_MESH_BLE_ADV_PRIO_HIGH) { + BT_ERR("Invalid adv priority %d", param->priority); + return -EINVAL; + } + + if (param->duration < ADV_SCAN_INT(param->interval)) { + BT_ERR("Too small duration %dms", param->duration); + return -EINVAL; + } + + buf = bt_mesh_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); + if (!buf) { + BT_ERR("No empty ble adv buffer"); + return -ENOBUFS; + } + + /* Set advertising data and scan response data */ + memset(buf->data, 0, buf->size); + if (data) { + net_buf_add_u8(buf, data->adv_data_len); + if (data->adv_data_len) { + net_buf_add_mem(buf, data->adv_data, data->adv_data_len); + } + net_buf_add_u8(buf, data->scan_rsp_data_len); + if (data->scan_rsp_data_len) { + net_buf_add_mem(buf, data->scan_rsp_data, data->scan_rsp_data_len); + } + } + + *index = net_buf_id(buf); + tx = &ble_adv_tx[*index]; + tx->buf = buf; + memcpy(&tx->param, param, sizeof(tx->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 + * sent only once. Just give a warning here, and since the + * 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 */ + net_buf_unref(buf); + } + + return 0; +} + +int bt_mesh_stop_ble_advertising(uint8_t index) +{ + struct bt_mesh_ble_adv_tx *tx = NULL; + bool unref = true; + + if (index >= ARRAY_SIZE(ble_adv_tx)) { + BT_ERR("Invalid adv index %d", index); + return -EINVAL; + } + + tx = &ble_adv_tx[index]; + + if (tx->buf == NULL) { + BT_WARN("Already stopped, index %d", index); + return 0; + } + + /* busy 1, ref 1; busy 1, ref 2; + * busy 0, ref 0; busy 0, ref 1; + */ + + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)) && + tx->buf->ref == 1U) { + unref = false; + } + ble_adv_tx_reset(tx, unref); + + return 0; +} + +struct bt_mesh_adv_queue *bt_mesh_ble_adv_queue_get(void) +{ +#if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE + bt_mesh_adv_queue_init(&ble_adv_queue, CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT, bt_mesh_ble_task_post); + return &ble_adv_queue; +#else + return bt_mesh_adv_queue_get(); +#endif +} + +void bt_mesh_ble_adv_init(void) +{ + 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_INST, CONFIG_BLE_MESH_BLE_ADV_INST_ID); + bt_mesh_adv_inst_type_add(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); +#else +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); +#endif +#endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ +} + +#if CONFIG_BLE_MESH_DEINIT +void bt_mesh_ble_adv_deinit(void) +{ + for (int i = 0; i < ARRAY_SIZE(ble_adv_tx); i++) { + 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)); + +#if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE + /* In other cases, ble_adv queue is an adv queue, + * so ble does not need to deinit separately */ + 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_INST); + bt_mesh_adv_inst_type_rm(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); +#else +#if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV + bt_mesh_adv_inst_type_rm(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 */ diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c new file mode 100644 index 00000000000..4958e5686db --- /dev/null +++ b/components/bt/esp_ble_mesh/core/ext_adv.c @@ -0,0 +1,454 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "mesh/kernel.h" +#include "mesh.h" +#include "mesh/hci.h" +#include "mesh/common.h" +#include "mesh/ffs.h" +#include "ext_adv.h" +#include "beacon.h" +#include "prov_common.h" +#include "foundation.h" +#include "proxy_server.h" +#include "proxy_client.h" +#include "prov_pvnr.h" +#include "mesh/adapter.h" + +#include "adv_common.h" +#include "ble_adv.h" + +static struct bt_mesh_adv_inst *adv_insts; + +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; + void *cb_data = BLE_MESH_ADV(buf)->cb_data; + struct bt_mesh_adv_param param = {0}; + uint16_t duration = 0U, adv_int = 0U; + uint8_t adv_cnt = 0; + struct bt_mesh_adv_data ad = {0}; + int err = 0; +#if CONFIG_BLE_MESH_EXT_ADV + 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)); + + switch (BLE_MESH_ADV(buf)->type) { +#if CONFIG_BLE_MESH_EXT_ADV + case BLE_MESH_ADV_EXT_PROV: + case BLE_MESH_ADV_EXT_DATA: + case BLE_MESH_ADV_EXT_RELAY_DATA: +#if CONFIG_BLE_MESH_LONG_PACKET + case BLE_MESH_ADV_EXT_LONG_PROV: + case BLE_MESH_ADV_EXT_LONG_DATA: + case BLE_MESH_ADV_EXT_LONG_RELAY_DATA: +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + { + is_ext_adv = true; + } +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + case BLE_MESH_ADV_PROV: + case BLE_MESH_ADV_DATA: +#if CONFIG_BLE_MESH_FRIEND + case BLE_MESH_ADV_FRIEND: +#endif +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + case BLE_MESH_ADV_RELAY_DATA: +#endif +#if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX + case BLE_MESH_ADV_PROXY_SOLIC: +#endif + case BLE_MESH_ADV_BEACON: + case BLE_MESH_ADV_URI: { +#if CONFIG_BLE_MESH_EXT_ADV + if (is_ext_adv) { + param.primary_phy = EXT_ADV(buf)->primary_phy; + param.secondary_phy = EXT_ADV(buf)->secondary_phy; + param.include_tx_power = EXT_ADV(buf)->include_tx_power; + param.tx_power = EXT_ADV(buf)->tx_power; + } else +#endif + { + param.primary_phy = BLE_MESH_ADV_PRI_PHY_DEFAULT; + param.secondary_phy = BLE_MESH_ADV_SEC_PHY_DEFAULT; + param.include_tx_power = BLE_MESH_TX_POWER_INCLUDE_DEFAULT; + param.tx_power = BLE_MESH_TX_POWER_DEFAULT; + } + + if (BLE_MESH_ADV(buf)->adv_itvl != BLE_MESH_ADV_ITVL_DEFAULT) { + adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_ADV(buf)->adv_itvl); + } else { + adv_int = MAX(ADV_ITVL_MIN, + BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); + } + + if (BLE_MESH_ADV(buf)->adv_cnt != BLE_MESH_ADV_CNT_DEFAULT) { + adv_cnt = BLE_MESH_ADV(buf)->adv_cnt; + } else { + adv_cnt = BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1; + } + + duration = adv_cnt * (adv_int + 10); + + BT_DBG("count %u interval %ums duration %ums", + adv_cnt, adv_int, duration); + + ad.type = adv_type[BLE_MESH_ADV(buf)->type]; + ad.data_len = buf->len; + ad.data = buf->data; + + param.options = 0U; + param.interval_min = ADV_SCAN_UNIT(adv_int); + param.interval_max = param.interval_min; + + param.adv_duration = duration; + param.adv_count = adv_cnt; + + if (BLE_MESH_ADV(buf)->channel_map) { + param.channel_map = BLE_MESH_ADV(buf)->channel_map; + } else { + param.channel_map = BLE_MESH_ADV_CHAN_DEFAULT; + } + +#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); + } else +#endif + { + 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; +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + case BLE_MESH_ADV_BLE: + struct bt_mesh_ble_adv_data data = {0}; + struct bt_mesh_ble_adv_tx *tx = cb_data; + + if (tx == NULL) { + BT_ERR("Invalid adv user data"); + net_buf_unref(buf); + return -EINVAL; + } + + 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); + + data.adv_data_len = tx->buf->data[0]; + if (data.adv_data_len) { + memcpy(data.adv_data, tx->buf->data + 1, data.adv_data_len); + } + data.scan_rsp_data_len = tx->buf->data[data.adv_data_len + 1]; + if (data.scan_rsp_data_len) { + memcpy(data.scan_rsp_data, tx->buf->data + data.adv_data_len + 2, data.scan_rsp_data_len); + } + duration = tx->param.duration; + + bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + + err = bt_mesh_ble_ext_adv_start(inst->id, &tx->param, &data); + break; +#endif + default: + BT_ERR("Error Type"); + break; + } + + adv_send_start(duration, err, cb, cb_data); + if (err) { + BT_ERR("Start advertising failed: err %d", err); + return err; + } + + *adv_duration = duration; + BT_DBG("Advertising started. %u ms", duration); + return 0; +} + +static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) +{ + 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. + */ + assert(msg->arg); + + /* 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. + */ + 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. + */ + 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 (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 + break; + } + + if (msg->arg == NULL) { + return -EINVAL; + } + + return 0; +} + +static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_duration) +{ + uint16_t cur_min_duration = K_FOREVER; + enum bt_mesh_adv_type adv_type = 0; + 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; + +#if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_SERVER + 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_INST].busy = true; + evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INST].id); + } +#endif + + 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) +#endif + ) { + continue; + } + + spt_mask = instance->spt_mask; + adv_type = 0; + + while(spt_mask) { + adv_type = find_lsb_set(spt_mask) - 1; + spt_mask &= ~BIT(adv_type); + msg_queue = &(bt_mesh_adv_types_mgmt_get(adv_type)->adv_q->q); + + /* 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); + 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. + */ + net_buf_unref(instance->sending_buf); + instance->sending_buf = NULL; + break; + } + + if (duration < cur_min_duration) { + cur_min_duration = duration; + } + + 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. + */ + msg.arg = NULL; + break; + } + } + + *min_duration = cur_min_duration; + *update_evts |= evts; + + return 0; +} + +static uint32_t received_adv_evts_handle(uint32_t recv_evts) +{ + if (!recv_evts) { + return 0; + } + + 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_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); + 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; + } + } + + return recv_evts; +} + +static void adv_thread(void *p) +{ + uint16_t adv_duration = K_FOREVER; + uint32_t recv_evts = 0; + uint32_t wait_evts = 0; + + BT_DBG("%s, starts", __func__); + + while (1) { + adv_duration = K_FOREVER; + wait_evts |= ADV_TASK_PKT_SEND_EVT; + + activate_idle_adv_instance(&wait_evts, &adv_duration); + + bt_mesh_adv_task_wait(wait_evts, adv_duration, &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_INST].busy = false; + recv_evts &= ~ADV_TASK_PROXY_ADV_UPD_EVT; + } +#endif + + /* 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; + } + + if (recv_evts & ADV_TASK_PKT_SEND_EVT) { + recv_evts &= ~ADV_TASK_PKT_SEND_EVT; + } + + recv_evts = received_adv_evts_handle(recv_evts); + + if (recv_evts) { + BT_ERR("Remain evts %08x to handle", recv_evts); + } + } +} + +void bt_mesh_adv_update(void) +{ +#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_INST].busy) { + bt_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); + } +#endif +} + +void bt_mesh_adv_init(void) +{ + bt_mesh_adv_common_init(); + + adv_insts = bt_mesh_get_adv_insts_set(); + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + bt_mesh_relay_adv_init(); +#endif + +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + bt_mesh_ble_adv_init(); +#endif + + bt_mesh_adv_task_init(adv_thread); +} + +#if CONFIG_BLE_MESH_DEINIT +void bt_mesh_adv_deinit(void) +{ + bt_mesh_adv_task_deinit(); + + bt_mesh_adv_common_deinit(); + + adv_insts = NULL; + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + bt_mesh_relay_adv_deinit(); +#endif + +#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV + bt_mesh_ble_adv_deinit(); +#endif +} +#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 new file mode 100644 index 00000000000..3d4820a8d62 --- /dev/null +++ b/components/bt/esp_ble_mesh/core/ext_adv.h @@ -0,0 +1,32 @@ +/* Bluetooth Mesh */ + +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileContributor: 2024-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _EXT_ADV_H_ +#define _EXT_ADV_H_ + +#include "mesh/atomic.h" +#include "mesh/access.h" +#include "mesh/adapter.h" +#include "mesh/queue.h" +#include "adv_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void bt_mesh_adv_update(void); + +void bt_mesh_adv_init(void); +void bt_mesh_adv_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXT_ADV_H_ */ 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 1cb239a3cac..5a1e4326a92 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-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 */ @@ -553,7 +553,7 @@ struct bt_mesh_gatt_attr { * @param len Length of data to read * @param offset Offset to start reading from * - * @return Number fo bytes read, or in case of an error + * @return Number of bytes read, or in case of an error * BLE_MESH_GATT_ERR() with a specific ATT error code. */ ssize_t (*read)(struct bt_mesh_conn *conn, diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index cc98e03cdc4..6a457718993 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -1560,8 +1560,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; @@ -1604,8 +1609,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; diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index 4ddd2418d3c..b46896bec95 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -99,21 +99,21 @@ int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], 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++; diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 33054e847c9..58d409dd37f 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -162,74 +162,6 @@ int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t 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; - } - - 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; -} - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) @@ -380,7 +312,6 @@ 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 @@ -388,27 +319,29 @@ static void schedule_retransmit(struct seg_tx *tx) * destination (dst) is unassigned, and then process * the seg_pending of this segment. * See BLEMESH25-92 for details */ + + bt_mesh_seg_tx_lock(tx); + if (tx->dst == BLE_MESH_ADDR_UNASSIGNED) { if (tx->seg_pending) { tx->seg_pending--; } - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } 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"); 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); } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index a4a5130e215..47dfcc56162 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -190,74 +190,6 @@ uint32_t bt_mesh_seg_ack_period(void) return (uint32_t)(val * 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 - } - - 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; - } - - 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; -} - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) 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 7e5448707d9..505bcd88d56 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,7 +20,7 @@ #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; @@ -86,7 +86,7 @@ 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) { + if ((node = client_pick_node(&data->queue, ctx->addr)) == NULL) { BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); @@ -113,32 +113,8 @@ 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) -{ - bt_mesh_client_node_t *node = NULL; - sys_snode_t *cur = NULL; - - 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) +static uint32_t 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; @@ -155,7 +131,7 @@ static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_ 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; @@ -177,9 +153,9 @@ static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) 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; @@ -203,7 +179,7 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, seg_rtx_to = bt_mesh_get_seg_rtx_timeout(ctx->addr, ctx->send_ttl); 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- @@ -309,7 +285,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; } @@ -324,14 +300,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");