Skip to content

Commit a4d2e06

Browse files
cvinayakcarlescufi
authored andcommitted
Bluetooth: controller: Fix regression in central initiated terminate
Fix regression in central initiated terminate introduced in commit 3a80785 ("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 <[email protected]>
1 parent b8dfecf commit a4d2e06

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

subsys/bluetooth/controller/ll_sw/ull_adv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ uint8_t ll_adv_enable(uint8_t enable)
913913
conn->llcp_feature.features_peer = 0;
914914
conn->llcp_version.req = conn->llcp_version.ack = 0;
915915
conn->llcp_version.tx = conn->llcp_version.rx = 0;
916+
conn->llcp_terminate.req = conn->llcp_terminate.ack = 0;
916917
conn->llcp_terminate.reason_final = 0;
917918
/* NOTE: use allocated link for generating dedicated
918919
* terminate ind rx node

subsys/bluetooth/controller/ll_sw/ull_conn.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,14 @@ static uint8_t force_md_cnt_calc(struct lll_conn *lll_conn, uint32_t tx_rate);
165165
offsetof(struct pdu_data, llctrl) + \
166166
sizeof(struct pdu_data_llctrl))
167167

168+
/* Terminate procedure state values */
169+
#define TERM_REQ 1
170+
#define TERM_ACKED 3
171+
168172
static MFIFO_DEFINE(conn_tx, sizeof(struct lll_tx), CONFIG_BT_CTLR_TX_BUFFERS);
169173
static MFIFO_DEFINE(conn_ack, sizeof(struct lll_tx),
170174
(CONFIG_BT_CTLR_TX_BUFFERS + CONN_TX_CTRL_BUFFERS));
171175

172-
173176
static struct {
174177
void *free;
175178
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)
458461
{
459462
struct ll_conn *conn;
460463

461-
if (!is_valid_disconnect_reason(reason)) {
462-
return BT_HCI_ERR_INVALID_PARAM;
463-
}
464-
465464
conn = ll_connected_get(handle);
466465
if (!conn) {
467466
return BT_HCI_ERR_UNKNOWN_CONN_ID;
468467
}
469468

470-
conn->llcp_terminate.reason_own = reason;
469+
if (conn->llcp_terminate.req != conn->llcp_terminate.ack) {
470+
return BT_HCI_ERR_CMD_DISALLOWED;
471+
}
471472

472-
conn->llcp_terminate.req++;
473+
if (!is_valid_disconnect_reason(reason)) {
474+
return BT_HCI_ERR_INVALID_PARAM;
475+
}
476+
477+
conn->llcp_terminate.reason_own = reason;
478+
conn->llcp_terminate.req++; /* (req - ack) == 1, TERM_REQ */
473479

474480
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn->lll.role) {
475481
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)
11091115
#endif /* CONFIG_BT_PERIPHERAL && CONFIG_BT_CTLR_LE_ENC */
11101116

11111117
/* Terminate Procedure Request */
1112-
if (conn->llcp_terminate.ack != conn->llcp_terminate.req) {
1118+
if (((conn->llcp_terminate.req - conn->llcp_terminate.ack) & 0xFF) ==
1119+
TERM_REQ) {
11131120
struct node_tx *tx;
11141121

11151122
tx = mem_acquire(&mem_conn_tx_ctrl.free);
11161123
if (tx) {
11171124
struct pdu_data *pdu_tx = (void *)tx->pdu;
11181125

1119-
/* Terminate Procedure acked */
1120-
conn->llcp_terminate.ack = conn->llcp_terminate.req;
1126+
/* Terminate Procedure initiated,
1127+
* make (req - ack) == 2
1128+
*/
1129+
conn->llcp_terminate.ack--;
11211130

11221131
/* place the terminate ind packet in tx queue */
11231132
pdu_tx->ll_id = PDU_DATA_LLID_CTRL;
@@ -1212,8 +1221,10 @@ void ull_conn_done(struct node_rx_event_done *done)
12121221
}
12131222
#endif /* CONFIG_BT_CTLR_LE_ENC */
12141223

1215-
/* Master transmitted ack for the received terminate ind or
1216-
* Slave received terminate ind or MIC failure
1224+
/* Peripheral received terminate ind or
1225+
* Central received ack for the transmitted terminate ind or
1226+
* Central transmitted ack for the received terminate ind or
1227+
* there has been MIC failure
12171228
*/
12181229
reason_final = conn->llcp_terminate.reason_final;
12191230
if (reason_final && (
@@ -1223,6 +1234,9 @@ void ull_conn_done(struct node_rx_event_done *done)
12231234
0 ||
12241235
#endif /* CONFIG_BT_PERIPHERAL */
12251236
#if defined(CONFIG_BT_CENTRAL)
1237+
(((conn->llcp_terminate.req -
1238+
conn->llcp_terminate.ack) & 0xFF) ==
1239+
TERM_ACKED) ||
12261240
conn->master.terminate_ack ||
12271241
(reason_final == BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL)
12281242
#else /* CONFIG_BT_CENTRAL */
@@ -5576,6 +5590,11 @@ static inline void ctrl_tx_ack(struct ll_conn *conn, struct node_tx **tx,
55765590
conn->llcp_terminate.reason_final =
55775591
pdu_tx->llctrl.terminate_ind.error_code;
55785592
}
5593+
5594+
/* Make (req - ack) == 3, a state indicating terminate_ind has
5595+
* been ack-ed.
5596+
*/
5597+
conn->llcp_terminate.ack--;
55795598
}
55805599
break;
55815600

subsys/bluetooth/controller/ll_sw/ull_master.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window,
261261
conn->llcp_feature.features_peer = 0;
262262
conn->llcp_version.req = conn->llcp_version.ack = 0;
263263
conn->llcp_version.tx = conn->llcp_version.rx = 0U;
264+
conn->llcp_terminate.req = conn->llcp_terminate.ack = 0U;
264265
conn->llcp_terminate.reason_final = 0U;
265266
/* NOTE: use allocated link for generating dedicated
266267
* terminate ind rx node

0 commit comments

Comments
 (0)