Merge branch 'fix/tx_power_validate_v6.1' into 'release/v6.1'

fix(bt): validate BR/EDR TX power against chip-supported range (v6.1)

See merge request espressif/esp-idf!50544
This commit is contained in:
Jiang Jiang Jian
2026-07-17 10:32:04 +08:00
5 changed files with 136 additions and 11 deletions

View File

@@ -695,6 +695,23 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
*/
esp_err_t esp_bt_controller_disable(void);
#if (UC_BT_CTRL_BR_EDR_IS_ENABLE)
/**
* @brief Get the BR/EDR TX power range (in dBm) actually supported by this chip.
*
* The TX power range configurable in menuconfig represents the maximum possible range.
* The values that can actually be applied depend on the chip and are reported by this function.
*
* @param[out] min_power : pointer to store the minimum supported TX power in dBm
* @param[out] max_power : pointer to store the maximum supported TX power in dBm
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_ERR_NOT_SUPPORTED: not supported
*/
esp_err_t esp_bredr_tx_power_range_get(int8_t *min_power, int8_t *max_power);
#endif // (UC_BT_CTRL_BR_EDR_IS_ENABLE)
/** @brief esp_vhci_host_callback
* used for vhci call host function to notify what host need to do
*/

View File

@@ -223,43 +223,65 @@ menu "TX Power Level settings"
config BT_CTRL_BR_EDR_TX_PWR_ACL_MIN
int "Default minimum TX power level for ACL"
default -13
range -24 12
range -24 20
help
Minimum BR/EDR transmission power level for ACL.
The transmission power for an ACL connection link will be affected by the following factors:
It must fall within the range of [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`]
The initial TX power level for an ACL link is inherited from
`BT_CTRL_BR_EDR_TX_PWR_PAGE` (for Central) and `BT_CTRL_BR_EDR_TX_PWR_PSCAN` (for Peripheral).
If the power is lower than BT_CTRL_BR_EDR_TX_PWR_ACL_MIN, BT_CTRL_BR_EDR_TX_PWR_ACL_MIN will be used.
It can be adjusted in response to LMP power control request PDUs from the peer device.
config BT_CTRL_BR_EDR_TX_PWR_ACL_MAX
int "Default maximum TX power level for ACL"
default 4
range -24 12
range -24 20
help
Maximum BR/EDR transmission power level for ACL.
The transmission power for an ACL connection link will be affected by the following factors:
It must fall within the range of [`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`]
The initial TX power level for an ACL link is inherited from
`BT_CTRL_BR_EDR_TX_PWR_PAGE` (for Central) and `BT_CTRL_BR_EDR_TX_PWR_PSCAN` (for Peripheral).
If the power is higher than BT_CTRL_BR_EDR_TX_PWR_ACL_MAX, BT_CTRL_BR_EDR_TX_PWR_ACL_MAX will be used.
It can be adjusted in response to LMP power control request PDUs from the peer device.
config BT_CTRL_BR_EDR_TX_PWR_APB
int "Default TX power level for APB"
depends on BT_CTRL_BR_EDR_APB_EN
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for APB.
config BT_CTRL_BR_EDR_TX_PWR_PAGE
int "Default TX power level for Page"
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for Page.
`BT_CTRL_BR_EDR_TX_PWR_PAGE` is recommended to fall within the ACL transmission power range
[`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`], because the Bluetooth controller
will try to use it as the initial TX power on the ACL link upon connection establishment from page
substate.
config BT_CTRL_BR_EDR_TX_PWR_PSCAN
int "Default TX power level for Page Scan"
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for Page Scan.
`BT_CTRL_BR_EDR_TX_PWR_PSCAN` is recommended to fall within the ACL transmission power range
[`BT_CTRL_BR_EDR_TX_PWR_ACL_MIN`, `BT_CTRL_BR_EDR_TX_PWR_ACL_MAX`], because the Bluetooth controller
will try to use it as the initial TX power on the ACL link upon connection establishment from
page scan substate.
config BT_CTRL_BR_EDR_TX_PWR_ISCAN
int "Default TX power level for Inquiry Scan"
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for Inquiry Scan.
@@ -267,7 +289,7 @@ menu "TX Power Level settings"
int "Default TX power level for CPB"
depends on BT_CTRL_BR_EDR_CPB_TX_EN
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for CPB.
@@ -275,7 +297,7 @@ menu "TX Power Level settings"
int "Default TX power level for Synchronization Train"
depends on BT_CTRL_BR_EDR_CPB_TX_EN
default 4
range -24 12
range -24 20
help
BR/EDR transmission power level for Synchronization Train.
endmenu

View File

@@ -52,6 +52,7 @@
#include "btdm_osal.h"
#include "btdm_endian.h"
#include "btdm_external.h"
#if CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS
#include "psa/crypto.h"
#endif
@@ -784,6 +785,78 @@ static int bredr_log_printf(const char *fmt, ...)
return len;
}
esp_err_t esp_bredr_tx_power_range_get(int8_t *min_power, int8_t *max_power)
{
if (min_power == NULL && max_power == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t pwr_tbl_sz = 0;
const int8_t *pwr_tbl = wr_btdm_external_bb_get_tx_pwr_table(&pwr_tbl_sz, TX_PWR_TABLE_MODEM_CFG_BREDR);
if (pwr_tbl == NULL || pwr_tbl_sz == 0) {
return ESP_ERR_NOT_SUPPORTED;
}
/* The power table is ordered from the lowest to the highest power level */
if (min_power != NULL) {
*min_power = pwr_tbl[0];
}
if (max_power != NULL) {
*max_power = pwr_tbl[pwr_tbl_sz - 1];
}
return ESP_OK;
}
/* Check a single configured TX power value against [min_power, max_power]. */
static bool bredr_check_tx_pwr(const char *name, int8_t value, int8_t min_power, int8_t max_power)
{
if (value < min_power || value > max_power) {
ESP_LOGE(BREDR_LOG_TAG, "%s tx power %d dBm out of supported range [%d, %d] dBm", name, value, min_power, max_power);
return false;
}
return true;
}
/*
* Validate the user-configured BR/EDR TX power values against the range actually supported by the chip.
* The menuconfig limits only describe the maximum possible range, but the achievable range can be narrower depending on the chip.
* Returns ESP_ERR_INVALID_ARG if any configured value is out of range so that controller init can be aborted.
*/
static esp_err_t bredr_validate_tx_pwr_cfg(const esp_bredr_controller_config_t *bredr_cfg)
{
int8_t min_power = 0;
int8_t max_power = 0;
esp_err_t ret = esp_bredr_tx_power_range_get(&min_power, &max_power);
if (ret != ESP_OK) {
ESP_LOGE(BREDR_LOG_TAG, "Failed to get TX power range, err 0x%x", ret);
return ret;
}
bool valid = true;
valid &= bredr_check_tx_pwr("ACL min", bredr_cfg->acl_min_tx_pwr, min_power, max_power);
valid &= bredr_check_tx_pwr("ACL max", bredr_cfg->acl_max_tx_pwr, min_power, max_power);
valid &= bredr_check_tx_pwr("Page", bredr_cfg->page_tx_pwr, min_power, max_power);
valid &= bredr_check_tx_pwr("Page Scan", bredr_cfg->pscan_tx_pwr, min_power, max_power);
valid &= bredr_check_tx_pwr("Inquiry Scan", bredr_cfg->iscan_tx_pwr, min_power, max_power);
#if UC_BR_EDR_APB_EN
valid &= bredr_check_tx_pwr("APB", bredr_cfg->apb_tx_pwr, min_power, max_power);
#endif
#if UC_BR_EDR_CPB_TX_LINK_NB
valid &= bredr_check_tx_pwr("CPB", bredr_cfg->cpb_tx_pwr, min_power, max_power);
valid &= bredr_check_tx_pwr("Sync Train", bredr_cfg->strain_tx_pwr, min_power, max_power);
#endif
if (bredr_cfg->acl_min_tx_pwr > bredr_cfg->acl_max_tx_pwr) {
ESP_LOGE(BREDR_LOG_TAG, "ACL min tx power %d dBm greater than max %d dBm", bredr_cfg->acl_min_tx_pwr, bredr_cfg->acl_max_tx_pwr);
valid = false;
}
return valid ? ESP_OK : ESP_ERR_INVALID_ARG;
}
int esp_bredr_controller_init(esp_bt_controller_config_t *cfg)
{
int status;
@@ -791,6 +864,11 @@ int esp_bredr_controller_init(esp_bt_controller_config_t *cfg)
ESP_LOGI(BREDR_LOG_TAG, "BT controller compile version [%s]", co_orca_get_git_version_str());
err = bredr_validate_tx_pwr_cfg(&cfg->bredr);
if (err != ESP_OK) {
return err;
}
bredr_register_setup_callback(bredr_ctrl_setup_callback);
bredr_register_ext_dep_callback(bredr_ctrl_ext_dep_callback);

View File

@@ -19,6 +19,13 @@ extern "C" {
#define btdm_external_bb_get_tx_pwr_table BTDM_EXTERNAL_WR_FUNC(btdm_external_bb_get_tx_pwr_table)
enum {
TX_PWR_TABLE_MODEM_CFG_BLE = 0,
TX_PWR_TABLE_MODEM_CFG_802154,
TX_PWR_TABLE_MODEM_CFG_BREDR,
TX_PWR_TABLE_MODEM_CFG_MAX,
};
/*
* Function declarations for BTDM EXTERNAL
*/

View File

@@ -15,11 +15,12 @@ const int8_t *
wr_btdm_external_bb_get_tx_pwr_table(uint8_t *length, uint8_t modem_cfg)
{
assert(length != NULL);
assert (modem_cfg <= 2);
// TODO: replace with bt_bb_tx_pwr_table_get when all the targets(h4, s31, etc) support this API
if (modem_cfg == 2) { // BREDR
assert (modem_cfg < TX_PWR_TABLE_MODEM_CFG_MAX);
if (modem_cfg == TX_PWR_TABLE_MODEM_CFG_BREDR) {
return bt_bb_tx_pwr_table_get(length, modem_cfg);
} else {
// TODO: replace with bt_bb_tx_pwr_table_get when all the targets(h4, s31, etc) support this API
return bt_bb_get_tx_pwr_table(length);
}
}