Bluetooth: controller: Fix regression in central initiated terminate
Fix regression in central initiated terminate introduced in
commit 3a80785947
("Bluetooth: controller: Fix connection
terminate to happen on event done").
The regression caused an additional central connection event
transmitting PDU after the previous connection event had
received acknowledgment for the terminate_ind PDU from the
peripheral.
Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
b8dfecfdc5
commit
a4d2e062cb
3 changed files with 33 additions and 12 deletions
|
@ -913,6 +913,7 @@ uint8_t ll_adv_enable(uint8_t enable)
|
||||||
conn->llcp_feature.features_peer = 0;
|
conn->llcp_feature.features_peer = 0;
|
||||||
conn->llcp_version.req = conn->llcp_version.ack = 0;
|
conn->llcp_version.req = conn->llcp_version.ack = 0;
|
||||||
conn->llcp_version.tx = conn->llcp_version.rx = 0;
|
conn->llcp_version.tx = conn->llcp_version.rx = 0;
|
||||||
|
conn->llcp_terminate.req = conn->llcp_terminate.ack = 0;
|
||||||
conn->llcp_terminate.reason_final = 0;
|
conn->llcp_terminate.reason_final = 0;
|
||||||
/* NOTE: use allocated link for generating dedicated
|
/* NOTE: use allocated link for generating dedicated
|
||||||
* terminate ind rx node
|
* terminate ind rx node
|
||||||
|
|
|
@ -165,11 +165,14 @@ static uint8_t force_md_cnt_calc(struct lll_conn *lll_conn, uint32_t tx_rate);
|
||||||
offsetof(struct pdu_data, llctrl) + \
|
offsetof(struct pdu_data, llctrl) + \
|
||||||
sizeof(struct pdu_data_llctrl))
|
sizeof(struct pdu_data_llctrl))
|
||||||
|
|
||||||
|
/* Terminate procedure state values */
|
||||||
|
#define TERM_REQ 1
|
||||||
|
#define TERM_ACKED 3
|
||||||
|
|
||||||
static MFIFO_DEFINE(conn_tx, sizeof(struct lll_tx), CONFIG_BT_CTLR_TX_BUFFERS);
|
static MFIFO_DEFINE(conn_tx, sizeof(struct lll_tx), CONFIG_BT_CTLR_TX_BUFFERS);
|
||||||
static MFIFO_DEFINE(conn_ack, sizeof(struct lll_tx),
|
static MFIFO_DEFINE(conn_ack, sizeof(struct lll_tx),
|
||||||
(CONFIG_BT_CTLR_TX_BUFFERS + CONN_TX_CTRL_BUFFERS));
|
(CONFIG_BT_CTLR_TX_BUFFERS + CONN_TX_CTRL_BUFFERS));
|
||||||
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
void *free;
|
void *free;
|
||||||
uint8_t pool[CONN_TX_BUF_SIZE * CONFIG_BT_CTLR_TX_BUFFERS];
|
uint8_t pool[CONN_TX_BUF_SIZE * CONFIG_BT_CTLR_TX_BUFFERS];
|
||||||
|
@ -458,18 +461,21 @@ uint8_t ll_terminate_ind_send(uint16_t handle, uint8_t reason)
|
||||||
{
|
{
|
||||||
struct ll_conn *conn;
|
struct ll_conn *conn;
|
||||||
|
|
||||||
if (!is_valid_disconnect_reason(reason)) {
|
|
||||||
return BT_HCI_ERR_INVALID_PARAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn = ll_connected_get(handle);
|
conn = ll_connected_get(handle);
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->llcp_terminate.reason_own = reason;
|
if (conn->llcp_terminate.req != conn->llcp_terminate.ack) {
|
||||||
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
conn->llcp_terminate.req++;
|
if (!is_valid_disconnect_reason(reason)) {
|
||||||
|
return BT_HCI_ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->llcp_terminate.reason_own = reason;
|
||||||
|
conn->llcp_terminate.req++; /* (req - ack) == 1, TERM_REQ */
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn->lll.role) {
|
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn->lll.role) {
|
||||||
ull_slave_latency_cancel(conn, handle);
|
ull_slave_latency_cancel(conn, handle);
|
||||||
|
@ -1109,15 +1115,18 @@ int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy)
|
||||||
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_LE_ENC */
|
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_LE_ENC */
|
||||||
|
|
||||||
/* Terminate Procedure Request */
|
/* Terminate Procedure Request */
|
||||||
if (conn->llcp_terminate.ack != conn->llcp_terminate.req) {
|
if (((conn->llcp_terminate.req - conn->llcp_terminate.ack) & 0xFF) ==
|
||||||
|
TERM_REQ) {
|
||||||
struct node_tx *tx;
|
struct node_tx *tx;
|
||||||
|
|
||||||
tx = mem_acquire(&mem_conn_tx_ctrl.free);
|
tx = mem_acquire(&mem_conn_tx_ctrl.free);
|
||||||
if (tx) {
|
if (tx) {
|
||||||
struct pdu_data *pdu_tx = (void *)tx->pdu;
|
struct pdu_data *pdu_tx = (void *)tx->pdu;
|
||||||
|
|
||||||
/* Terminate Procedure acked */
|
/* Terminate Procedure initiated,
|
||||||
conn->llcp_terminate.ack = conn->llcp_terminate.req;
|
* make (req - ack) == 2
|
||||||
|
*/
|
||||||
|
conn->llcp_terminate.ack--;
|
||||||
|
|
||||||
/* place the terminate ind packet in tx queue */
|
/* place the terminate ind packet in tx queue */
|
||||||
pdu_tx->ll_id = PDU_DATA_LLID_CTRL;
|
pdu_tx->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
|
@ -1212,8 +1221,10 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||||
|
|
||||||
/* Master transmitted ack for the received terminate ind or
|
/* Peripheral received terminate ind or
|
||||||
* Slave received terminate ind or MIC failure
|
* Central received ack for the transmitted terminate ind or
|
||||||
|
* Central transmitted ack for the received terminate ind or
|
||||||
|
* there has been MIC failure
|
||||||
*/
|
*/
|
||||||
reason_final = conn->llcp_terminate.reason_final;
|
reason_final = conn->llcp_terminate.reason_final;
|
||||||
if (reason_final && (
|
if (reason_final && (
|
||||||
|
@ -1223,6 +1234,9 @@ void ull_conn_done(struct node_rx_event_done *done)
|
||||||
0 ||
|
0 ||
|
||||||
#endif /* CONFIG_BT_PERIPHERAL */
|
#endif /* CONFIG_BT_PERIPHERAL */
|
||||||
#if defined(CONFIG_BT_CENTRAL)
|
#if defined(CONFIG_BT_CENTRAL)
|
||||||
|
(((conn->llcp_terminate.req -
|
||||||
|
conn->llcp_terminate.ack) & 0xFF) ==
|
||||||
|
TERM_ACKED) ||
|
||||||
conn->master.terminate_ack ||
|
conn->master.terminate_ack ||
|
||||||
(reason_final == BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL)
|
(reason_final == BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL)
|
||||||
#else /* CONFIG_BT_CENTRAL */
|
#else /* CONFIG_BT_CENTRAL */
|
||||||
|
@ -5576,6 +5590,11 @@ static inline void ctrl_tx_ack(struct ll_conn *conn, struct node_tx **tx,
|
||||||
conn->llcp_terminate.reason_final =
|
conn->llcp_terminate.reason_final =
|
||||||
pdu_tx->llctrl.terminate_ind.error_code;
|
pdu_tx->llctrl.terminate_ind.error_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make (req - ack) == 3, a state indicating terminate_ind has
|
||||||
|
* been ack-ed.
|
||||||
|
*/
|
||||||
|
conn->llcp_terminate.ack--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -261,6 +261,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window,
|
||||||
conn->llcp_feature.features_peer = 0;
|
conn->llcp_feature.features_peer = 0;
|
||||||
conn->llcp_version.req = conn->llcp_version.ack = 0;
|
conn->llcp_version.req = conn->llcp_version.ack = 0;
|
||||||
conn->llcp_version.tx = conn->llcp_version.rx = 0U;
|
conn->llcp_version.tx = conn->llcp_version.rx = 0U;
|
||||||
|
conn->llcp_terminate.req = conn->llcp_terminate.ack = 0U;
|
||||||
conn->llcp_terminate.reason_final = 0U;
|
conn->llcp_terminate.reason_final = 0U;
|
||||||
/* NOTE: use allocated link for generating dedicated
|
/* NOTE: use allocated link for generating dedicated
|
||||||
* terminate ind rx node
|
* terminate ind rx node
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue