Skip to content

Commit bbdf13d

Browse files
cvinayaknashif
authored andcommitted
Bluetooth: controller: Fix control tx queue handling
Fix control tx queue handling to correctly pause control PDU responses during encryption setup. Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent f3e9177 commit bbdf13d

File tree

1 file changed

+74
-9
lines changed
  • subsys/bluetooth/controller/ll_sw

1 file changed

+74
-9
lines changed

subsys/bluetooth/controller/ll_sw/ctrl.c

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9948,8 +9948,15 @@ static void prepare_pdu_data_tx(struct connection *conn,
99489948

99499949
if (!conn->pkt_tx_ctrl &&
99509950
(conn->pkt_tx_head != conn->pkt_tx_data)) {
9951-
conn->pkt_tx_ctrl = conn->pkt_tx_ctrl_last =
9952-
conn->pkt_tx_head;
9951+
struct pdu_data *pdu_data_tx;
9952+
9953+
pdu_data_tx = (void *)conn->pkt_tx_head->pdu_data;
9954+
if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
9955+
(pdu_data_tx->llctrl.opcode !=
9956+
PDU_DATA_LLCTRL_TYPE_ENC_REQ)) {
9957+
conn->pkt_tx_ctrl = conn->pkt_tx_ctrl_last =
9958+
conn->pkt_tx_head;
9959+
}
99539960
}
99549961
}
99559962

@@ -9970,8 +9977,9 @@ static void ctrl_tx_last_enqueue(struct connection *conn,
99709977
conn->pkt_tx_ctrl_last = node_tx;
99719978
}
99729979

9973-
static void ctrl_tx_enqueue(struct connection *conn,
9974-
struct radio_pdu_node_tx *node_tx)
9980+
static inline void ctrl_tx_pause_enqueue(struct connection *conn,
9981+
struct radio_pdu_node_tx *node_tx,
9982+
bool pause)
99759983
{
99769984
/* check if a packet was tx-ed and not acked by peer */
99779985
if (
@@ -9999,9 +10007,27 @@ static void ctrl_tx_enqueue(struct connection *conn,
999910007
if (!conn->pkt_tx_ctrl) {
1000010008
node_tx->next = conn->pkt_tx_head->next;
1000110009
conn->pkt_tx_head->next = node_tx;
10002-
conn->pkt_tx_ctrl = node_tx;
10003-
conn->pkt_tx_ctrl_last = node_tx;
10010+
10011+
/* If in Encryption Procedure, other control PDUs,
10012+
* Feature Rsp and Version Ind, are placed before data
10013+
* marker and after control last marker. Hence, if no
10014+
* control marker i.e. this is the first control PDU and
10015+
* to be paused, do not set the control marker. A valid
10016+
* control PDU in Encryption Procedure that is not
10017+
* implicitly paused, will set the control and control
10018+
* last marker.
10019+
*/
10020+
if (!pause) {
10021+
conn->pkt_tx_ctrl = node_tx;
10022+
conn->pkt_tx_ctrl_last = node_tx;
10023+
}
1000410024
} else {
10025+
/* ENC_REQ PDU is always allocated from data pool, hence
10026+
* the head can not have the control marker, and pause
10027+
* be true.
10028+
*/
10029+
LL_ASSERT(!pause);
10030+
1000510031
ctrl_tx_last_enqueue(conn, node_tx);
1000610032
}
1000710033
} else {
@@ -10013,9 +10039,13 @@ static void ctrl_tx_enqueue(struct connection *conn,
1001310039
if (!conn->pkt_tx_ctrl) {
1001410040
node_tx->next = conn->pkt_tx_head;
1001510041
conn->pkt_tx_head = node_tx;
10016-
conn->pkt_tx_ctrl = node_tx;
10017-
conn->pkt_tx_ctrl_last = node_tx;
10042+
if (!pause) {
10043+
conn->pkt_tx_ctrl = node_tx;
10044+
conn->pkt_tx_ctrl_last = node_tx;
10045+
}
1001810046
} else {
10047+
LL_ASSERT(!pause);
10048+
1001910049
ctrl_tx_last_enqueue(conn, node_tx);
1002010050
}
1002110051
}
@@ -10026,19 +10056,54 @@ static void ctrl_tx_enqueue(struct connection *conn,
1002610056
}
1002710057
}
1002810058

10059+
static void ctrl_tx_enqueue(struct connection *conn,
10060+
struct radio_pdu_node_tx *node_tx)
10061+
{
10062+
ctrl_tx_pause_enqueue(conn, node_tx, false);
10063+
}
10064+
1002910065
static void ctrl_tx_sec_enqueue(struct connection *conn,
1003010066
struct radio_pdu_node_tx *node_tx)
1003110067
{
1003210068
if (conn->pause_tx) {
1003310069
if (!conn->pkt_tx_ctrl) {
10070+
/* As data PDU tx is paused and no control PDU in queue,
10071+
* its safe to add new control PDU at head.
10072+
* Note, here the PDUs are stacked, not queued. Last In
10073+
* First Out.
10074+
*/
1003410075
node_tx->next = conn->pkt_tx_head;
1003510076
conn->pkt_tx_head = node_tx;
1003610077
} else {
10078+
/* As data PDU tx is paused and there are control PDUs
10079+
* in the queue, add it after control PDUs last marker
10080+
* and before the data start marker.
10081+
* Note, here the PDUs are stacked, not queued. Last In
10082+
* First Out.
10083+
*/
1003710084
node_tx->next = conn->pkt_tx_ctrl_last->next;
1003810085
conn->pkt_tx_ctrl_last->next = node_tx;
1003910086
}
1004010087
} else {
10041-
ctrl_tx_enqueue(conn, node_tx);
10088+
bool pause = false;
10089+
10090+
/* check if Encryption Request is at head, it may have been
10091+
* transmitted and not ack-ed. Hence, enqueue this control PDU
10092+
* after control last marker and before data marker.
10093+
* This way it is paused until Encryption Setup completes.
10094+
*/
10095+
if (conn->pkt_tx_head) {
10096+
struct pdu_data *pdu_data_tx;
10097+
10098+
pdu_data_tx = (void *)conn->pkt_tx_head->pdu_data;
10099+
if ((pdu_data_tx->ll_id == PDU_DATA_LLID_CTRL) &&
10100+
(pdu_data_tx->llctrl.opcode ==
10101+
PDU_DATA_LLCTRL_TYPE_ENC_REQ)) {
10102+
pause = true;
10103+
}
10104+
}
10105+
10106+
ctrl_tx_pause_enqueue(conn, node_tx, pause);
1004210107
}
1004310108
}
1004410109

0 commit comments

Comments
 (0)