mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'feat/added_nonblocking_mode_for_hci_alloc_6.1' into 'release/v6.1'
fix(bt): fixed multiple CVE issues for Bluetooth Classic Controller See merge request espressif/esp-idf!52846
This commit is contained in:
@@ -239,6 +239,7 @@ extern int btdm_common_sched_bredr_on_sched_hw_list_done(void *param);
|
||||
extern int hci_tl_bredr_on_rx_cmd_c2h_num_pkt(void *param);
|
||||
extern int hci_tl_bredr_on_rx_cmd_set_c2h_flow_ctrl(void *param);
|
||||
extern int odm_afh_on_coex_wifi_channel_change(void *param);
|
||||
extern int olc_acl_on_coex_schm_update(void *param);
|
||||
extern int olc_intc_on_hal_exit_isr(void *param);
|
||||
extern int olc_sleep_on_sched_actual_time_get(void *param);
|
||||
extern int olc_sleep_on_sched_get_earlist_ticks(void *param);
|
||||
@@ -406,11 +407,14 @@ const void * const _base_linear_broker_flash[] = BTDM_BROKER_NODE_DEF_FLASH(
|
||||
#endif /* UC_BT_CTRL_BLE_IS_ENABLE */
|
||||
|
||||
const void * const _btdm_coex_linear_broker_flash[] = BTDM_BROKER_NODE_DEF_FLASH(
|
||||
#if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
[1] = BTDM_BROKER_ENTRY_DEF_FLASH(
|
||||
#if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
brk_sym_coexHook_WcEp3uxRHd6HYgB0pn0L,
|
||||
),
|
||||
#endif /* UC_BT_CTRL_BLE_IS_ENABLE */
|
||||
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
|
||||
olc_acl_on_coex_schm_update,
|
||||
#endif /* UC_BT_CTRL_BR_EDR_IS_ENABLE */
|
||||
),
|
||||
[2] = BTDM_BROKER_ENTRY_DEF_FLASH(
|
||||
#if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
brk_sym_coexHook_wiWNhAUWlHyTZ7Z5ZC5Z,
|
||||
|
||||
Submodule components/bt/controller/lib_esp32h4/esp32h4-bt-lib updated: 00b5a98c1b...9358cd13cc
Submodule components/bt/controller/lib_esp32s31/esp32s31-bt-lib updated: 20e84f6ebe...849186e861
@@ -113,7 +113,7 @@
|
||||
#include "../../common/btdm_le.h"
|
||||
#endif /* SOC_BLE_SUPPORTED */
|
||||
|
||||
#define BTDM_CONFIG_VERSION 0x20260127
|
||||
#define BTDM_CONFIG_VERSION 0x20260911
|
||||
#define BTDM_CONFIG_MAGIC_VALUE 0x5a5aa5a5
|
||||
|
||||
/* Types definition
|
||||
@@ -124,15 +124,16 @@
|
||||
* @brief BTDM controller common configuration options
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t version; /*!< Version number of the defined structure */
|
||||
uint16_t task_stack_size; /*!< Size of Bluetooth controller task stack */
|
||||
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
|
||||
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
|
||||
uint8_t hci_cmd_num; /*!< HCI command buffer number */
|
||||
uint8_t sleep_en; /*!< Enable sleep functionality */
|
||||
uint8_t version_num; /*!< Hardware version number of this chip */
|
||||
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
|
||||
uint32_t magic; /*!< Magic number for configuration validation */
|
||||
uint32_t version; /*!< Version number of the defined structure */
|
||||
uint16_t task_stack_size; /*!< Size of Bluetooth controller task stack */
|
||||
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
|
||||
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
|
||||
uint8_t hci_cmd_num; /*!< HCI command buffer number */
|
||||
uint8_t nonblocking_cmd_buf; /*!< Non-blocking mode for command buffer allocation */
|
||||
uint8_t sleep_en; /*!< Enable sleep functionality */
|
||||
uint8_t version_num; /*!< Hardware version number of this chip */
|
||||
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
|
||||
uint32_t magic; /*!< Magic number for configuration validation */
|
||||
} esp_bt_ctrl_btdm_config_t;
|
||||
|
||||
/**
|
||||
@@ -157,38 +158,40 @@
|
||||
#endif // defined(CONFIG_BTDM_CTRL_MODE_BLE_ONLY)
|
||||
|
||||
#if SOC_BT_CLASSIC_SUPPORTED
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
|
||||
{ \
|
||||
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
|
||||
.bredr = _BT_CTRL_BREDR_INIT_CONFIG_DEFAULT(), \
|
||||
.btdm = \
|
||||
{ \
|
||||
.version = BTDM_CONFIG_VERSION, \
|
||||
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
.magic = BTDM_CONFIG_MAGIC_VALUE, \
|
||||
}, \
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
|
||||
{ \
|
||||
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
|
||||
.bredr = _BT_CTRL_BREDR_INIT_CONFIG_DEFAULT(), \
|
||||
.btdm = \
|
||||
{ \
|
||||
.version = BTDM_CONFIG_VERSION, \
|
||||
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
.magic = BTDM_CONFIG_MAGIC_VALUE, \
|
||||
}, \
|
||||
}
|
||||
#else
|
||||
#else
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() \
|
||||
{ \
|
||||
.ble = _BT_CTRL_LE_INIT_CONFIG_DEFAULT(), \
|
||||
.btdm = \
|
||||
{ \
|
||||
.version = BTDM_CONFIG_VERSION, \
|
||||
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
.magic = BTDM_CONFIG_MAGIC_VALUE, \
|
||||
.version = BTDM_CONFIG_VERSION, \
|
||||
.task_stack_size = UC_BT_CTRL_TASK_STACK_SIZE, \
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
.magic = BTDM_CONFIG_MAGIC_VALUE, \
|
||||
}, \
|
||||
}
|
||||
#endif // SOC_BT_CLASSIC_SUPPORTED
|
||||
|
||||
@@ -112,7 +112,7 @@ typedef struct {
|
||||
#include "../../common/btdm_le.h"
|
||||
#endif /* SOC_BLE_SUPPORTED */
|
||||
|
||||
#define BTDM_CONFIG_VERSION 0x20260127
|
||||
#define BTDM_CONFIG_VERSION 0x20260911
|
||||
#define BTDM_CONFIG_MAGIC_VALUE 0x5a5aa5a5
|
||||
|
||||
/* Types definition
|
||||
@@ -128,6 +128,7 @@ typedef struct {
|
||||
uint8_t task_prio; /*!< Priority of the Bluetooth controller task */
|
||||
uint8_t task_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */
|
||||
uint8_t hci_cmd_num; /*!< HCI command buffer number */
|
||||
uint8_t nonblocking_cmd_buf; /*!< Non-blocking mode for command buffer allocation */
|
||||
uint8_t sleep_en; /*!< Enable sleep functionality */
|
||||
uint8_t version_num; /*!< Hardware version number of this chip */
|
||||
uint8_t bluetooth_mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */
|
||||
@@ -167,6 +168,7 @@ typedef struct {
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
@@ -184,6 +186,7 @@ typedef struct {
|
||||
.task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
|
||||
.task_run_cpu = CONFIG_BT_CTRL_PINNED_TO_CORE, \
|
||||
.hci_cmd_num = CONFIG_BT_CTRL_HCI_CMD_NUM, \
|
||||
.nonblocking_cmd_buf = UC_BT_CTRL_NONBLOCK_CMD_BUF, \
|
||||
.sleep_en = UC_BT_CTRL_SLEEP_ENABLE, \
|
||||
.version_num = 0, \
|
||||
.bluetooth_mode = BTDM_CONTROLLER_MODE_EFF, \
|
||||
|
||||
@@ -295,6 +295,41 @@ static int bredr_psa_gen_keypair(bool p256, uint8_t *public_key, uint8_t *privat
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CVE-2018-5383: validate the peer's public key is a valid point on the curve
|
||||
* before using it in the DH computation. PSA validates the point (rejects the
|
||||
* point at infinity and out-of-range coordinates) when importing it as a public key.
|
||||
*/
|
||||
static int bredr_psa_validate_peer_pubkey(bool p256, const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y)
|
||||
{
|
||||
const size_t coord_len = p256 ? BREDR_P256_COORD_LEN : BREDR_P192_COORD_LEN;
|
||||
const size_t pub_len = p256 ? BREDR_PUB_KEY_LEN_P256 : BREDR_PUB_KEY_LEN_P192;
|
||||
|
||||
uint8_t pk[BREDR_PUB_KEY_LEN_P256]; /* uncompressed: 0x04 || X || Y */
|
||||
|
||||
pk[0] = 0x04;
|
||||
btdm_swap_buf(&pk[1], peer_pub_key_x, coord_len);
|
||||
btdm_swap_buf(&pk[1 + coord_len], peer_pub_key_y, coord_len);
|
||||
|
||||
psa_key_attributes_t pub_attr = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t pub_key_id = 0;
|
||||
psa_status_t pub_status;
|
||||
|
||||
psa_set_key_type(&pub_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
|
||||
psa_set_key_bits(&pub_attr, p256 ? 256 : 192);
|
||||
psa_set_key_usage_flags(&pub_attr, 0);
|
||||
|
||||
pub_status = psa_import_key(&pub_attr, pk, pub_len, &pub_key_id);
|
||||
psa_reset_key_attributes(&pub_attr);
|
||||
if (pub_status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG_BREDR_CRYPTO, "invalid peer public key: psa_import_key failed: %d", (int)pub_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
psa_destroy_key(pub_key_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bredr_psa_gen_dhkey(bool p256, const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y,
|
||||
const uint8_t *our_priv_key, uint8_t *out_dhkey)
|
||||
{
|
||||
@@ -306,11 +341,18 @@ static int bredr_psa_gen_dhkey(bool p256, const uint8_t *peer_pub_key_x, const u
|
||||
uint8_t pk[65];
|
||||
uint8_t dh[32];
|
||||
|
||||
btdm_swap_buf(priv, our_priv_key, priv_len);
|
||||
/* Validate the peer's public key before using it in the DH computation. */
|
||||
if (bredr_psa_validate_peer_pubkey(p256, peer_pub_key_x, peer_pub_key_y) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reconstruct the peer public key in uncompressed form (0x04 || X || Y). */
|
||||
pk[0] = 0x04;
|
||||
btdm_swap_buf(&pk[1], peer_pub_key_x, coord_len);
|
||||
btdm_swap_buf(&pk[1 + coord_len], peer_pub_key_y, coord_len);
|
||||
|
||||
btdm_swap_buf(priv, our_priv_key, priv_len);
|
||||
|
||||
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t key_id = 0;
|
||||
psa_status_t status;
|
||||
|
||||
@@ -24,6 +24,12 @@ extern "C" {
|
||||
|
||||
#define UC_BT_CTRL_TASK_STACK_SIZE CONFIG_BT_CTRL_TASK_STACK_SIZE
|
||||
|
||||
#ifdef CONFIG_BT_CTRL_NONBLOCK_CMD_BUF
|
||||
#define UC_BT_CTRL_NONBLOCK_CMD_BUF CONFIG_BT_CTRL_NONBLOCK_CMD_BUF
|
||||
#else
|
||||
#define UC_BT_CTRL_NONBLOCK_CMD_BUF (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
|
||||
#define UC_HCI_UART_EN CONFIG_BT_CTRL_HCI_INTERFACE_USE_UART
|
||||
#else
|
||||
|
||||
@@ -133,4 +133,12 @@ menu "Bluetooth controller HCI"
|
||||
Deprecated: this option is no longer used after HCI UART DMA
|
||||
switched to UHCI driver APIs, and will be removed in a future release.
|
||||
|
||||
config BT_CTRL_NONBLOCK_CMD_BUF
|
||||
bool "Return NULL when no HCI command buffer is available instead of blocking"
|
||||
default y if BT_CTRL_UART_HCI_DMA_MODE || BT_NIMBLE_ENABLED
|
||||
default n
|
||||
help
|
||||
By default, the API will block if no HCI command buffer is available.
|
||||
It is recommended to enable this option when HCI Tx and Rx processing run within the same task.
|
||||
Otherwise, the task may deadlock.
|
||||
endmenu
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
#define HCI_H4_SM_W4_HEADER 1
|
||||
#define HCI_H4_SM_W4_PAYLOAD 2
|
||||
#define HCI_H4_SM_COMPLETED 3
|
||||
#define HCI_H4_SM_WAIT_RESET 4
|
||||
|
||||
/* Buffer allocation failed. The stream is still in sync, so the state machine
|
||||
* is kept as is and the allocation is retried on the next pass.
|
||||
*/
|
||||
#define HCI_H4_ERR_MEM (-1)
|
||||
/* The stream cannot be parsed anymore, the current packet has to be dropped. */
|
||||
#define HCI_H4_ERR_SYNC_LOSS (-2)
|
||||
|
||||
#define TAG "HCI_H4"
|
||||
|
||||
@@ -78,7 +86,7 @@ hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
|
||||
#endif // (!CONFIG_BT_CONTROLLER_ENABLED)
|
||||
default:
|
||||
/* !TODO: Sync loss. Need to wait for reset. */
|
||||
return -1;
|
||||
return HCI_H4_ERR_SYNC_LOSS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -129,7 +137,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->cmd, 0, 0);
|
||||
h4sm->pkt = h4sm->allocs->cmd();
|
||||
if (!h4sm->pkt) {
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
|
||||
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
|
||||
@@ -143,7 +151,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
|
||||
h4sm->pkt = h4sm->allocs->bredr_acl(conn_handle);
|
||||
if (!h4sm->pkt) {
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
memcpy(h4sm->pkt->data, h4sm->hdr, h4sm->len);
|
||||
break;
|
||||
@@ -153,17 +161,20 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
if (HCI_INTERNAL_CONN_IS_BLE(conn_handle)) {
|
||||
h4sm->om = h4sm->allocs->acl();
|
||||
if (!h4sm->om) {
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
|
||||
if (ble_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len)) {
|
||||
return -1;
|
||||
/* Release the mbuf so that the retry starts from a clean state. */
|
||||
h4sm->frees->acl(h4sm->om);
|
||||
h4sm->om = NULL;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
h4sm->exp_len = btdm_get_le16(&h4sm->hdr[2]) + 4;
|
||||
break;
|
||||
}
|
||||
#endif // UC_BT_CTRL_BLE_IS_ENABLE
|
||||
return -1;
|
||||
return HCI_H4_ERR_SYNC_LOSS;
|
||||
#if UC_BT_CTRL_BR_EDR_IS_ENABLE
|
||||
case HCI_H4_SYNC:
|
||||
conn_handle = btdm_get_le16(&h4sm->hdr[0]) & HCI_INTERNAL_CONN_MASK;
|
||||
@@ -214,7 +225,7 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
} else {
|
||||
h4sm->buf = h4sm->allocs->evt(0);
|
||||
if (!h4sm->buf) {
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,14 +241,14 @@ hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
h4sm->exp_len = (btdm_get_le16(&h4sm->hdr[2]) & 0x3fff) + 4;
|
||||
h4sm->buf = h4sm->allocs->iso(h4sm->exp_len);
|
||||
if (!h4sm->buf) {
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
|
||||
memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
|
||||
break;
|
||||
#endif // CONFIG_BT_LE_ISO_SUPPORT
|
||||
default:
|
||||
return -2;
|
||||
return HCI_H4_ERR_SYNC_LOSS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -288,13 +299,13 @@ hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
|
||||
len = BLE_MBUF_PKTLEN(h4sm->om) - mbuf_len;
|
||||
h4sm->len += len;
|
||||
hci_h4_ib_consume(ib, len);
|
||||
return -1;
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
}
|
||||
#endif // UC_BT_CTRL_BLE_IS_ENABLE
|
||||
break;
|
||||
default:
|
||||
return -2;
|
||||
return HCI_H4_ERR_SYNC_LOSS;
|
||||
}
|
||||
|
||||
h4sm->len += len;
|
||||
@@ -389,6 +400,67 @@ hci_h4_sm_completed(struct hci_h4_sm *h4sm)
|
||||
}
|
||||
}
|
||||
|
||||
/* H4 type + HCI Reset (opcode 0x0C03, plen 0). */
|
||||
static const uint8_t s_hci_h4_reset_pattern[] = {HCI_H4_CMD, 0x03, 0x0C, 0x00};
|
||||
|
||||
static int
|
||||
hci_h4_sm_dispatch_reset_cmd(struct hci_h4_sm *h4sm)
|
||||
{
|
||||
HCI_TRANS_ASSERT(h4sm->allocs && h4sm->allocs->cmd, 0, 0);
|
||||
h4sm->pkt_type = HCI_H4_CMD;
|
||||
h4sm->pkt = h4sm->allocs->cmd();
|
||||
if (!h4sm->pkt) {
|
||||
return HCI_H4_ERR_MEM;
|
||||
}
|
||||
|
||||
memcpy(h4sm->pkt->data, &s_hci_h4_reset_pattern[1], 3);
|
||||
h4sm->len = 3;
|
||||
hci_h4_sm_completed(h4sm);
|
||||
h4sm->reset_match_idx = 0;
|
||||
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hci_h4_sm_wait_for_reset(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Pattern already fully matched; retry delivery after a previous OOM. */
|
||||
if (h4sm->reset_match_idx == sizeof(s_hci_h4_reset_pattern)) {
|
||||
return hci_h4_sm_dispatch_reset_cmd(h4sm);
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < ib->len; i++) {
|
||||
if (ib->buf[i] == s_hci_h4_reset_pattern[h4sm->reset_match_idx]) {
|
||||
h4sm->reset_match_idx++;
|
||||
} else {
|
||||
if (ib->buf[i] == s_hci_h4_reset_pattern[0]) {
|
||||
h4sm->reset_match_idx = 1;
|
||||
} else {
|
||||
h4sm->reset_match_idx = 0;
|
||||
}
|
||||
}
|
||||
if (h4sm->reset_match_idx == sizeof(s_hci_h4_reset_pattern)) {
|
||||
hci_h4_ib_consume(ib, i + 1);
|
||||
rc = hci_h4_sm_dispatch_reset_cmd(h4sm);
|
||||
if (rc == HCI_H4_ERR_MEM) {
|
||||
/* Reset bytes are already consumed; keep idx at 4 and retry alloc. */
|
||||
h4sm->state = HCI_H4_SM_WAIT_RESET;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (h4sm->reset_match_idx) {
|
||||
/* Need more data */
|
||||
hci_h4_ib_consume(ib, ib->len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return HCI_H4_ERR_SYNC_LOSS;
|
||||
}
|
||||
|
||||
static int
|
||||
hci_h4_sm_free_buf(struct hci_h4_sm *h4sm)
|
||||
{
|
||||
@@ -466,7 +538,8 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
|
||||
switch (h4sm->state) {
|
||||
case HCI_H4_SM_W4_PKT_TYPE:
|
||||
if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) {
|
||||
return -1;
|
||||
rc = HCI_H4_ERR_SYNC_LOSS;
|
||||
break;
|
||||
}
|
||||
|
||||
hci_h4_ib_consume(&ib, 1);
|
||||
@@ -492,27 +565,32 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
|
||||
hci_h4_sm_completed(h4sm);
|
||||
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
|
||||
break;
|
||||
case HCI_H4_SM_WAIT_RESET:
|
||||
rc = hci_h4_sm_wait_for_reset(h4sm, &ib);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
rc = HCI_H4_ERR_SYNC_LOSS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
if ((rc < 0) && (rc != HCI_H4_ERR_MEM)) {
|
||||
hci_h4_sm_free_buf(h4sm);
|
||||
h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
|
||||
return -1;
|
||||
h4sm->reset_match_idx = 0;
|
||||
h4sm->state = HCI_H4_SM_WAIT_RESET;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Calculate consumed bytes
|
||||
*
|
||||
* Note: we should always consume some bytes unless there is an oom error.
|
||||
* It's also possible that we have an oom error but already consumed some
|
||||
* data, in such case just return success and error will be returned on next
|
||||
* pass.
|
||||
* On oom the state machine is left untouched so that the allocation is
|
||||
* retried on the next pass, and the number of bytes actually taken from
|
||||
* `buf` is reported to let the caller resubmit the remaining data.
|
||||
*/
|
||||
len = len - ib.len;
|
||||
if (len == 0) {
|
||||
HCI_TRANS_ASSERT((rc < 0), rc, ib.len);
|
||||
return -1;
|
||||
HCI_TRANS_ASSERT((rc == HCI_H4_ERR_MEM), rc, ib.len);
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
@@ -53,6 +53,9 @@ typedef struct {
|
||||
uhci_transmit_buffer_info_t *tx_segments; /*!< Scratch array of UHCI TX segments for one multi-buffer transaction. */
|
||||
volatile hci_trans_tx_state_t hci_tx_state; /*!< Only one HCI packet is in flight (tx-list entries cannot be mixed). */
|
||||
volatile bool rx_copy_overflow; /*!< Set in ISR when rx_copy_ringbuf cannot accept a DMA slice. */
|
||||
uint8_t *rx_pending_item; /*!< Original xRingbufferReceive() pointer; held until H4 consumes the slice. */
|
||||
uint8_t *rx_pending_data; /*!< Unparsed remainder of rx_pending_item (item + already consumed). */
|
||||
size_t rx_pending_len; /*!< Bytes still to feed to hci_h4_sm_rx() from rx_pending_data. */
|
||||
} hci_driver_uart_dma_env_t;
|
||||
|
||||
/* Max UHCI TX segments in one uhci_multi_buffer_transmit(); maps to max_transmit_buffer_count. */
|
||||
@@ -77,7 +80,6 @@ typedef struct {
|
||||
*/
|
||||
#define HCI_UHCI_RX_DESC_MEM (UC_BT_CTRL_HCI_TRANS_RX_MEM_NUM * HCI_RX_DMA_RING_SIZE)
|
||||
#define HCI_RX_COPY_RINGBUF_SIZE HCI_RX_DMA_RING_SIZE
|
||||
|
||||
static const char *TAG = "uart_dma";
|
||||
static hci_driver_uart_dma_env_t s_hci_driver_uart_dma_env;
|
||||
static struct hci_h4_sm s_hci_driver_uart_h4_sm;
|
||||
@@ -85,6 +87,18 @@ static portMUX_TYPE s_hci_tx_state_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static int hci_driver_uart_dma_tx_submit(void);
|
||||
|
||||
static void
|
||||
hci_driver_uart_dma_rx_pending_clear(void)
|
||||
{
|
||||
if (s_hci_driver_uart_dma_env.rx_pending_item && s_hci_driver_uart_dma_env.rx_copy_ringbuf) {
|
||||
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf,
|
||||
s_hci_driver_uart_dma_env.rx_pending_item);
|
||||
}
|
||||
s_hci_driver_uart_dma_env.rx_pending_item = NULL;
|
||||
s_hci_driver_uart_dma_env.rx_pending_data = NULL;
|
||||
s_hci_driver_uart_dma_env.rx_pending_len = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the DMA ring, software RX ringbuf and TX segment scratch array.
|
||||
*
|
||||
@@ -94,6 +108,8 @@ static int hci_driver_uart_dma_tx_submit(void);
|
||||
static void
|
||||
hci_driver_uart_dma_memory_deinit(void)
|
||||
{
|
||||
hci_driver_uart_dma_rx_pending_clear();
|
||||
|
||||
if (s_hci_driver_uart_dma_env.rx_copy_ringbuf) {
|
||||
vRingbufferDelete(s_hci_driver_uart_dma_env.rx_copy_ringbuf);
|
||||
s_hci_driver_uart_dma_env.rx_copy_ringbuf = NULL;
|
||||
@@ -423,18 +439,55 @@ hci_driver_uart_dma_h4_frame_cb(uint8_t pkt_type, void *data, int pkt_len, uint8
|
||||
return forward_cb(pkt_type, data, pkt_len, HCI_DRIVER_DIR_H2C, data_source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Feed one H4 slice and either return the ringbuf item or hold the remainder.
|
||||
*
|
||||
* @return true if the caller may continue with the next ringbuf item.
|
||||
* false if H4 consumed fewer bytes than offered (typically OOM); the
|
||||
* unparsed tail is stored in rx_pending_* and must be retried
|
||||
* on the next process_rx() entry.
|
||||
*/
|
||||
static bool
|
||||
hci_driver_uart_dma_h4_feed(uint8_t *item, uint8_t *data, size_t item_size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ESP_LOGD(TAG, "uart rx");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, item_size, ESP_LOG_DEBUG);
|
||||
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, data, (uint16_t)item_size);
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, "parse rx data error!\n");
|
||||
#if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
|
||||
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
} else if ((size_t)ret < item_size) {
|
||||
/* Keep the ringbuf item checked out so the unparsed bytes stay valid. */
|
||||
s_hci_driver_uart_dma_env.rx_pending_item = item;
|
||||
s_hci_driver_uart_dma_env.rx_pending_data = data + ret;
|
||||
s_hci_driver_uart_dma_env.rx_pending_len = item_size - (size_t)ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf, item);
|
||||
s_hci_driver_uart_dma_env.rx_pending_item = NULL;
|
||||
s_hci_driver_uart_dma_env.rx_pending_data = NULL;
|
||||
s_hci_driver_uart_dma_env.rx_pending_len = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Drain the software RX ringbuf into the H4 state machine.
|
||||
*
|
||||
* Timeout is 0: the process task is already woken by process_sem. Chunks may be
|
||||
* one DMA node or a short EOF tail; H4 concatenates them into HCI packets.
|
||||
* If H4 returns a partial consume, the remainder is retried first on the next call.
|
||||
*/
|
||||
static void
|
||||
hci_driver_uart_dma_process_rx(void)
|
||||
{
|
||||
size_t item_size;
|
||||
uint8_t *rx_data;
|
||||
int ret;
|
||||
|
||||
if (s_hci_driver_uart_dma_env.rx_copy_overflow) {
|
||||
ESP_LOGE(TAG, "RX software ring buffer overflow, HCI stream may lose sync");
|
||||
@@ -444,17 +497,17 @@ hci_driver_uart_dma_process_rx(void)
|
||||
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
}
|
||||
|
||||
if (s_hci_driver_uart_dma_env.rx_pending_item) {
|
||||
if (!hci_driver_uart_dma_h4_feed(s_hci_driver_uart_dma_env.rx_pending_item,
|
||||
s_hci_driver_uart_dma_env.rx_pending_data,
|
||||
s_hci_driver_uart_dma_env.rx_pending_len)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while ((rx_data = xRingbufferReceive(s_hci_driver_uart_dma_env.rx_copy_ringbuf, &item_size, 0)) != NULL) {
|
||||
ESP_LOGD(TAG, "uart rx");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, item_size, ESP_LOG_DEBUG);
|
||||
ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, (uint16_t)item_size);
|
||||
/* Return the item before parsing the next slice so the ringbuf can accept more ISR copies. */
|
||||
vRingbufferReturnItem(s_hci_driver_uart_dma_env.rx_copy_ringbuf, rx_data);
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, "parse rx data error!\n");
|
||||
#if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR);
|
||||
#endif // #if UC_BT_CTRL_BLE_IS_ENABLE
|
||||
if (!hci_driver_uart_dma_h4_feed(rx_data, rx_data, item_size)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ struct hci_h4_sm {
|
||||
uint8_t state;
|
||||
uint8_t pkt_type;
|
||||
uint8_t min_len;
|
||||
uint8_t reset_match_idx;
|
||||
uint16_t len;
|
||||
uint16_t exp_len;
|
||||
uint8_t hdr[4];
|
||||
@@ -115,6 +116,17 @@ void hci_h4_sm_init(struct hci_h4_sm *h4sm,
|
||||
const struct hci_h4_frees *frees,
|
||||
hci_h4_frame_cb *frame_cb);
|
||||
|
||||
/**
|
||||
* @brief Feed received H4 data into the parser state machine.
|
||||
*
|
||||
* @return Number of bytes of `buf` that have been parsed, which may be less
|
||||
* than `len` (0 included) when a buffer allocation failed. The
|
||||
* unparsed data has to be submitted again, the allocation is retried
|
||||
* on the next call.
|
||||
* A negative value means the stream cannot be parsed anymore and the
|
||||
* current packet has been dropped, the caller should report a sync
|
||||
* loss.
|
||||
*/
|
||||
int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len);
|
||||
|
||||
#endif /* _HCI_H4_H_ */
|
||||
|
||||
Reference in New Issue
Block a user