From 9ce26e421f359b0709e141df9d6145ab03c577d8 Mon Sep 17 00:00:00 2001 From: luoxu Date: Thu, 15 May 2025 17:47:44 +0800 Subject: [PATCH] feat(ble_mesh): add BLE 5.0 extended advertising and long packet support - Add extended advertising configuration with customizable PHY selection (1M, 2M, Coded) - Implement long packet mode to overcome standard BLE Mesh packet length limitations - Add configurable advertising parameters: interval, count, channel map, TX power - Introduce enhanced message context structure for fine-grained advertising control - Add Kconfig options for buffer management and segment count configuration - Support both forced and preferred long packet transmission modes - Update advertising buffer pools to accommodate extended and long packet types - Add validation for enhanced advertising parameters and packet length limits - Maintain backward compatibility with existing BLE Mesh functionality --- components/bt/esp_ble_mesh/Kconfig.in | 80 +++++ .../api/core/esp_ble_mesh_networking_api.c | 58 +++- .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 171 +++++++++- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 2 + components/bt/esp_ble_mesh/core/access.c | 21 +- components/bt/esp_ble_mesh/core/adv.c | 53 ++- components/bt/esp_ble_mesh/core/adv_common.c | 225 ++++++++++++- components/bt/esp_ble_mesh/core/adv_common.h | 69 +++- components/bt/esp_ble_mesh/core/ble_adv.c | 4 +- .../core/bluedroid_host/adapter.c | 119 +++++-- components/bt/esp_ble_mesh/core/ext_adv.c | 66 +++- .../esp_ble_mesh/core/include/mesh/access.h | 47 ++- .../esp_ble_mesh/core/include/mesh/adapter.h | 32 +- .../bt/esp_ble_mesh/core/include/mesh/hci.h | 4 + components/bt/esp_ble_mesh/core/net.c | 92 ++++- components/bt/esp_ble_mesh/core/net.h | 10 +- .../esp_ble_mesh/core/nimble_host/adapter.c | 117 ++++++- .../bt/esp_ble_mesh/core/proxy_server.c | 6 + components/bt/esp_ble_mesh/core/scan.c | 25 +- components/bt/esp_ble_mesh/core/transport.c | 314 +++++++++++++++--- .../bt/esp_ble_mesh/core/transport.enh.c | 307 +++++++++++++++-- components/bt/esp_ble_mesh/core/transport.h | 53 ++- .../models/client/client_common.c | 11 +- 23 files changed, 1694 insertions(+), 192 deletions(-) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index eb761a5e74..3f8f0a37d7 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -33,6 +33,86 @@ if BLE_MESH help This option to enable BLE Mesh using some BLE 5.0 APIs. + menuconfig BLE_MESH_EXT_ADV + bool "Enable extended advertising for BLE Mesh" + depends on BLE_MESH_USE_BLE_50 + default n + help + Enable broadcasting of BLE Mesh messages using BLE 5.0 extended advertising. + This allows control of extended advertising parameters (e.g., PHY selection) + while maintaining standard BLE Mesh packet length. + + config BLE_MESH_EXT_ADV_BUF_COUNT + int "Number of extended advertising buffers" + depends on BLE_MESH_EXT_ADV + range 6 256 + default 60 + help + Number of buffer slots allocated for extended advertising packets. + + config BLE_MESH_EXT_RELAY_ADV_BUF_COUNT + int "Number of extended relay advertising buffers" + depends on BLE_MESH_EXT_ADV + depends on BLE_MESH_RELAY + range 0 256 + default 60 + help + Number of buffer slots allocated for extended advertising packets used in message relay. + + menuconfig BLE_MESH_LONG_PACKET + bool "Enable non-standard long packet mode for BLE Mesh" + depends on BLE_MESH_EXT_ADV + default n + help + Enable extended-length advertising packets for BLE Mesh using BLE 5.0 extended advertising. + This overrides the standard BLE Mesh packet length limitations. + + config BLE_MESH_LONG_PACKET_ADV_LEN + int "Maximum advertising payload length" + depends on BLE_MESH_LONG_PACKET + range 30 249 + default 105 + help + Maximum payload length for extended advertising packets (bytes). + Range: 30-249 bytes. + Default: 105. + Note: Maximum access payload = (LENGTH - 17) × SEGMENT_COUNT + - Transmission: Uses BLE_MESH_LONG_PACKET_TX_SEG_CNT + - Reception: Uses BLE_MESH_LONG_PACKET_RX_SEG_CNT + + config BLE_MESH_LONG_PACKET_ADV_BUF_COUNT + int "Long packet advertising buffer count" + depends on BLE_MESH_LONG_PACKET + default 20 + help + Number of advertising buffers allocated for long packet transmissions. + + config BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT + int "Long packet relay buffer count" + depends on BLE_MESH_LONG_PACKET + depends on BLE_MESH_RELAY + default 20 + help + Number of advertising buffers allocated for relay long packets. + + config BLE_MESH_LONG_PACKET_TX_SEG_CNT + int "Maximum transmission segments per message" + depends on BLE_MESH_LONG_PACKET + range 1 BLE_MESH_TX_SEG_MAX if BLE_MESH_TX_SEG_MAX < BLE_MESH_LONG_PACKET_ADV_BUF_COUNT + range 1 BLE_MESH_LONG_PACKET_ADV_BUF_COUNT if BLE_MESH_TX_SEG_MAX >= BLE_MESH_LONG_PACKET_ADV_BUF_COUNT + default 20 + help + Maximum number of segments for outgoing long packet messages. + Upper bound: min(BLE_MESH_TX_SEG_MAX, BLE_MESH_LONG_PACKET_ADV_BUF_COUNT) + + config BLE_MESH_LONG_PACKET_RX_SEG_CNT + int "Maximum reception segments per message" + depends on BLE_MESH_LONG_PACKET + range 1 BLE_MESH_LONG_PACKET_ADV_BUF_COUNT + default 20 + help + Maximum number of segments supported for receiving long packet messages. + config BLE_MESH_ADV_INST_ID depends on BLE_MESH_USE_BLE_50 int "Extended adv instance for Mesh normal packets" diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c index 4f6b46196a..daa7e00ab0 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.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 */ @@ -30,8 +30,55 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); - if (ctx && ctx->addr == ESP_BLE_MESH_ADDR_UNASSIGNED) { - BT_ERR("Invalid destination address 0x0000"); + if (ctx) { + if (ctx->addr == ESP_BLE_MESH_ADDR_UNASSIGNED) { + BT_ERR("Invalid destination address 0x0000"); + return ESP_ERR_INVALID_ARG; + } + + if (ctx->enh.adv_cfg_used && + ctx->enh.adv_cfg.channel_map & BIT(3)) { + BT_ERR("Invalid channel map 0x%04x: bit 3 is reserved", ctx->enh.adv_cfg.channel_map); + return ESP_ERR_INVALID_ARG; + } + +#if CONFIG_BLE_MESH_EXT_ADV + if (ctx->enh.ext_adv_cfg_used) { + if (ctx->enh.ext_adv_cfg.primary_phy == ESP_BLE_MESH_ADV_PHY_CODED) { + BT_ERR("Primary phy can't be set to coded phy"); + return ESP_ERR_INVALID_ARG; + } + + if (ctx->enh.ext_adv_cfg.primary_phy == ESP_BLE_MESH_ADV_PHY_UNASSIGNED) { + ctx->enh.ext_adv_cfg.primary_phy = ESP_BLE_MESH_ADV_PHY_DEFAULT; + } + + if (ctx->enh.ext_adv_cfg.secondary_phy == ESP_BLE_MESH_ADV_PHY_UNASSIGNED) { + ctx->enh.ext_adv_cfg.secondary_phy = ESP_BLE_MESH_ADV_PHY_DEFAULT; + } + } +#if CONFIG_BLE_MESH_LONG_PACKET + if (ctx->enh.long_pkt_cfg_used && + (ctx->enh.long_pkt_cfg != ESP_BLE_MESH_LONG_PACKET_FORCE && + ctx->enh.long_pkt_cfg != ESP_BLE_MESH_LONG_PACKET_PREFER)) { + BT_ERR("Invalid long packet configuration %d (expected FORCE=1 or PREFER=2)", + ctx->enh.long_pkt_cfg); + } + + if (ctx->enh.long_pkt_cfg_used && (op_len + length + mic_len > ESP_BLE_MESH_EXT_SDU_MAX_LEN)) { + BT_ERR("The length(%d) exceeds the maximum length supported by the long packet", length); + return ESP_ERR_INVALID_ARG; + } + if (((!ctx->enh.long_pkt_cfg_used) && op_len + length + mic_len > MIN(ESP_BLE_MESH_SDU_MAX_LEN, ESP_BLE_MESH_TX_SDU_MAX))) { + BT_ERR("Too large data length %d", length); + return ESP_ERR_INVALID_ARG; + } +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + } // if (ctx) + + if (op_len + length + mic_len > MIN(ESP_BLE_MESH_SDU_MAX_LEN, ESP_BLE_MESH_TX_SDU_MAX)) { + BT_ERR("Too large data length %d", length); return ESP_ERR_INVALID_ARG; } @@ -70,11 +117,6 @@ static esp_err_t ble_mesh_model_send_msg(esp_ble_mesh_model_t *model, ESP_BLE_MESH_MIC_LONG : ESP_BLE_MESH_MIC_SHORT; } - if (op_len + length + mic_len > MIN(ESP_BLE_MESH_SDU_MAX_LEN, ESP_BLE_MESH_TX_SDU_MAX)) { - BT_ERR("Too large data length %d", length); - return ESP_ERR_INVALID_ARG; - } - if (act == BTC_BLE_MESH_ACT_MODEL_PUBLISH) { bt_mesh_model_msg_init(model->pub->msg, opcode); net_buf_simple_add_mem(model->pub->msg, data, length); 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 188d6db22d..7d4b0ed170 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 @@ -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 */ @@ -20,6 +20,12 @@ extern "C" { /*!< The maximum length of a BLE Mesh message, including Opcode, Payload and TransMIC */ #define ESP_BLE_MESH_SDU_MAX_LEN 384 +#if CONFIG_BLE_MESH_LONG_PACKET +/* Extended SDU maximum length (included Opcode, Payload and TransMIC) calculation: + * SEGMENT_COUNT × (ADV_PAYLOAD_LEN - 17 bytes overhead) + * 17 bytes = 9 bytes mesh network header + 4 bytes transport overhead + 4 bytes NetMIC */ +#define ESP_BLE_MESH_EXT_SDU_MAX_LEN (CONFIG_BLE_MESH_LONG_PACKET_TX_SEG_CNT * (CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN - 17)) +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ /*!< Length of a short Mesh MIC. */ #define ESP_BLE_MESH_MIC_SHORT 4 @@ -613,6 +619,166 @@ struct esp_ble_mesh_model { */ #define ESP_BLE_MESH_MODEL_NONE ((esp_ble_mesh_model_t []){}) +#if CONFIG_BLE_MESH_USE_BLE_50 +#define ESP_BLE_MESH_ADV_CHAN_UNASSIGNED (0) +#define ESP_BLE_MESH_ADV_CHAN_37 BIT(0) +#define ESP_BLE_MESH_ADV_CHAN_38 BIT(1) +#define ESP_BLE_MESH_ADV_CHAN_39 BIT(2) + +#define ESP_BLE_MESH_DEFAULT_CHANNEL_MAP (ESP_BLE_MESH_ADV_CHAN_37| \ + ESP_BLE_MESH_ADV_CHAN_38| \ + ESP_BLE_MESH_ADV_CHAN_39) + +#define ESP_BLE_MESH_ADV_PHY_UNASSIGNED (0) +#define ESP_BLE_MESH_ADV_PHY_1M (1) +#define ESP_BLE_MESH_ADV_PHY_2M (2) +#define ESP_BLE_MESH_ADV_PHY_CODED (3) +#define ESP_BLE_MESH_ADV_PHY_DEFAULT ESP_BLE_MESH_ADV_PHY_1M +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + +/** + * Enhanced configuration for Mesh messages with legacy advertising + */ +typedef struct { + /** + * Advertising interval in milliseconds. + * If set to 0, the Mesh protocol stack's xmit parameters are used. + * If set to another value (e.g., 10), the advertising interval will be 10 ms. + */ + uint32_t adv_itvl; + + /** + * Number of advertising per packet. + * If set to 0, the Mesh protocol stack's xmit parameters are used. + * If set to another value (e.g., 3), the number of advertising per packet will be 3. + */ + uint8_t adv_cnt; + + /** + * Advertising channel map. + * If set to 0, the protocol stack uses default channels. + * If set to another value (e.g., ESP_BLE_MESH_ADV_CHAN_37), + * the advertising channel map will be 0x01, the advertising + * packet will only advertise on channel 37. + */ + uint8_t channel_map; +} esp_ble_mesh_adv_cfg_t; + +#if CONFIG_BLE_MESH_EXT_ADV +/** Enhanced configuration for Mesh messages with extended advertising */ +typedef struct { + /** + * Primary PHY for advertising (ESP_BLE_MESH_ADV_PHY_1M or + * ESP_BLE_MESH_ADV_PHY_CODED). + * When using coded PHY, receivers must use coded scanning. + */ + uint8_t primary_phy; + + /** + * Secondary PHY for advertising (ESP_BLE_MESH_ADV_PHY_1M, + * ESP_BLE_MESH_ADV_PHY_2M, or ESP_BLE_MESH_ADV_PHY_CODED). + * When using coded PHY, receivers must use coded scanning. + */ + uint8_t secondary_phy; + + /** + * Include TX power in advertising packets (0: disabled, 1: enabled). + * Allows receivers/relays to maintain original transmission power. + */ + uint8_t include_tx_power:1; + + /** Transmission power level (in dBm) */ + int8_t tx_power; +} esp_ble_mesh_ext_adv_cfg_t; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET +/** Force this message to use long packet format */ +#define ESP_BLE_MESH_LONG_PACKET_FORCE (1) + +/** + * Whether to use the long packet mode will be chosen by the protocol stack, + * which currently makes the decision based on message length. + * Advertising using the standard BLE Mesh protocol when possible. + * Switch to long packet mode for advertising when the standard BLE + * Mesh protocol cannot be used. + */ +#define ESP_BLE_MESH_LONG_PACKET_PREFER (2) +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + +/** Enhanced message advertising parameters */ +typedef struct { + /** + * Use custom advertising parameters (0: disabled, 1: enabled). + * When enabled, `adv_cfg` parameters override stack defaults. + */ + uint8_t adv_cfg_used:1; + +#if CONFIG_BLE_MESH_EXT_ADV + /** + * Use extended advertising parameters (0: disabled, 1: enabled). + * When enabled, `ext_adv_cfg` parameters override stack defaults. + */ + uint8_t ext_adv_cfg_used:1; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET + /** + * Control long packet usage (0: disabled, 1: enabled). + * When disabled, the protocol stack cannot use long packets to + * send this message. + */ + uint8_t long_pkt_cfg_used:1; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + + /** Standard advertising parameters */ + esp_ble_mesh_adv_cfg_t adv_cfg; + +#if CONFIG_BLE_MESH_EXT_ADV + /** Extended advertising parameters */ + esp_ble_mesh_ext_adv_cfg_t ext_adv_cfg; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET + /** + * Long packet configuration: + * - ESP_BLE_MESH_LONG_PACKET_FORCE + * - ESP_BLE_MESH_LONG_PACKET_PREFER + */ + uint8_t long_pkt_cfg:2; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +} esp_ble_mesh_msg_enh_params_t; + +#define ESP_BLE_MESH_ADV_CFG_NULL ((esp_ble_mesh_adv_cfg_t){0}) +#define ESP_BLE_MESH_EXT_ADV_CFG_NULL ((esp_ble_mesh_ext_adv_cfg_t){0}) + +#define ESP_BLE_MESH_ADV_CFG_DEFAULT \ + ((esp_ble_mesh_adv_cfg_t){\ + .adv_itvl= 0, \ + .adv_cnt = 0, \ + .channel_map = ESP_BLE_MESH_DEFAULT_CHANNEL_MAP, \ + }) + +#define ESP_BLE_MESH_EXT_ADV_CFG_DEFAULT \ + ((esp_ble_mesh_ext_adv_cfg_t){ \ + .primary_phy = ESP_BLE_MESH_ADV_PHY_1M, \ + .secondary_phy = ESP_BLE_MESH_ADV_PHY_1M, \ + .tx_power = 0x7f, \ + .include_tx_power = false,\ + }) + +#if CONFIG_BLE_MESH_LONG_PACKET +#define ESP_BLE_MESH_LONG_PACKET_DEF_ENH_SET(ADV_CFG, EXT_ADV_CFG, LONG_PACKET_CFG) \ + ((esp_ble_mesh_msg_enh_params_t){ \ + .adv_cfg_used = true,\ + .adv_cfg = ADV_CFG, \ + .ext_adv_cfg_used = true, \ + .ext_adv_cfg = EXT_ADV_CFG, \ + .long_pkt_cfg_used = true, \ + .long_pkt_cfg = LONG_PACKET_CFG, \ + }) +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + /** Message sending context. * This structure is associated with struct bt_mesh_msg_ctx in mesh_access.h */ @@ -664,6 +830,9 @@ typedef struct { /** Indicate if the message is sent by a node server model, no need to be initialized before sending message */ bool srv_send __attribute__((deprecated)); + + /** Enhanced message advertising parameters */ + esp_ble_mesh_msg_enh_params_t enh; } esp_ble_mesh_msg_ctx_t; /** Provisioning properties & capabilities. 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 e878250012..72d1774d5e 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 @@ -2950,6 +2950,8 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg) .msg_timeout = arg->model_send.msg_timeout, }; + memcpy(¶m.ctx.enh, &arg->model_send.ctx->enh, sizeof(bt_mesh_msg_enh_params_t)); + err = bt_mesh_client_send_msg(¶m, buf, arg->model_send.need_rsp, btc_ble_mesh_client_model_timeout_cb); bt_mesh_free_buf(buf); diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 3791add9e3..86d80139d0 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 */ @@ -29,6 +29,11 @@ #define BLE_MESH_SDU_MAX_LEN 384 +/* Extended SDU maximum length (message length + TransMIC size) calculation: + * 32 segments maximum × (249 bytes max PDU - 17 bytes overhead) + * 17 bytes = 9 bytes mesh header + 4 bytes transport overhead + 4-byte NetMIC */ +#define BLE_MESH_EXT_SDU_MAX_LEN (32*(249-17)) + extern const struct bt_mesh_comp *comp_0; static uint16_t dev_primary_addr; @@ -973,10 +978,24 @@ static int model_send(struct bt_mesh_model *model, return -EINVAL; } +#if CONFIG_BLE_MESH_LONG_PACKET + if (msg->len > MIN(BLE_MESH_EXT_TX_SDU_MAX, BLE_MESH_EXT_SDU_MAX_LEN) - BLE_MESH_MIC_SHORT) { + BT_ERR("Too big ext message (len %d)", msg->len); + return -EMSGSIZE; + } + + if ((msg->len <= MIN(BLE_MESH_EXT_TX_SDU_MAX, BLE_MESH_EXT_SDU_MAX_LEN) - BLE_MESH_MIC_SHORT) && + (msg->len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SDU_MAX_LEN) - BLE_MESH_MIC_SHORT) && + !tx->ctx->enh.long_pkt_cfg_used) { + BT_ERR("Extended message length %d requires long packet mode, but long_pkt_cfg_used is false", msg->len); + return -EMSGSIZE; + } +#else if (msg->len > MIN(BLE_MESH_TX_SDU_MAX, BLE_MESH_SDU_MAX_LEN) - BLE_MESH_MIC_SHORT) { BT_ERR("Too big message (len %d)", msg->len); return -EMSGSIZE; } +#endif if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) { BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx); diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index 54efa0d43e..0258c24c62 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.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 */ @@ -60,6 +60,7 @@ static inline int adv_send(struct net_buf *buf) 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; @@ -69,10 +70,20 @@ static inline int adv_send(struct net_buf *buf) #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV if (BLE_MESH_ADV(buf)->type != BLE_MESH_ADV_BLE) { #endif - adv_int = MAX(ADV_ITVL_MIN, - BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); - duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10); + 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", BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1, adv_int, @@ -86,10 +97,38 @@ static inline int adv_send(struct net_buf *buf) param.interval_min = ADV_SCAN_UNIT(adv_int); param.interval_max = param.interval_min; + 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_USE_BLE_50 - param.adv_duration = duration; - param.adv_count = BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1; +#if CONFIG_BLE_MESH_EXT_ADV + if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_PROV || + BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_DATA || + BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_RELAY_DATA +#if CONFIG_BLE_MESH_LONG_PACKET + || BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_LONG_PROV + || BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_LONG_DATA + || BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_EXT_LONG_RELAY_DATA #endif + ) { + 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; + } + + param.adv_duration = duration; + param.adv_count = adv_cnt; +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c index e7ae571f34..2f3d01e346 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.c +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -35,6 +35,36 @@ struct bt_mesh_adv_queue relay_adv_queue; #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 @@ -48,8 +78,10 @@ NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; -struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx) +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; } @@ -154,11 +186,58 @@ int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ -struct bt_mesh_adv *adv_alloc(int id) +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]; @@ -357,12 +436,8 @@ struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, BT_DBG("pool %p, buf_count %d, uinit_count %d, ref %d", buf->pool, pool->buf_count, pool->uninit_count, buf->ref); - adv = adv_types[type].pool_allocator(net_buf_id(buf)); + adv = adv_types[type].pool_allocator(net_buf_id(buf), type); BLE_MESH_ADV(buf) = adv; - - (void)memset(adv, 0, sizeof(*adv)); - - adv->type = type; bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); return buf; } @@ -476,8 +551,10 @@ bool bt_mesh_ignore_relay_packet(uint32_t timestamp) return ((interval >= BLE_MESH_RELAY_TIME_INTERVAL) ? true : false); } -static struct bt_mesh_adv *relay_adv_alloc(int id) +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]; } @@ -531,21 +608,58 @@ 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; + +#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, CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT, + bt_mesh_adv_queue_init(&relay_adv_queue, ble_mesh_relay_adv_buf_count_get(), ble_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 */ +#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, 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); + +#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); +#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); +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); -#endif +#if CONFIG_BLE_MESH_EXT_ADV + bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, 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); +#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 */ } @@ -554,14 +668,33 @@ 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 + #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); +#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); +#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); +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INS); #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); -#endif +#if CONFIG_BLE_MESH_EXT_ADV + bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, 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); +#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); @@ -597,6 +730,27 @@ 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 + return adv_count; +} + void bt_mesh_adv_task_init(void adv_thread(void *p)) { if (!adv_thread) { @@ -625,7 +779,7 @@ void bt_mesh_adv_task_init(void adv_thread(void *p)) void bt_mesh_adv_common_init(void) { bt_mesh_r_mutex_create(&adv_buf_alloc_lock); - bt_mesh_adv_queue_init(&adv_queue, BLE_MESH_ADV_QUEUE_SIZE, bt_mesh_task_post); + bt_mesh_adv_queue_init(&adv_queue, ble_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); @@ -636,7 +790,21 @@ void bt_mesh_adv_common_init(void) #if CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_adv_inst_init(BLE_MESH_ADV_INS, 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 /** @@ -651,7 +819,21 @@ void bt_mesh_adv_common_init(void) 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); +#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); +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF + bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, 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); +#if !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); +#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 @@ -677,6 +859,25 @@ void bt_mesh_adv_common_deinit(void) 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_INS); diff --git a/components/bt/esp_ble_mesh/core/adv_common.h b/components/bt/esp_ble_mesh/core/adv_common.h index 0477e889e9..23372d404c 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.h +++ b/components/bt/esp_ble_mesh/core/adv_common.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 */ @@ -48,9 +48,6 @@ extern "C" { #define BLE_MESH_ADV_INS_UNUSED 0xFF -/* We reserve one queue item for bt_mesh_adv_update() */ -#define BLE_MESH_ADV_QUEUE_SIZE (CONFIG_BLE_MESH_ADV_BUF_COUNT + 1) - struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; void *cb_data; @@ -60,8 +57,23 @@ struct bt_mesh_adv { 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) @@ -110,14 +122,6 @@ typedef struct bt_mesh_msg { uint32_t timestamp; /* Timestamp recorded when the relay packet is posted to queue */ } bt_mesh_msg_t; -typedef struct bt_mesh_adv *(*bt_mesh_pool_allocator_t)(int id); -typedef void (*bt_mesh_adv_queue_send_cb_t)(bt_mesh_msg_t *msg, uint32_t timeout, bool front); - -struct bt_mesh_adv_queue { - bt_mesh_queue_t q; - bt_mesh_adv_queue_send_cb_t send; -}; - struct bt_mesh_adv_inst { uint8_t id; #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV @@ -132,6 +136,16 @@ struct bt_mesh_adv_inst { 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 @@ -155,15 +169,20 @@ typedef enum { BLE_MESH_BUF_REF_MAX, } bt_mesh_buf_ref_flag_t; -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; -}; 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 @@ -174,6 +193,20 @@ static const uint8_t adv_type[] = { [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); @@ -255,7 +288,7 @@ 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); +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 diff --git a/components/bt/esp_ble_mesh/core/ble_adv.c b/components/bt/esp_ble_mesh/core/ble_adv.c index ec99efa09c..ec2e0cc227 100644 --- a/components/bt/esp_ble_mesh/core/ble_adv.c +++ b/components/bt/esp_ble_mesh/core/ble_adv.c @@ -30,8 +30,10 @@ static struct bt_mesh_ble_adv_tx ble_adv_tx[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); -static struct bt_mesh_adv *ble_adv_alloc(int id) +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]; } 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 db96209760..a74dc749f8 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 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 */ @@ -240,9 +240,19 @@ void bt_mesh_ble_ext_adv_report(tBTM_BLE_EXT_ADV_REPORT *ext_adv_report) #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ } +#if CONFIG_BLE_MESH_LONG_PACKET +static struct { + struct bt_mesh_adv_report adv_rpt; + uint8_t adv_data_len; + uint8_t adv_data[2 + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN]; +} adv_report_cache; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + static bool bt_mesh_scan_result_process(tBTM_BLE_EXT_ADV_REPORT *ext_adv_report) { struct bt_mesh_adv_report adv_rpt = {0}; + uint8_t *adv_data = NULL; + uint8_t adv_data_len = 0; assert(ext_adv_report); @@ -251,23 +261,31 @@ static bool bt_mesh_scan_result_process(tBTM_BLE_EXT_ADV_REPORT *ext_adv_report) adv_rpt.primary_phy = ext_adv_report->primary_phy; adv_rpt.secondary_phy = ext_adv_report->secondry_phy; adv_rpt.rssi = ext_adv_report->rssi; + adv_rpt.tx_power = ext_adv_report->tx_power; + adv_data = ext_adv_report->adv_data; + adv_data_len = ext_adv_report->adv_data_len; +#if !CONFIG_BLE_MESH_EXT_ADV if (!(ext_adv_report->event_type & BTM_BLE_ADV_LEGACY_MASK)) { return false; } - - if (!bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_SCANNING)) { - return false; - } +#endif BT_DBG("Recv adv report type %04x", ext_adv_report->event_type); + if (ext_adv_report->adv_data_len > BLE_MESH_GAP_ADV_MAX_LEN) { + return false; + } + switch (ext_adv_report->event_type) { case BLE_MESH_ADV_IND: case BLE_MESH_ADV_DIRECT_IND: case BLE_MESH_ADV_SCAN_IND: case BLE_MESH_ADV_NONCONN_IND: case BLE_MESH_ADV_SCAN_RSP: +#if CONFIG_BLE_MESH_EXT_ADV + case BLE_MESH_EXT_ADV_NONCONN_IND: +#endif adv_rpt.adv_type = ext_adv_report->event_type; break; default: @@ -275,10 +293,51 @@ static bool bt_mesh_scan_result_process(tBTM_BLE_EXT_ADV_REPORT *ext_adv_report) break; } +#if CONFIG_BLE_MESH_LONG_PACKET + switch (ext_adv_report->data_status) { + case BTM_BLE_EXT_ADV_DATA_COMPLETE: + if (adv_report_cache.adv_data_len) { + memcpy(adv_report_cache.adv_data + adv_report_cache.adv_data_len, + ext_adv_report->adv_data, ext_adv_report->adv_data_len); + adv_report_cache.adv_data_len += ext_adv_report->adv_data_len; + adv_data = adv_report_cache.adv_data; + adv_data_len = adv_report_cache.adv_data_len; + adv_report_cache.adv_data_len = 0; + } + break; + case BTM_BLE_EXT_ADV_DATA_INCOMPLETE: + if ((adv_report_cache.adv_data_len + ext_adv_report->adv_data_len) > BLE_MESH_GAP_ADV_MAX_LEN) { + adv_report_cache.adv_data_len = 0; + return false; + } + if (adv_report_cache.adv_data_len == 0) { + memcpy(&adv_report_cache.adv_rpt, &adv_rpt, sizeof(struct bt_mesh_adv_report)); + } + memcpy(adv_report_cache.adv_data + adv_report_cache.adv_data_len, + ext_adv_report->adv_data, ext_adv_report->adv_data_len); + adv_report_cache.adv_data_len += ext_adv_report->adv_data_len; + /* To avoid discarding user's packets, + * it is assumed here that this packet + * is not mesh's packet */ + return false; + case BTM_BLE_EXT_ADV_DATA_TRUNCATED: + if (adv_report_cache.adv_data_len) { + memset(&adv_report_cache, 0, sizeof(adv_report_cache)); + } + return false; + default: + assert(0); + } +#else /* CONFIG_BLE_MESH_LONG_PACKET */ + if (ext_adv_report->data_status != BTM_BLE_EXT_ADV_DATA_COMPLETE) { + return false; + } +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + if (bt_mesh_scan_dev_found_cb) { - net_buf_simple_init_with_data(&adv_rpt.adv_data, ext_adv_report->adv_data, ext_adv_report->adv_data_len); + net_buf_simple_init_with_data(&adv_rpt.adv_data, adv_data, adv_data_len); bt_mesh_scan_dev_found_cb(&adv_rpt); - if (adv_rpt.adv_data.len != ext_adv_report->adv_data_len) { + if (adv_rpt.adv_data.len != adv_data_len) { /* The advertising data has been processed by Mesh Protocol */ return true; } @@ -430,7 +489,7 @@ static int set_adv_data(uint16_t hci_op, const struct bt_mesh_adv_data *ad, size for (i = 0; i < ad_len; i++) { /* Check if ad fit in the remaining buffer */ - if (param.len + ad[i].data_len + 2 > 31) { + if (param.len + ad[i].data_len + 2 > sizeof(param.data)) { return -EINVAL; } @@ -593,6 +652,11 @@ static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARC #endif #if CONFIG_BLE_MESH_USE_BLE_50 +static struct { + bool set; + tBTA_DM_BLE_GAP_EXT_ADV_PARAMS param; +} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; + int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, const struct bt_mesh_adv_data *ad, size_t ad_len, @@ -624,11 +688,10 @@ int bt_le_ext_adv_start(const uint8_t inst_id, ext_adv_params.type = BTA_DM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_SCAN; } else { if (param->primary_phy == BLE_MESH_ADV_PHY_1M && - param->secondary_phy == BLE_MESH_ADV_PHY_1M) { - ext_adv_params.type = BTA_DM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_NONCONN; - } else { - BT_ERR("Unsupported PHY: pri %d sec %d",param->primary_phy, param->secondary_phy); - return -EINVAL; + param->secondary_phy == BLE_MESH_ADV_PHY_1M && + param->include_tx_power == false && + ad->data_len <= 29) { + ext_adv_params.type = BTA_DM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_NONCONN; } } @@ -648,12 +711,16 @@ int bt_le_ext_adv_start(const uint8_t inst_id, ext_adv_params.sid = inst_id; ext_adv_params.max_skip = 0; - ext_adv_params.tx_power = 0x7F; + ext_adv_params.tx_power = param->tx_power; ext_adv_params.scan_req_notif = false; ext_adv_params.primary_phy = param->primary_phy; ext_adv_params.secondary_phy = param->secondary_phy; ext_adv_params.filter_policy = BLE_MESH_AP_SCAN_CONN_ALL; - ext_adv_params.channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + ext_adv_params.channel_map = param->channel_map; + + if (param->include_tx_power) { + ext_adv_params.type |= BTA_DM_BLE_GAP_SET_EXT_ADV_PROP_INCLUDE_TX_PWR; + } interval = param->interval_min; @@ -674,8 +741,18 @@ int bt_le_ext_adv_start(const uint8_t inst_id, ext_adv_params.interval_min = interval; ext_adv_params.interval_max = interval; - /* Check if we can start adv using BTM_BleSetAdvParamsStartAdvCheck */ - BTA_DmBleGapExtAdvSetParams(inst_id, &ext_adv_params); + if (memcmp(&ext_adv_params, &last_param[inst_id].param, sizeof(tBTA_DM_BLE_GAP_EXT_ADV_PARAMS))) { + if (last_param[inst_id].set) { + BTA_DmBleGapExtAdvSetRemove(inst_id); + } + + last_param[inst_id].set = true; + + /* Check if we can start adv using BTM_BleSetAdvParamsStartAdvCheck */ + BTA_DmBleGapExtAdvSetParams(inst_id, &ext_adv_params); + + memcpy(&last_param[inst_id].param, &ext_adv_params, sizeof(tBTA_DM_BLE_GAP_EXT_ADV_PARAMS)); + } err = set_adv_data(BLE_MESH_HCI_OP_SET_ADV_DATA, inst_id, ad, ad_len); if (err) { @@ -723,7 +800,6 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, const struct bt_mesh_adv_data *sd, size_t sd_len) { tBTA_START_ADV_CMPL_CBACK *p_start_adv_cb = NULL; - tBTM_BLE_ADV_CHNL_MAP channel_map = 0U; tBLE_ADDR_TYPE addr_type_own = 0U; tBLE_BD_ADDR p_dir_bda = {0}; tBTM_BLE_AFP adv_fil_pol = 0U; @@ -787,7 +863,6 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, addr_type_own = BLE_MESH_ADDR_PUBLIC; #endif - channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; adv_fil_pol = BLE_MESH_AP_SCAN_CONN_ALL; p_start_adv_cb = start_adv_completed_cb; @@ -810,7 +885,7 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, BLE_MESH_BTM_CHECK_STATUS( BTM_BleSetAdvParamsAll(interval, interval, adv_type, addr_type_own, &p_dir_bda, - channel_map, adv_fil_pol, p_start_adv_cb)); + param->channel_map, adv_fil_pol, p_start_adv_cb)); BLE_MESH_BTM_CHECK_STATUS(BTM_BleStartAdv()); #if BLE_MESH_DEV @@ -891,7 +966,7 @@ int bt_mesh_ble_ext_adv_start(const uint8_t inst_id, ext_adv_params.primary_phy = BLE_MESH_ADV_PHY_1M; ext_adv_params.secondary_phy = BLE_MESH_ADV_PHY_1M; ext_adv_params.filter_policy = BLE_MESH_AP_SCAN_CONN_ALL; - ext_adv_params.channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + ext_adv_params.channel_map = BLE_MESH_ADV_CHAN_37 | BLE_MESH_ADV_CHAN_38 | BLE_MESH_ADV_CHAN_39; if (param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || @@ -939,7 +1014,7 @@ int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param, } } - channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + channel_map = BLE_MESH_ADV_CHAN_37 | BLE_MESH_ADV_CHAN_38 | BLE_MESH_ADV_CHAN_39; adv_fil_pol = BLE_MESH_AP_SCAN_CONN_ALL; if (param->own_addr_type == BLE_MESH_ADDR_PUBLIC_ID || param->own_addr_type == BLE_MESH_ADDR_RANDOM_ID || diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c index 32157ea3d3..ebc2851777 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.c +++ b/components/bt/esp_ble_mesh/core/ext_adv.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 */ @@ -56,13 +56,30 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration 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)); + 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 @@ -76,14 +93,38 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration #endif case BLE_MESH_ADV_BEACON: case BLE_MESH_ADV_URI: { - adv_int = MAX(ADV_ITVL_MIN, - BLE_MESH_TRANSMIT_INT(BLE_MESH_ADV(buf)->xmit)); - duration = (BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10); +#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", - BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1, adv_int, - duration); + adv_cnt, adv_int, duration); ad.type = adv_type[BLE_MESH_ADV(buf)->type]; ad.data_len = buf->len; @@ -94,10 +135,13 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration param.interval_max = param.interval_min; param.adv_duration = duration; - param.adv_count = BLE_MESH_TRANSMIT_COUNT(BLE_MESH_ADV(buf)->xmit) + 1; + param.adv_count = adv_cnt; - param.primary_phy = BLE_MESH_ADV_PHY_1M; - param.secondary_phy = BLE_MESH_ADV_PHY_1M; + 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) { 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 fac499764d..38be1a6cac 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/access.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/access.h @@ -4,7 +4,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 */ @@ -154,6 +154,49 @@ struct bt_mesh_elem { #define BLE_MESH_MODEL_ID_MBT_SRV 0x1400 #define BLE_MESH_MODEL_ID_MBT_CLI 0x1401 +typedef struct { + uint32_t adv_itvl; + uint8_t adv_cnt; + uint8_t channel_map; +} ble_mesh_adv_cfg_t; + +#if CONFIG_BLE_MESH_EXT_ADV +typedef struct { + uint8_t primary_phy; + uint8_t secondary_phy; + uint8_t include_tx_power:1; + int8_t tx_power; +} ble_mesh_ext_adv_cfg_t; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET +#define BLE_MESH_LONG_PACKET_FORCE (1) +#define BLE_MESH_LONG_PACKET_PREFER (2) +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + +typedef struct { + uint8_t adv_cfg_used : 1; +#if CONFIG_BLE_MESH_EXT_ADV + uint8_t ext_adv_cfg_used : 1; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +#if CONFIG_BLE_MESH_LONG_PACKET + uint8_t long_pkt_cfg_used : 1; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + + ble_mesh_adv_cfg_t adv_cfg; +#if CONFIG_BLE_MESH_EXT_ADV + ble_mesh_ext_adv_cfg_t ext_adv_cfg; +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +#if CONFIG_BLE_MESH_LONG_PACKET + /** + * Long packets will be used for broadcasting + * only if this flag is set and the traditional + * packet length (380 bytes) cannot be used. + */ + uint8_t long_pkt_cfg : 2; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +} bt_mesh_msg_enh_params_t; + /** Message sending context. */ struct bt_mesh_msg_ctx { /** NetKey Index of the subnet to send the message on. */ @@ -204,6 +247,8 @@ struct bt_mesh_msg_ctx { /** Change by Espressif, if the message is sent by a server * model. Not used for receiving message. */ bool srv_send __attribute__((deprecated)); + + bt_mesh_msg_enh_params_t enh; }; struct bt_mesh_model_op { 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 f02c9f5b3b..de8b01c95f 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-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -77,11 +77,17 @@ extern "C" { #endif #endif /* CONFIG_BT_NIMBLE_ENABLED */ +#if CONFIG_BLE_MESH_LONG_PACKET +#define BLE_MESH_GAP_ADV_MAX_LEN (2 + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN) +#else #define BLE_MESH_GAP_ADV_MAX_LEN 31 +#endif #define BLE_MESH_GATT_DEF_MTU_SIZE 23 #if CONFIG_BLE_MESH_USE_BLE_50 +#define BLE_MESH_TX_POWER_INCLUDE_DEFAULT false +#define BLE_MESH_TX_POWER_DEFAULT 0x7f #define BLE_MESH_ADV_PHY_UNASSIGNED 0 #define BLE_MESH_ADV_PHY_1M 1 #define BLE_MESH_ADV_PHY_2M 2 @@ -91,6 +97,8 @@ extern "C" { #define BLE_MESH_ADV_PHY_OPTION_PREFER_S8 2 #define BLE_MESH_ADV_PHY_OPTION_REQUIRE_S2 3 #define BLE_MESH_ADV_PHY_OPTION_REQUIRE_S8 4 +#define BLE_MESH_ADV_PRI_PHY_DEFAULT BLE_MESH_ADV_PHY_1M +#define BLE_MESH_ADV_SEC_PHY_DEFAULT BLE_MESH_ADV_PHY_1M #endif /* BD ADDR types */ @@ -112,6 +120,9 @@ extern "C" { #define BLE_MESH_ADV_SCAN_RSP 0x04 #else /* Bluetooth Core Spec 6.0, Vol 4, Part E, 7.7.65.13 */ +#if CONFIG_BLE_MESH_EXT_ADV +#define BLE_MESH_EXT_ADV_NONCONN_IND (0) +#endif #define BLE_MESH_ADV_IND (0x13) #define BLE_MESH_ADV_DIRECT_IND (0x15) #define BLE_MESH_ADV_SCAN_IND (0x12) @@ -120,10 +131,15 @@ extern "C" { #define BLE_MESH_ADV_SCAN_RSP (0x1b) #endif +#define BLE_MESH_ADV_ITVL_DEFAULT (0) +#define BLE_MESH_ADV_CNT_DEFAULT (0) + /* advertising channel map */ -#define BLE_MESH_ADV_CHNL_37 BIT(0) -#define BLE_MESH_ADV_CHNL_38 BIT(1) -#define BLE_MESH_ADV_CHNL_39 BIT(2) +#define BLE_MESH_ADV_CHAN_UNASSIGNED (0) +#define BLE_MESH_ADV_CHAN_37 BIT(0) +#define BLE_MESH_ADV_CHAN_38 BIT(1) +#define BLE_MESH_ADV_CHAN_39 BIT(2) +#define BLE_MESH_ADV_CHAN_DEFAULT (BLE_MESH_ADV_CHAN_39|BLE_MESH_ADV_CHAN_38|BLE_MESH_ADV_CHAN_37) /* Advertising filter policy */ #define BLE_MESH_AP_SCAN_CONN_ALL 0x00 @@ -472,6 +488,8 @@ struct bt_mesh_adv_param { /** Maximum Advertising Interval (N * 0.625) */ uint16_t interval_max; + uint8_t channel_map; + #if CONFIG_BLE_MESH_USE_BLE_50 /** Maximum Advertising Duration (N * 0.625) */ uint16_t adv_duration; @@ -484,6 +502,10 @@ struct bt_mesh_adv_param { /** Advertising Secondary PHY */ uint8_t secondary_phy; + + int8_t tx_power; + + uint8_t include_tx_power : 1; #endif }; @@ -577,6 +599,8 @@ struct bt_mesh_adv_report { /* Secondary advertising PHY */ uint8_t secondary_phy; + + uint8_t tx_power; #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ }; diff --git a/components/bt/esp_ble_mesh/core/include/mesh/hci.h b/components/bt/esp_ble_mesh/core/include/mesh/hci.h index 9be507d95e..2d2ecc8a0d 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/hci.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/hci.h @@ -112,7 +112,11 @@ struct bt_mesh_hci_cp_set_adv_param { #define BLE_MESH_HCI_OP_SET_ADV_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0008) struct bt_mesh_hci_cp_set_adv_data { uint8_t len; +#if CONFIG_BLE_MESH_LONG_PACKET + uint8_t data[2 + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN]; +#else uint8_t data[31]; +#endif } __attribute__((packed)); #define BLE_MESH_HCI_OP_SET_SCAN_RSP_DATA BLE_MESH_OP(BLE_MESH_OGF_LE, 0x0009) diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 4f54c85419..c81b15d37d 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.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 */ @@ -27,7 +27,6 @@ #include "fast_prov.h" #include "prov_node.h" #include "test.h" -#include "fast_prov.h" #include "proxy_client.h" #include "proxy_server.h" #include "pvnr_mgmt.h" @@ -1674,7 +1673,27 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, */ #if !CONFIG_BLE_MESH_RELAY_ADV_BUF - buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); +#if CONFIG_BLE_MESH_EXT_ADV + if (rx->ctx.enh.ext_adv_cfg_used) { +#if CONFIG_BLE_MESH_LONG_PACKET + if (rx->ctx.enh.long_pkt_cfg) { + buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); + } else +#endif + { + buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); + } + if (buf) { + EXT_ADV(buf)->primary_phy = rx->ctx.enh.ext_adv_cfg.primary_phy; + EXT_ADV(buf)->secondary_phy = rx->ctx.enh.ext_adv_cfg.secondary_phy; + EXT_ADV(buf)->include_tx_power = rx->ctx.enh.ext_adv_cfg.include_tx_power; + EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; + } + } else +#endif + { + buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); + } #else /* Check if the number of relay packets in queue is too large, if so * use minimum relay retransmit value for later relay packets. @@ -1682,7 +1701,27 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (bt_mesh_get_stored_relay_count() >= BLE_MESH_MAX_STORED_RELAY_COUNT) { xmit = BLE_MESH_TRANSMIT(0, 20); } - buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); +#if CONFIG_BLE_MESH_EXT_ADV + if (rx->ctx.enh.ext_adv_cfg_used) { +#if CONFIG_BLE_MESH_LONG_PACKET + if (rx->ctx.enh.long_pkt_cfg) { + buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); + } else +#endif + { + buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); + } + if (buf) { + EXT_ADV(buf)->primary_phy = rx->ctx.enh.ext_adv_cfg.primary_phy; + EXT_ADV(buf)->secondary_phy = rx->ctx.enh.ext_adv_cfg.secondary_phy; + EXT_ADV(buf)->include_tx_power = rx->ctx.enh.ext_adv_cfg.include_tx_power; + EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; + } + } else +#endif + { + buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); + } #endif if (!buf) { @@ -1922,33 +1961,42 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, struct bt_mesh_net_rx *rx, enum bt_mesh_net_if net_if) { - NET_BUF_SIMPLE_DEFINE(buf, 29); struct net_buf_simple_state state = {0}; + struct net_buf_simple *buf = NULL; - assert(rx); - - BT_DBG("rssi %d net_if %u", rx->ctx.recv_rssi, net_if); + if (data->len > (BLE_MESH_GAP_ADV_MAX_LEN - 2)) { + BT_ERR("Invalid net message length %d", data->len); + return; + } if (!ready_to_recv()) { return; } - if (bt_mesh_net_decode(data, net_if, rx, &buf)) { + buf = bt_mesh_alloc_buf(data->len); + if (!buf) { + BT_ERR("Alloc net msg buffer failed"); return; } + BT_DBG("rssi %d net_if %u", rx->ctx.recv_rssi, net_if); + + if (bt_mesh_net_decode(data, net_if, rx, buf)) { + goto free_net_msg_buf; + } + if (ignore_net_msg(rx->ctx.addr, rx->ctx.recv_dst)) { - return; + goto free_net_msg_buf; } /* Save the state so the buffer can later be relayed */ - net_buf_simple_save(&buf, &state); + net_buf_simple_save(buf, &state); 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", rx->ctl, rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_ttl, - bt_hex(buf.data + BLE_MESH_NET_HDR_LEN, buf.len - BLE_MESH_NET_HDR_LEN)); + bt_hex(buf->data + BLE_MESH_NET_HDR_LEN, buf->len - BLE_MESH_NET_HDR_LEN)); /* If trying to handle a message with DST set to all-directed-forwarding-nodes, * we need to make sure the directed forwarding functionality is enabled in the @@ -1958,6 +2006,15 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, 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 + * is less than or equal to 29, it still may be the + * last segment for a long packet, But if the bit + * is set, it must be part of the long packet*/ + rx->ctx.enh.long_pkt_cfg_used = (buf->len >= 29); + rx->ctx.enh.long_pkt_cfg = BLE_MESH_LONG_PACKET_FORCE; +#endif + 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 && @@ -1968,7 +2025,7 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_DISABLED && !rx->local_match) { BT_INFO("Proxy is disabled; ignoring message"); - return; + goto free_net_msg_buf; } /* If the Directed Proxy Server receives a valid Network PDU from the Directed @@ -1995,7 +2052,7 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, * credentials. Remove it from the message cache so that we accept * it again in the future. */ - if (bt_mesh_trans_recv(&buf, rx) == -EAGAIN) { + if (bt_mesh_trans_recv(buf, rx) == -EAGAIN) { BT_WARN("Removing rejected message from Network Message Cache"); msg_cache[rx->msg_cache_idx].src = BLE_MESH_ADDR_UNASSIGNED; /* Rewind the next index now that we're not using this entry */ @@ -2011,9 +2068,12 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, && !rx->replay_msg #endif )) { - net_buf_simple_restore(&buf, &state); - bt_mesh_net_relay(&buf, rx); + net_buf_simple_restore(buf, &state); + bt_mesh_net_relay(buf, rx); } + +free_net_msg_buf: + bt_mesh_free(buf); } static void ivu_refresh(struct k_work *work) diff --git a/components/bt/esp_ble_mesh/core/net.h b/components/bt/esp_ble_mesh/core/net.h index 94e0781917..e946daef0f 100644 --- a/components/bt/esp_ble_mesh/core/net.h +++ b/components/bt/esp_ble_mesh/core/net.h @@ -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 */ @@ -473,6 +473,14 @@ static inline void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, enum bt_mesh_net_if net_if) { struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi }; +#if CONFIG_BLE_MESH_EXT_ADV + rx.ctx.enh.adv_cfg_used = false; + rx.ctx.enh.ext_adv_cfg_used = false; +#if CONFIG_BLE_MESH_LONG_PACKET + rx.ctx.enh.long_pkt_cfg_used = (data->len >= 29); + rx.ctx.enh.long_pkt_cfg = BLE_MESH_LONG_PACKET_FORCE; +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_generic_net_recv(data, &rx, net_if); } 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 b247734575..60478e93e7 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 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 */ @@ -494,6 +494,14 @@ void bt_mesh_ble_ext_adv_report(struct ble_gap_ext_disc_desc *desc) } #endif +#if CONFIG_BLE_MESH_LONG_PACKET +static struct { + struct bt_mesh_adv_report adv_rpt; + uint8_t adv_data_len; + uint8_t adv_data[2 + CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN]; +} adv_report_cache; +#endif + int disc_cb(struct ble_gap_event *event, void *arg) { #if CONFIG_BLE_MESH_USE_BLE_50 @@ -517,29 +525,84 @@ int disc_cb(struct ble_gap_event *event, void *arg) #if CONFIG_BLE_MESH_USE_BLE_50 case BLE_GAP_EVENT_EXT_DISC: { struct bt_mesh_adv_report adv_rpt = {0}; + uint8_t *adv_data = NULL; + uint8_t adv_data_len = 0; desc = &event->ext_disc; - + if (desc->length_data > BLE_MESH_GAP_ADV_MAX_LEN) { + /* @todo: bt_mesh_ble_ext_adv_report and transfer + * to user have functional duplication */ + goto report_to_user; + } memcpy(&adv_rpt.addr, &desc->addr, sizeof(bt_mesh_addr_t)); adv_rpt.rssi = desc->rssi; adv_rpt.adv_type = desc->props; adv_rpt.primary_phy = desc->prim_phy; adv_rpt.secondary_phy = desc->sec_phy; + adv_rpt.tx_power = desc->tx_power; + adv_data = (uint8_t *)desc->data; + adv_data_len = desc->length_data; - net_buf_simple_init_with_data(&adv_rpt.adv_data, (void *)desc->data, desc->length_data); +#if CONFIG_BLE_MESH_LONG_PACKET + switch (desc->data_status) { + case BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE: + if (adv_report_cache.adv_data_len) { + memcpy(adv_report_cache.adv_data + adv_report_cache.adv_data_len, + desc->data, desc->length_data); + adv_report_cache.adv_data_len += desc->length_data; + adv_data = adv_report_cache.adv_data; + adv_data_len = adv_report_cache.adv_data_len; + adv_report_cache.adv_data_len = 0; + } + break; + case BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE: + if ((adv_report_cache.adv_data_len + desc->length_data) > BLE_MESH_GAP_ADV_MAX_LEN) { + adv_report_cache.adv_data_len = 0; + return false; + } + if (adv_report_cache.adv_data_len == 0) { + memcpy(&adv_report_cache.adv_rpt, &adv_rpt, sizeof(struct bt_mesh_adv_report)); + } + memcpy(adv_report_cache.adv_data + adv_report_cache.adv_data_len, + desc->data, desc->length_data); + adv_report_cache.adv_data_len += desc->length_data; + /* To avoid discarding user's packets, + * it is assumed here that this packet + * is not mesh's packet */ + goto report_to_user; + case BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED: + if (adv_report_cache.adv_data_len) { + memset(&adv_report_cache, 0, sizeof(adv_report_cache)); + } + goto report_to_user; + default: + assert(0); + } +#else /* CONFIG_BLE_MESH_LONG_PACKET */ + if (desc->data_status != BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE) { + goto report_to_user; + } +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + + net_buf_simple_init_with_data(&adv_rpt.adv_data, (void *)adv_data, adv_data_len); if (bt_mesh_scan_dev_found_cb) { /* TODO: Support Scan Response data length for NimBLE host */ - if (desc->props & BLE_HCI_ADV_LEGACY_MASK) { + if (desc->props & BLE_HCI_ADV_LEGACY_MASK || + (IS_ENABLED(CONFIG_BLE_MESH_EXT_ADV) && + desc->props == BLE_MESH_EXT_ADV_NONCONN_IND)) { bt_mesh_scan_dev_found_cb(&adv_rpt); } } /* Mesh didn't process that data */ - if (adv_rpt.adv_data.len == desc->length_data) { - bt_mesh_ble_ext_adv_report(desc); + if (adv_rpt.adv_data.len == adv_data_len) { + goto report_to_user; } + break; +report_to_user: + bt_mesh_ble_ext_adv_report(desc); break; } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ @@ -1101,6 +1164,11 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) #endif /* CONFIG_BLE_MESH_NODE */ #if CONFIG_BLE_MESH_USE_BLE_50 +static struct { + bool set; + struct ble_gap_ext_adv_params param; +} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; + int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, const struct bt_mesh_adv_data *ad, size_t ad_len, @@ -1125,7 +1193,7 @@ int bt_le_ext_adv_start(const uint8_t inst_id, return -EALREADY; } #endif - buf = bt_mesh_calloc(ad_len * BLE_HS_ADV_MAX_SZ); + buf = bt_mesh_calloc(ad_len * BLE_MESH_GAP_ADV_MAX_LEN); if (!buf) { BT_ERR("ad buffer alloc failed"); return -ENOMEM; @@ -1201,16 +1269,19 @@ int bt_le_ext_adv_start(const uint8_t inst_id, adv_params.legacy_pdu = true; } else { if (param->primary_phy == BLE_MESH_ADV_PHY_1M && - param->secondary_phy == BLE_MESH_ADV_PHY_1M) { - adv_params.legacy_pdu = true; + param->secondary_phy == BLE_MESH_ADV_PHY_1M && + param->include_tx_power == false && + ad->data_len <= 29) { + adv_params.legacy_pdu = true; } } adv_params.sid = inst_id; adv_params.primary_phy = param->primary_phy; adv_params.secondary_phy = param->secondary_phy; - adv_params.tx_power = 0x7F; // tx power will be selected by controller + adv_params.tx_power = param->tx_power; adv_params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + adv_params.include_tx_power = param->include_tx_power; interval = param->interval_min; @@ -1230,10 +1301,23 @@ int bt_le_ext_adv_start(const uint8_t inst_id, adv_params.itvl_min = interval; adv_params.itvl_max = interval; - err = ble_gap_ext_adv_configure(inst_id, &adv_params, NULL, gap_event_cb, NULL); - if (err != 0) { - BT_ERR("Advertising config failed: err %d", err); - return err; + if (memcmp(&adv_params, &last_param[inst_id].param, + sizeof(struct ble_gap_ext_adv_params))) { + if (last_param[inst_id].set) { + err = ble_gap_ext_adv_remove(inst_id); + if (err != 0 && err != BLE_HS_EALREADY) { + BT_ERR("Advertising rm failed: err %d", err); + return err; + } + } + last_param[inst_id].set = true; + err = ble_gap_ext_adv_configure(inst_id, &adv_params, NULL, gap_event_cb, NULL); + if (err != 0) { + BT_ERR("Advertising config failed: err %d", err); + return err; + } + + memcpy(&last_param[inst_id].param, &adv_params, sizeof(struct ble_gap_ext_adv_params)); } err = ble_gap_ext_adv_set_data(inst_id, data); @@ -1358,6 +1442,7 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param, adv_params.itvl_min = interval; adv_params.itvl_max = interval; + adv_params.channel_map = param->channel_map; again: err = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params, @@ -1460,7 +1545,7 @@ int bt_mesh_ble_ext_adv_start(const uint8_t inst_id, adv_params.itvl_min = param->interval; adv_params.itvl_max = param->interval; - adv_params.channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + adv_params.channel_map = BLE_MESH_ADV_CHAN_37 | BLE_MESH_ADV_CHAN_38 | BLE_MESH_ADV_CHAN_39; adv_params.filter_policy = BLE_MESH_AP_SCAN_CONN_ALL; adv_params.primary_phy = BLE_MESH_ADV_PHY_1M; adv_params.secondary_phy = BLE_MESH_ADV_PHY_1M; @@ -1581,7 +1666,7 @@ int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param, } adv_params.itvl_min = param->interval; adv_params.itvl_max = param->interval; - adv_params.channel_map = BLE_MESH_ADV_CHNL_37 | BLE_MESH_ADV_CHNL_38 | BLE_MESH_ADV_CHNL_39; + adv_params.channel_map = BLE_MESH_ADV_CHAN_37 | BLE_MESH_ADV_CHAN_38 | BLE_MESH_ADV_CHAN_39; adv_params.filter_policy = BLE_MESH_AP_SCAN_CONN_ALL; adv_params.high_duty_cycle = (param->adv_type == BLE_MESH_ADV_DIRECT_IND) ? true : false; diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index e806915506..062bb9b247 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -56,11 +56,14 @@ static const struct bt_mesh_adv_param slow_adv_param = { .options = ADV_OPT, .interval_min = BLE_MESH_GAP_ADV_SLOW_INT_MIN, .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, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, + .tx_power = 0x7f, + .include_tx_power = false, #endif }; @@ -68,11 +71,14 @@ static const struct bt_mesh_adv_param fast_adv_param = { .options = ADV_OPT, .interval_min = BLE_MESH_GAP_ADV_FAST_INT_MIN_0, .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, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, + .tx_power = 0x7f, + .include_tx_power = false, #endif }; diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index 192f63f879..0742ddc099 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -424,7 +424,11 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) net_buf_simple_save(buf, &buf_state); - if (adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND && + if ( +#if CONFIG_BLE_MESH_LONG_PACKET + adv_rpt->adv_type != 0 && +#endif + adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND && adv_rpt->adv_type != BLE_MESH_ADV_IND #if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN && adv_rpt->adv_type != BLE_MESH_ADV_SCAN_RSP @@ -490,7 +494,11 @@ 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)) { + 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 +#endif + )) { BT_DBG("Ignore mesh packet (type 0x%02x) with adv_type 0x%02x", type, adv_rpt->adv_type); return; } @@ -500,6 +508,19 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) struct bt_mesh_net_rx rx = { .ctx.recv_rssi = adv_rpt->rssi, }; +#if CONFIG_BLE_MESH_EXT_ADV + if (adv_rpt->adv_type == BLE_MESH_EXT_ADV_NONCONN_IND) { + rx.ctx.enh.ext_adv_cfg_used = true; + rx.ctx.enh.ext_adv_cfg.primary_phy = adv_rpt->primary_phy; + rx.ctx.enh.ext_adv_cfg.secondary_phy = adv_rpt->secondary_phy; + if (adv_rpt->tx_power == 0x7f) { + rx.ctx.enh.ext_adv_cfg.include_tx_power = false; + } else { + rx.ctx.enh.ext_adv_cfg.include_tx_power = true; + } + rx.ctx.enh.ext_adv_cfg.tx_power = adv_rpt->tx_power; + } +#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 diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 33054e847c..bb3575e6f7 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -77,8 +77,16 @@ _Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3) /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT +struct seg_info { + uint8_t ctl:1; /* Control message */ +#if CONFIG_BLE_MESH_LONG_PACKET + uint8_t long_pkt:1; /* Long packet */ +#endif +}; + static struct seg_tx { struct bt_mesh_subnet *sub; + // @todo: select the max one between large seg max and normal seg max struct net_buf *seg[CONFIG_BLE_MESH_TX_SEG_MAX]; uint64_t seq_auth; uint16_t dst; @@ -100,10 +108,11 @@ static struct seg_tx { static struct seg_rx { struct bt_mesh_subnet *sub; uint64_t seq_auth; - uint8_t seg_n:5, + uint16_t seg_n:5, ctl:1, in_use:1, - obo:1; + obo:1, + ext:1; uint8_t hdr; uint8_t ttl; uint16_t src; @@ -112,14 +121,20 @@ static struct seg_rx { uint32_t last; struct k_delayed_work ack_timer; struct net_buf_simple buf; -} seg_rx[CONFIG_BLE_MESH_RX_SEG_MSG_COUNT] = { - [0 ... (CONFIG_BLE_MESH_RX_SEG_MSG_COUNT - 1)] = { - .buf.size = CONFIG_BLE_MESH_RX_SDU_MAX, - }, -}; +} seg_rx[CONFIG_BLE_MESH_RX_SEG_MSG_COUNT]; static uint8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT * CONFIG_BLE_MESH_RX_SDU_MAX)]; +#if CONFIG_BLE_MESH_LONG_PACKET +/* @todo: could merge ext_seg_rx into seg_rx */ +static struct seg_rx ext_seg_rx[CONFIG_BLE_MESH_LONG_PACKET_RX_SEG_CNT]; +static uint8_t ext_seg_rx_buf_data[(CONFIG_BLE_MESH_LONG_PACKET_RX_SEG_CNT * + BLE_MESH_EXT_RX_SDU_MAX)]; +#endif + +static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, + const uint8_t *hdr, const uint64_t *seq_auth, + uint8_t seg_n); static bt_mesh_mutex_t seg_rx_lock; @@ -236,15 +251,47 @@ 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); - buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); +#if CONFIG_BLE_MESH_EXT_ADV +#if CONFIG_BLE_MESH_LONG_PACKET + if (tx->ctx->enh.long_pkt_cfg_used && + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE || + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER && + sdu->len > (BLE_MESH_SDU_UNSEG_MAX + 4)))) { + adv_type = BLE_MESH_ADV_EXT_LONG_DATA; + } else +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + { + if (tx->ctx->enh.ext_adv_cfg_used) { + adv_type = BLE_MESH_ADV_EXT_DATA; + } + } +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + + buf = bt_mesh_adv_create(adv_type, BUF_TIMEOUT); if (!buf) { BT_ERR("Out of network buffers"); return -ENOBUFS; } + if (tx->ctx->enh.adv_cfg_used) { + BLE_MESH_ADV(buf)->channel_map = tx->ctx->enh.adv_cfg.channel_map; + BLE_MESH_ADV(buf)->adv_cnt = tx->ctx->enh.adv_cfg.adv_cnt; + BLE_MESH_ADV(buf)->adv_itvl = tx->ctx->enh.adv_cfg.adv_itvl; + } + +#if CONFIG_BLE_MESH_EXT_ADV + if (tx->ctx->enh.ext_adv_cfg_used) { + EXT_ADV(buf)->primary_phy = tx->ctx->enh.ext_adv_cfg.primary_phy; + EXT_ADV(buf)->secondary_phy = tx->ctx->enh.ext_adv_cfg.secondary_phy; + EXT_ADV(buf)->include_tx_power = tx->ctx->enh.ext_adv_cfg.include_tx_power; + EXT_ADV(buf)->tx_power = tx->ctx->enh.ext_adv_cfg.tx_power; + } +#endif + net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); if (ctl_op) { @@ -287,13 +334,21 @@ send: return bt_mesh_net_send(tx, buf, cb, cb_data); } -static inline uint8_t seg_len(bool ctl) +static inline uint8_t seg_len(struct seg_info *si) { - if (ctl) { - return BLE_MESH_CTL_SEG_SDU_MAX; + if (si->ctl) { + return +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : +#endif + BLE_MESH_CTL_SEG_SDU_MAX; } - return BLE_MESH_APP_SEG_SDU_MAX; + return +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : +#endif + BLE_MESH_APP_SEG_SDU_MAX; } bool bt_mesh_tx_in_progress(void) @@ -311,7 +366,14 @@ bool bt_mesh_tx_in_progress(void) 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); + /* 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())) && + (bt_mesh_fixed_group_match(tx->dst) || bt_mesh_elem_find(tx->dst))) { + bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 4U, BLE_MESH_BUF_REF_SMALL); + } else { + 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` @@ -512,7 +574,9 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { + enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; struct seg_tx *tx = NULL; + struct seg_info si = {0}; uint16_t seq_zero = 0U; uint8_t seg_hdr = 0U; uint8_t seg_o = 0U; @@ -544,16 +608,28 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, } if (ctl_op) { + si.ctl = 1; seg_hdr = TRANS_CTL_HDR(*ctl_op, 1); } else if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + si.ctl = 0; seg_hdr = SEG_HDR(0, 0); } else { + si.ctl = 0; seg_hdr = SEG_HDR(1, net_tx->aid); } +#if CONFIG_BLE_MESH_LONG_PACKET + if (net_tx->ctx->enh.long_pkt_cfg_used && + (net_tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE || + (net_tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER && + sdu->len > BLE_MESH_TX_SDU_MAX))) { + si.long_pkt = 1; + } +#endif + tx->dst = net_tx->ctx->addr; if (sdu->len) { - tx->seg_n = (sdu->len - 1) / seg_len(!!ctl_op); + tx->seg_n = (sdu->len - 1) / seg_len(&si); } else { tx->seg_n = 0; } @@ -594,14 +670,43 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, for (seg_o = 0U; sdu->len; seg_o++) { struct net_buf *seg = NULL; uint16_t len = 0U; - - seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); +#if CONFIG_BLE_MESH_LONG_PACKET + if (si.long_pkt) { + adv_type = BLE_MESH_ADV_EXT_LONG_DATA; + } else +#endif + { +#if CONFIG_BLE_MESH_EXT_ADV + if (net_tx->ctx->enh.ext_adv_cfg_used) { + adv_type = BLE_MESH_ADV_EXT_DATA; + } else +#endif + { + adv_type = BLE_MESH_ADV_DATA; + } + } + seg = bt_mesh_adv_create(adv_type, BUF_TIMEOUT); if (!seg) { BT_ERR("Out of segment buffers"); err = -ENOBUFS; break; } + if (net_tx->ctx->enh.adv_cfg_used) { + BLE_MESH_ADV(seg)->channel_map = net_tx->ctx->enh.adv_cfg.channel_map; + BLE_MESH_ADV(seg)->adv_cnt = net_tx->ctx->enh.adv_cfg.adv_cnt; + BLE_MESH_ADV(seg)->adv_itvl = net_tx->ctx->enh.adv_cfg.adv_itvl; + } + +#if CONFIG_BLE_MESH_EXT_ADV + if (net_tx->ctx->enh.ext_adv_cfg_used) { + EXT_ADV(seg)->primary_phy = net_tx->ctx->enh.ext_adv_cfg.primary_phy; + EXT_ADV(seg)->secondary_phy = net_tx->ctx->enh.ext_adv_cfg.secondary_phy; + EXT_ADV(seg)->include_tx_power = net_tx->ctx->enh.ext_adv_cfg.include_tx_power; + EXT_ADV(seg)->tx_power = net_tx->ctx->enh.ext_adv_cfg.tx_power; + } +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN); net_buf_add_u8(seg, seg_hdr); @@ -609,7 +714,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, net_buf_add_u8(seg, (((seq_zero & 0x3f) << 2) | (seg_o >> 3))); net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx->seg_n); - len = MIN(sdu->len, seg_len(!!ctl_op)); + len = MIN(sdu->len, seg_len(&si)); net_buf_add_mem(seg, net_buf_simple_pull_mem(sdu, len), len); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { @@ -694,9 +799,22 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, return -EINVAL; } +#if CONFIG_BLE_MESH_LONG_PACKET + if (tx->ctx->enh.long_pkt_cfg_used == true && + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE || + tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER) && + msg->len > BLE_MESH_EXT_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } else { + if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } + } +#else if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; } +#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); @@ -794,7 +912,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, /* Use bt_mesh_alloc_buf() instead of NET_BUF_SIMPLE_DEFINE to avoid * causing btu task stack overflow. */ - sdu = bt_mesh_alloc_buf(CONFIG_BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT); + sdu = bt_mesh_alloc_buf(buf->len); if (!sdu) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; @@ -1342,19 +1460,34 @@ static void seg_ack(struct k_work *work) bt_mesh_seg_rx_unlock(); } -static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) +static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { - return ((seg_n + 1) * seg_len(ctl) <= CONFIG_BLE_MESH_RX_SDU_MAX); + return ((seg_n + 1) * seg_len); } -static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, - const uint64_t *seq_auth) +static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) +{ + struct seg_info si = { + .ctl = ctl, + }; +#if CONFIG_BLE_MESH_LONG_PACKET + if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { + si.long_pkt = 1; + return ((seg_n + 1) * seg_len(&si) <= BLE_MESH_EXT_RX_SDU_MAX); + } +#endif + return ((seg_n + 1) * seg_len(&si) <= CONFIG_BLE_MESH_RX_SDU_MAX); +} + +static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth, + struct seg_rx *rx_buf, + uint16_t rx_buf_size ) { int i; - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; - + for (i = 0; i < rx_buf_size; i++) { + struct seg_rx *rx = &rx_buf[i]; if (rx->src != net_rx->ctx.addr || rx->dst != net_rx->ctx.recv_dst) { continue; @@ -1387,6 +1520,64 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, return NULL; } + +static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth) +{ +#if CONFIG_BLE_MESH_LONG_PACKET + struct seg_rx *rx = NULL; + rx = seg_rx_find_with_buf(net_rx, seq_auth, seg_rx, ARRAY_SIZE(seg_rx)); + + if (rx) { + if (likely(!net_rx->ctx.enh.long_pkt_cfg_used)) { + return rx; + } + + if (rx->seq_auth != *seq_auth) { + return rx; + } + + /* The first received segment that is possible is the last segment. + * The segment information is stored in seg_rx, so it needs to be + * confirmed in seg_rx. + * This will only happen when the last segment is received + * */ + assert(rx->block == BIT(rx->seg_n)); + assert(rx->ctl == net_rx->ctl); + struct seg_info si = { + .ctl = net_rx->ctl, + .long_pkt = 0, + }; + + /* @note: This situation will not occur in theory. + * If it occurs, please check the reason carefully */ + if (rx->buf.len <= (rx->seg_n * seg_len(&si))) { + BT_ERR("Incorrect packet length, the rx will be reset"); + seg_rx_reset(rx, true); + return NULL; + } + + /* Copy the information in seg_rx into ext_seg_rx */ + struct seg_rx *ext_rx = seg_rx_alloc(net_rx, &(rx->hdr), seq_auth, rx->seg_n); + uint16_t last_seg_len = rx->buf.len - (rx->seg_n * seg_len(&si)); + uint8_t *last_seg = rx->buf.data + (rx->seg_n * seg_len(&si)); + + /* Update to long packet length */ + si.long_pkt = 1; + ext_rx->buf.len = rx->seg_n * seg_len(&si) + last_seg_len; + ext_rx->block = rx->block; + ext_rx->obo = rx->obo; + + memcpy(ext_rx->buf.data + (rx->seg_n * seg_len(&si)), last_seg, last_seg_len); + seg_rx_reset(rx, true); + return ext_rx; + } + return seg_rx_find_with_buf(net_rx, seq_auth, ext_seg_rx, ARRAY_SIZE(ext_seg_rx)); +#else + return seg_rx_find_with_buf(net_rx, seq_auth, seg_rx, ARRAY_SIZE(seg_rx)); +#endif +} + 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) { @@ -1413,9 +1604,25 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, uint8_t seg_n) { int i; + /* By default, traditional seg_rx is used for allocation. + * If the first segment received is the last segment of + * the long packet, and its length is the length of the traditional packet, + * Since it is impossible to determine whether it is a long packet + * under the current situation, can only copy the rx information + * into the ext_rx buffer when the next segment received and can be + * confirmed to be a long packet*/ + struct seg_rx *seg_rx_buf = seg_rx; + uint16_t rx_buf_size = ARRAY_SIZE(seg_rx); - for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; +#if CONFIG_BLE_MESH_LONG_PACKET + if (net_rx->ctx.enh.long_pkt_cfg_used) { + seg_rx_buf = ext_seg_rx; + rx_buf_size = ARRAY_SIZE(ext_seg_rx); + } +#endif + + for (i = 0; i < rx_buf_size; i++) { + struct seg_rx *rx = &seg_rx_buf[i]; if (rx->in_use) { continue; @@ -1432,7 +1639,11 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, rx->src = net_rx->ctx.addr; rx->dst = net_rx->ctx.recv_dst; rx->block = 0U; - +#if CONFIG_BLE_MESH_LONG_PACKET + rx->ext = (seg_rx_buf == ext_seg_rx); +#else + rx->ext = 0; +#endif BT_DBG("New RX context. Block Complete 0x%08x", BLOCK_COMPLETE(seg_n)); @@ -1483,6 +1694,14 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, return -EINVAL; } +#if CONFIG_BLE_MESH_LONG_PACKET + if (buf->len > BLE_MESH_EXT_APP_SEG_SDU_MAX) { + BT_ERR("The seg length(%d) exceeds the maximum seg length(%d) supported", + buf->len, BLE_MESH_EXT_APP_SEG_SDU_MAX); + return -EINVAL; + } +#endif + /* According to Mesh 1.0 specification: * "The SeqAuth is composed of the IV Index and the sequence number * (SEQ) of the first segment" @@ -1543,7 +1762,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, } /* Bail out early if we're not ready to receive such a large SDU */ - if (!sdu_len_is_ok(net_rx->ctl, seg_n)) { + if (!sdu_len_is_ok(net_rx->ctl, seg_n, buf->len)) { BT_ERR("Too big incoming SDU length"); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, @@ -1586,17 +1805,26 @@ found_rx: return -EALREADY; } + struct seg_info si = { + .ctl = rx->ctl, +#if CONFIG_BLE_MESH_LONG_PACKET + .long_pkt = rx->ext, +#endif + }; + /* All segments, except the last one, must either have 8 bytes of * payload (for 64bit Net MIC) or 12 bytes of payload (for 32bit * Net MIC). */ if (seg_o == seg_n) { /* Set the expected final buffer length */ - rx->buf.len = seg_n * seg_len(rx->ctl) + buf->len; - BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(rx->ctl), - buf->len, rx->buf.len); + rx->buf.len = seg_n * seg_len(&si) + buf->len; - if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { + 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"); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, @@ -1605,8 +1833,9 @@ found_rx: return -EMSGSIZE; } } else { - if (buf->len != seg_len(rx->ctl)) { - BT_ERR("Incorrect segment size for message type"); + if (buf->len != seg_len(&si)) { + BT_ERR("Incorrect segment size for message type %d %d len %d except %d", + rx->ext, rx->ctl, buf->len, seg_len(&si)); return -EINVAL; } } @@ -1620,9 +1849,9 @@ found_rx: } /* Location in buffer can be calculated based on seg_o & rx->ctl */ - memcpy(rx->buf.data + (seg_o * seg_len(rx->ctl)), buf->data, buf->len); + memcpy(rx->buf.data + (seg_o * seg_len(&si)), buf->data, buf->len); - BT_INFO("Seg %u/%u received", seg_o, seg_n); + BT_INFO("Seg %u/%u received",seg_o, seg_n); /* Mark segment as received */ rx->block |= BIT(seg_o); @@ -1804,11 +2033,22 @@ void bt_mesh_trans_init(void) for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { k_delayed_work_init(&seg_rx[i].ack_timer, seg_ack); + seg_rx[i].buf.size = CONFIG_BLE_MESH_RX_SDU_MAX; seg_rx[i].buf.__buf = (seg_rx_buf_data + (i * CONFIG_BLE_MESH_RX_SDU_MAX)); seg_rx[i].buf.data = seg_rx[i].buf.__buf; } +#if CONFIG_BLE_MESH_LONG_PACKET + for (i = 0; i < ARRAY_SIZE(ext_seg_rx); i++) { + k_delayed_work_init(&ext_seg_rx[i].ack_timer, seg_ack); + ext_seg_rx[i].buf.size = CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN; + ext_seg_rx[i].buf.__buf = (ext_seg_rx_buf_data + + (i * CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN)); + ext_seg_rx[i].buf.data = ext_seg_rx[i].buf.__buf; + } +#endif + bt_mesh_mutex_create(&seg_rx_lock); } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index a4a5130e21..434ec0c73a 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 */ @@ -55,6 +55,13 @@ _Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3) /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT +struct seg_info { + uint8_t ctl:1; /* Control message */ +#if CONFIG_BLE_MESH_LONG_PACKET + uint8_t long_pkt:1; /* Long packet */ +#endif +}; + static struct seg_tx { struct bt_mesh_subnet *sub; struct net_buf *seg[CONFIG_BLE_MESH_TX_SEG_MAX]; @@ -95,7 +102,8 @@ static struct seg_rx { in_use:1, obo:1, new_seg:1, /* Indicate if a new segment is just received */ - sarc:2; /* SAR ACK Retransmissions Count */ + sarc:2, /* SAR ACK Retransmissions Count */ + ext:1; uint8_t hdr; uint8_t ttl; uint16_t src; @@ -114,11 +122,22 @@ static struct seg_rx { static uint8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT * CONFIG_BLE_MESH_RX_SDU_MAX)]; +#if CONFIG_BLE_MESH_LONG_PACKET +/* @todo: could merge ext_seg_rx into seg_rx */ +static struct seg_rx ext_seg_rx[CONFIG_BLE_MESH_LONG_PACKET_RX_SEG_CNT]; +static uint8_t ext_seg_rx_buf_data[(CONFIG_BLE_MESH_LONG_PACKET_RX_SEG_CNT * + BLE_MESH_EXT_RX_SDU_MAX)]; +#endif + static const struct bt_mesh_send_cb seg_sent_cb; static bt_mesh_mutex_t seg_tx_lock; static bt_mesh_mutex_t seg_rx_lock; +static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, + const uint8_t *hdr, const uint64_t *seq_auth, + uint8_t seg_n); + static inline void bt_mesh_seg_tx_lock(void) { bt_mesh_r_mutex_lock(&seg_tx_lock); @@ -263,16 +282,48 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const uint8_t *ctl_op) { 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); - buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); +#if CONFIG_BLE_MESH_EXT_ADV +#if CONFIG_BLE_MESH_LONG_PACKET + if (tx->ctx->enh.long_pkt_cfg_used && + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE || + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER && + sdu->len > (BLE_MESH_SDU_UNSEG_MAX + 4)))) { + adv_type = BLE_MESH_ADV_EXT_LONG_DATA; + } else +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + { + if (tx->ctx->enh.ext_adv_cfg_used) { + adv_type = BLE_MESH_ADV_EXT_DATA; + } + } +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + + buf = bt_mesh_adv_create(adv_type, BUF_TIMEOUT); if (!buf) { BT_ERR("Out of network buffers"); return -ENOBUFS; } + if (tx->ctx->enh.adv_cfg_used) { + BLE_MESH_ADV(buf)->channel_map = tx->ctx->enh.adv_cfg.channel_map; + BLE_MESH_ADV(buf)->adv_cnt = tx->ctx->enh.adv_cfg.adv_cnt; + BLE_MESH_ADV(buf)->adv_itvl = tx->ctx->enh.adv_cfg.adv_itvl; + } + +#if CONFIG_BLE_MESH_EXT_ADV + if (tx->ctx->enh.ext_adv_cfg_used) { + EXT_ADV(buf)->primary_phy = tx->ctx->enh.ext_adv_cfg.primary_phy; + EXT_ADV(buf)->secondary_phy = tx->ctx->enh.ext_adv_cfg.secondary_phy; + EXT_ADV(buf)->include_tx_power = tx->ctx->enh.ext_adv_cfg.include_tx_power; + EXT_ADV(buf)->tx_power = tx->ctx->enh.ext_adv_cfg.tx_power; + } +#endif + net_buf_reserve(buf, BLE_MESH_NET_HDR_LEN); if (ctl_op) { @@ -315,13 +366,21 @@ send: return bt_mesh_net_send(tx, buf, cb, cb_data); } -static inline uint8_t seg_len(bool ctl) +static inline uint8_t seg_len(struct seg_info *si) { - if (ctl) { - return BLE_MESH_CTL_SEG_SDU_MAX; + if (si->ctl) { + return +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : +#endif + BLE_MESH_CTL_SEG_SDU_MAX; } - return BLE_MESH_APP_SEG_SDU_MAX; + return +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : +#endif + BLE_MESH_APP_SEG_SDU_MAX; } bool bt_mesh_tx_in_progress(void) @@ -812,7 +871,9 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) { + enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; struct seg_tx *tx = NULL; + struct seg_info si = {0}; uint16_t seq_zero = 0U; uint8_t seg_o = 0U; int err = 0; @@ -863,12 +924,25 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, tx->sub = net_tx->sub; tx->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq); if (ctl_op) { + si.ctl = true; tx->hdr = TRANS_CTL_HDR(*ctl_op, 1); } else if (net_tx->ctx->app_idx == BLE_MESH_KEY_DEV) { + si.ctl = false; tx->hdr = SEG_HDR(0, 0); } else { + si.ctl = false; tx->hdr = SEG_HDR(1, net_tx->aid); } + +#if CONFIG_BLE_MESH_LONG_PACKET + if (net_tx->ctx->enh.long_pkt_cfg_used && + ((net_tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER && + sdu->len > BLE_MESH_TX_SDU_MAX) || + net_tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE)) { + si.long_pkt = 1; + } +#endif + tx->src = net_tx->src; tx->dst = net_tx->ctx->addr; tx->app_idx = net_tx->ctx->app_idx; @@ -883,7 +957,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, tx->tag = net_tx->ctx->send_tag; tx->len = sdu->len; if (sdu->len) { - tx->seg_n = (sdu->len - 1) / seg_len(!!ctl_op); + tx->seg_n = (sdu->len - 1) / seg_len(&si); } else { tx->seg_n = 0; } @@ -933,13 +1007,45 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, struct net_buf *seg = NULL; uint16_t len = 0U; - seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT); +#if CONFIG_BLE_MESH_LONG_PACKET + if (si.long_pkt) { + adv_type = BLE_MESH_ADV_EXT_LONG_DATA; + BT_INFO("use ext long adv data"); + } else +#endif + { +#if CONFIG_BLE_MESH_EXT_ADV + if (net_tx->ctx->enh.ext_adv_cfg_used) { + adv_type = BLE_MESH_ADV_EXT_DATA; + BT_INFO("use ext adv data"); + } else +#endif + { + adv_type = BLE_MESH_ADV_DATA; + } + } + seg = bt_mesh_adv_create(adv_type, BUF_TIMEOUT); if (!seg) { BT_ERR("Out of segment buffers"); seg_tx_reset(tx); return -ENOBUFS; } + if (net_tx->ctx->enh.adv_cfg_used) { + BLE_MESH_ADV(seg)->channel_map = net_tx->ctx->enh.adv_cfg.channel_map; + BLE_MESH_ADV(seg)->adv_cnt = net_tx->ctx->enh.adv_cfg.adv_cnt; + BLE_MESH_ADV(seg)->adv_itvl = net_tx->ctx->enh.adv_cfg.adv_itvl; + } + +#if CONFIG_BLE_MESH_EXT_ADV + if (net_tx->ctx->enh.ext_adv_cfg_used) { + EXT_ADV(seg)->primary_phy = net_tx->ctx->enh.ext_adv_cfg.primary_phy; + EXT_ADV(seg)->secondary_phy = net_tx->ctx->enh.ext_adv_cfg.secondary_phy; + EXT_ADV(seg)->include_tx_power = net_tx->ctx->enh.ext_adv_cfg.include_tx_power; + EXT_ADV(seg)->tx_power = net_tx->ctx->enh.ext_adv_cfg.tx_power; + } +#endif + net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN); net_buf_add_u8(seg, tx->hdr); @@ -947,7 +1053,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, net_buf_add_u8(seg, (((seq_zero & 0x3f) << 2) | (seg_o >> 3))); net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx->seg_n); - len = MIN(sdu->len, seg_len(!!ctl_op)); + len = MIN(sdu->len, seg_len(&si)); net_buf_add_mem(seg, net_buf_simple_pull_mem(sdu, len), len); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { @@ -1044,9 +1150,22 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, return -EINVAL; } +#if CONFIG_BLE_MESH_LONG_PACKET + if (tx->ctx->enh.long_pkt_cfg_used == true && + (tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_FORCE || + tx->ctx->enh.long_pkt_cfg == BLE_MESH_LONG_PACKET_PREFER) && + msg->len > BLE_MESH_EXT_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } else { + if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { + tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; + } + } +#else if (msg->len > BLE_MESH_SDU_UNSEG_MAX) { tx->ctx->send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; } +#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); @@ -1144,7 +1263,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, /* Use bt_mesh_alloc_buf() instead of NET_BUF_SIMPLE_DEFINE to avoid * causing btu task stack overflow. */ - sdu = bt_mesh_alloc_buf(CONFIG_BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT); + sdu = bt_mesh_alloc_buf(buf->len); if (!sdu) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; @@ -1843,9 +1962,23 @@ static void discard_msg(struct k_work *work) seg_rx_reset(rx, false); } -static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) +static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { - return ((seg_n + 1) * seg_len(ctl) <= CONFIG_BLE_MESH_RX_SDU_MAX); + return ((seg_n + 1) * seg_len); +} + +static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) +{ + struct seg_info si = { + .ctl = ctl, + }; +#if CONFIG_BLE_MESH_LONG_PACKET + if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { + si.long_pkt = 1; + return ((seg_n + 1) * seg_len(&si) <= BLE_MESH_EXT_RX_SDU_MAX); + } +#endif + return ((seg_n + 1) * seg_len(&si) <= CONFIG_BLE_MESH_RX_SDU_MAX); } static void seg_rx_reset_pending(struct bt_mesh_net_rx *net_rx, @@ -1867,22 +2000,93 @@ static void seg_rx_reset_pending(struct bt_mesh_net_rx *net_rx, } } -static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, - const uint64_t *seq_auth) +static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth, + struct seg_rx *rx_buf, + uint16_t rx_buf_size ) { - for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; + for (size_t i = 0; i < rx_buf_size; i++) { + struct seg_rx *rx = &rx_buf[i]; if (rx->src == net_rx->ctx.addr && - rx->dst == net_rx->ctx.recv_dst && - rx->seq_auth >= *seq_auth) { - return rx; + rx->dst == net_rx->ctx.recv_dst) { + if (rx->seq_auth >= *seq_auth) { + return rx; + } + + /* Received a new packet when the old packet was not fully obtained */ + BT_WARN("Duplicate SDU from src 0x%04x auth 0x%04x", net_rx->ctx.addr, rx->seq_auth); + + /* Clear out the old context since the sender + * has apparently started sending a new SDU. + */ + seg_rx_reset(rx, true); + + /* Return non-match so caller can re-allocate */ + return NULL; } } return NULL; } +static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, + const uint64_t *seq_auth) +{ +#if CONFIG_BLE_MESH_LONG_PACKET + struct seg_rx *rx = NULL; + + rx = seg_rx_find_with_buf(net_rx, seq_auth, seg_rx, ARRAY_SIZE(seg_rx)); + if (rx) { + if (likely(!net_rx->ctx.enh.long_pkt_cfg_used)) { + return rx; + } + + if (rx->seq_auth != *seq_auth) { + return rx; + } + + /* The first received segment that is possible is the last segment. + * The segment information is stored in seg_rx, so it needs to be + * confirmed in seg_rx */ + /* This will only happen when the last segment is received */ + assert(rx->block == BIT(rx->seg_n)); + assert(rx->ctl == net_rx->ctl); + + struct seg_info si = { + .ctl = net_rx->ctl, + .long_pkt = 0, + }; + + /* @note: This situation will not occur in theory. + * If it occurs, please check the reason carefully */ + if (rx->buf.len <= (rx->seg_n * seg_len(&si))) { + BT_ERR("Incorrect packet length, the rx will be reset"); + seg_rx_reset(rx, true); + return NULL; + } + + /* Copy the information in seg_rx into ext_seg_rx */ + struct seg_rx *ext_rx = seg_rx_alloc(net_rx, &(rx->hdr), seq_auth, rx->seg_n); + uint16_t last_seg_len = rx->buf.len - (rx->seg_n * seg_len(&si)); + uint8_t *last_seg = rx->buf.data + (rx->seg_n * seg_len(&si)); + + /* Update to long packet length */ + si.long_pkt = 1; + ext_rx->buf.len = rx->seg_n * seg_len(&si) + last_seg_len; + ext_rx->block = rx->block; + ext_rx->obo = rx->obo; + + memcpy(ext_rx->buf.data + (rx->seg_n * seg_len(&si)), last_seg, last_seg_len); + seg_rx_reset(rx, true); + return ext_rx; + } + return seg_rx_find_with_buf(net_rx, seq_auth, ext_seg_rx, ARRAY_SIZE(ext_seg_rx)); +#else + return seg_rx_find_with_buf(net_rx, seq_auth, seg_rx, ARRAY_SIZE(seg_rx)); +#endif +} + 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) { @@ -1905,8 +2109,25 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, { int err = 0; - for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; + /* By default, traditional seg_rx is used for allocation. + * If the first segment received is the last segment of + * the long packet, and its length is the length of the traditional packet, + * Since it is impossible to determine whether it is a long packet + * under the current situation, can only copy the rx information + * into the ext_rx buffer when the next segment received and can be + * confirmed to be a long packet*/ + struct seg_rx *seg_rx_buf = seg_rx; + uint16_t rx_buf_size = ARRAY_SIZE(seg_rx); + +#if CONFIG_BLE_MESH_LONG_PACKET + if (net_rx->ctx.enh.long_pkt_cfg_used) { + seg_rx_buf = ext_seg_rx; + rx_buf_size = ARRAY_SIZE(ext_seg_rx); + } +#endif + + for (size_t i = 0; i < rx_buf_size; i++) { + struct seg_rx *rx = &seg_rx_buf[i]; if (rx->in_use) { continue; @@ -1939,7 +2160,11 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, rx->dst = net_rx->ctx.recv_dst; rx->block = 0U; rx->last_ack = 0; - +#if CONFIG_BLE_MESH_LONG_PACKET + rx->ext = (seg_rx_buf == ext_seg_rx); +#else + rx->ext = 0; +#endif BT_DBG("New RX context. Block Complete 0x%08x", BLOCK_COMPLETE(seg_n)); @@ -2062,7 +2287,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, } /* Bail out early if we're not ready to receive such a large SDU */ - if (!sdu_len_is_ok(net_rx->ctl, seg_n)) { + if (!sdu_len_is_ok(net_rx->ctl, seg_n, buf->len)) { BT_ERR("Too big incoming SDU length"); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, @@ -2109,6 +2334,13 @@ found_rx: return -EALREADY; } + struct seg_info si = { + .ctl = rx->ctl, +#if CONFIG_BLE_MESH_LONG_PACKET + .long_pkt = rx->ext, +#endif + }; + /* All segments, except the last one, must either have 8 bytes of * payload (for 64bit Net MIC) or 12 bytes of payload (for 32bit * Net MIC). @@ -2116,9 +2348,9 @@ found_rx: */ if (seg_o == seg_n) { /* Set the expected final buffer length */ - rx->buf.len = seg_n * seg_len(rx->ctl) + buf->len; + rx->buf.len = seg_n * seg_len(&si) + buf->len; - BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(rx->ctl), + BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(&si), buf->len, rx->buf.len); /* This should not happen, since we have made sure the whole @@ -2126,7 +2358,11 @@ found_rx: * But if the peer device sends the segments of a segmented * message with different CTL, then the following could happen. */ - if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { + 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 %u/%u", rx->buf.len, CONFIG_BLE_MESH_RX_SDU_MAX); @@ -2138,14 +2374,14 @@ found_rx: return -EMSGSIZE; } } else { - if (buf->len != seg_len(rx->ctl)) { + if (buf->len != seg_len(&si)) { BT_ERR("Incorrect segment size for message type"); return -EINVAL; } } /* Location in buffer can be calculated based on seg_o & rx->ctl */ - memcpy(rx->buf.data + (seg_o * seg_len(rx->ctl)), buf->data, buf->len); + memcpy(rx->buf.data + (seg_o * seg_len(&si)), buf->data, buf->len); BT_INFO("Seg %u/%u received", seg_o, seg_n); @@ -2342,13 +2578,24 @@ void bt_mesh_tx_reset_single(uint16_t dst) void bt_mesh_trans_init(void) { + size_t i; + bt_mesh_sar_init(); - for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx[i].buf.__buf = (seg_rx_buf_data + (i * CONFIG_BLE_MESH_RX_SDU_MAX)); seg_rx[i].buf.data = seg_rx[i].buf.__buf; } +#if CONFIG_BLE_MESH_LONG_PACKET + for (i = 0; i < ARRAY_SIZE(ext_seg_rx); i++) { + ext_seg_rx[i].buf.size = CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN; + ext_seg_rx[i].buf.__buf = (ext_seg_rx_buf_data + + (i * CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN)); + ext_seg_rx[i].buf.data = ext_seg_rx[i].buf.__buf; + } +#endif + bt_mesh_r_mutex_create(&seg_tx_lock); bt_mesh_r_mutex_create(&seg_rx_lock); } diff --git a/components/bt/esp_ble_mesh/core/transport.h b/components/bt/esp_ble_mesh/core/transport.h index 9c75ea77e9..d8d32f81b6 100644 --- a/components/bt/esp_ble_mesh/core/transport.h +++ b/components/bt/esp_ble_mesh/core/transport.h @@ -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 */ @@ -17,11 +17,58 @@ extern "C" { #endif #define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff - +#if CONFIG_BLE_MESH_LONG_PACKET +#include "adv.h" +/** + * Advertising Packet Length: 29 bytes + * + * Network Layer: + * - Network Header: 9 bytes + * - NetMIC: 4 bytes (for unsegmented messages), 8 bytes (for segmented messages) + * + * Lower Transport PDU: + * - Unsegmented: + * - Header: 1 byte + * - Payload: up to 15 bytes + * - Segmented: + * - Header: 4 bytes + * - Payload: up to 12 bytes per segment + * + * Upper Transport PDU (Access Messages): + * - Unsegmented: + * - TransMIC: 4 bytes + * - Max Access Payload: 11 bytes + * - Segmented: + * - TransMIC size depends on ASZMIC flag: + * - 4-byte TransMIC: Max payload = (32 segments * 12 bytes) - 4 = 380 bytes + * - 8-byte TransMIC: Max payload = (32 segments * 12 bytes) - 8 = 376 bytes + * + * Extended Advertising (ADV) Support: + * - If ADV length is increased to 249 bytes: + * - Max access payload = 32 * (249 - 17) - 8 = 7416 bytes + * - (17 bytes = Network Header + Segment Header + TransMIC) + * + * Reliability Consideration: + * - To achieve an expected valid message ratio of x, + * the minimum ADV packet length should be: + * min_adv_len = 21 / (1 - x) + * Example: + * For >80% success rate (x = 0.8), min_adv_len = 105 bytes + */ +#define BLE_MESH_EXT_SDU_UNSEG_MAX (CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN - 18) +#define BLE_MESH_EXT_CTL_SEG_SDU_MAX (CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN - 21) +#define BLE_MESH_EXT_APP_SEG_SDU_MAX (CONFIG_BLE_MESH_LONG_PACKET_ADV_LEN - 17) +#define BLE_MESH_EXT_TX_SDU_MAX (CONFIG_BLE_MESH_LONG_PACKET_TX_SEG_CNT * BLE_MESH_EXT_APP_SEG_SDU_MAX) +#define BLE_MESH_EXT_RX_SDU_MAX (CONFIG_BLE_MESH_LONG_PACKET_RX_SEG_CNT * BLE_MESH_EXT_APP_SEG_SDU_MAX) +#endif #define BLE_MESH_SDU_UNSEG_MAX 11 +#define BLE_MESH_MSG_UNSEG_MAX (BLE_MESH_SDU_UNSEG_MAX + BLE_MESH_MIC_SHORT) #define BLE_MESH_CTL_SEG_SDU_MAX 8 +/** Maximum size of an access message segment (in octets). */ #define BLE_MESH_APP_SEG_SDU_MAX 12 -#define BLE_MESH_TX_SDU_MAX (CONFIG_BLE_MESH_TX_SEG_MAX * 12) + +#define BLE_MESH_TX_SDU_MAX MAX(BLE_MESH_MSG_UNSEG_MAX, (CONFIG_BLE_MESH_TX_SEG_MAX * 12)) +#define BLE_MESH_RX_SDU_MAX MAX(BLE_MESH_MSG_UNSEG_MAX, (BLE_MESH_APP_SEG_SDU_MAX * 32)) #define TRANS_SEQ_ZERO_MASK ((uint16_t)BIT_MASK(13)) #define TRANS_CTL_OP_MASK ((uint8_t)BIT_MASK(7)) 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 7e5448707d..d10aa244a3 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -201,7 +201,16 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, */ seg_rtx_num = bt_mesh_get_seg_rtx_num(); seg_rtx_to = bt_mesh_get_seg_rtx_timeout(ctx->addr, ctx->send_ttl); - seg_count = (msg->len + mic_size - 1) / 12U + 1U; + +#if CONFIG_BLE_MESH_LONG_PACKET + if (ctx->enh.long_pkt_cfg && + msg->len > BLE_MESH_TX_SDU_MAX) { + seg_count = (msg->len + mic_size - 1) / BLE_MESH_EXT_APP_SEG_SDU_MAX + 1U; + } else +#endif + { + seg_count = (msg->len + mic_size - 1) / 12U + 1U; + } duration = bt_mesh_get_adv_duration(ctx);