Skip to content

Commit fa619bd

Browse files
cvinayaknashif
authored andcommitted
Bluetooth: controller: Fix cmd disallowed and collision disconnects
Fix implementation to correctly cache the control procedures initiatable by local and peer. And, fix feature exchange and version information procedures from being disallowed by having then as cached requests to the controller. Relates to #15256. Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent 3ad9394 commit fa619bd

File tree

2 files changed

+99
-65
lines changed

2 files changed

+99
-65
lines changed

subsys/bluetooth/controller/ll_sw/ctrl.c

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,7 +2821,8 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
28212821
rsp = &pdu_data_rx->llctrl.feature_rsp;
28222822

28232823
/* AND the feature set to get Feature USED */
2824-
_radio.conn_curr->llcp_features &= feat_get(&rsp->features[0]);
2824+
_radio.conn_curr->llcp_feature.features &=
2825+
feat_get(&rsp->features[0]);
28252826

28262827
/* features exchanged */
28272828
_radio.conn_curr->common.fex_valid = 1U;
@@ -2830,6 +2831,8 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
28302831
*rx_enqueue = 1U;
28312832

28322833
/* Procedure complete */
2834+
_radio.conn_curr->llcp_feature.ack =
2835+
_radio.conn_curr->llcp_feature.req;
28332836
_radio.conn_curr->procedure_expire = 0U;
28342837
}
28352838
break;
@@ -7579,7 +7582,7 @@ static inline void event_enc_reject_prep(struct connection *conn,
75797582
pdu->ll_id = PDU_DATA_LLID_CTRL;
75807583

75817584
if (conn->common.fex_valid &&
7582-
(conn->llcp_features & BIT(BT_LE_FEAT_BIT_EXT_REJ_IND))) {
7585+
(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_EXT_REJ_IND))) {
75837586
struct pdu_data_llctrl_reject_ext_ind *p;
75847587

75857588
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
@@ -7744,12 +7747,17 @@ static inline void event_fex_prep(struct connection *conn)
77447747
{
77457748
struct radio_pdu_node_tx *node_tx;
77467749

7750+
/* If waiting for response, do nothing */
7751+
if (!((conn->llcp_feature.ack - conn->llcp_feature.req) & 0x01)) {
7752+
return;
7753+
}
7754+
77477755
if (conn->common.fex_valid) {
77487756
struct radio_pdu_node_rx *node_rx;
77497757
struct pdu_data *pdu_ctrl_rx;
77507758

77517759
/* procedure request acked */
7752-
conn->llcp_ack = conn->llcp_req;
7760+
conn->llcp_feature.ack = conn->llcp_feature.req;
77537761

77547762
/* Prepare the rx packet structure */
77557763
node_rx = packet_rx_reserve_get(2);
@@ -7768,11 +7776,11 @@ static inline void event_fex_prep(struct connection *conn)
77687776
(void)memset(&pdu_ctrl_rx->llctrl.feature_rsp.features[0], 0x00,
77697777
sizeof(pdu_ctrl_rx->llctrl.feature_rsp.features));
77707778
pdu_ctrl_rx->llctrl.feature_req.features[0] =
7771-
conn->llcp_features & 0xFF;
7779+
conn->llcp_feature.features & 0xFF;
77727780
pdu_ctrl_rx->llctrl.feature_req.features[1] =
7773-
(conn->llcp_features >> 8) & 0xFF;
7781+
(conn->llcp_feature.features >> 8) & 0xFF;
77747782
pdu_ctrl_rx->llctrl.feature_req.features[2] =
7775-
(conn->llcp_features >> 16) & 0xFF;
7783+
(conn->llcp_feature.features >> 16) & 0xFF;
77767784

77777785
/* enqueue feature rsp structure into rx queue */
77787786
packet_rx_enqueue();
@@ -7784,11 +7792,11 @@ static inline void event_fex_prep(struct connection *conn)
77847792
if (node_tx) {
77857793
struct pdu_data *pdu_ctrl_tx = (void *)node_tx->pdu_data;
77867794

7787-
/* procedure request acked */
7788-
conn->llcp_ack = conn->llcp_req;
7795+
/* procedure request acked, move to waiting state */
7796+
conn->llcp_feature.ack--;
77897797

77907798
/* use initial feature bitmap */
7791-
conn->llcp_features = LL_FEAT;
7799+
conn->llcp_feature.features = LL_FEAT;
77927800

77937801
/* place the feature exchange req packet as next in tx queue */
77947802
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
@@ -7803,11 +7811,11 @@ static inline void event_fex_prep(struct connection *conn)
78037811
0x00,
78047812
sizeof(pdu_ctrl_tx->llctrl.feature_req.features));
78057813
pdu_ctrl_tx->llctrl.feature_req.features[0] =
7806-
conn->llcp_features & 0xFF;
7814+
conn->llcp_feature.features & 0xFF;
78077815
pdu_ctrl_tx->llctrl.feature_req.features[1] =
7808-
(conn->llcp_features >> 8) & 0xFF;
7816+
(conn->llcp_feature.features >> 8) & 0xFF;
78097817
pdu_ctrl_tx->llctrl.feature_req.features[2] =
7810-
(conn->llcp_features >> 16) & 0xFF;
7818+
(conn->llcp_feature.features >> 16) & 0xFF;
78117819

78127820
ctrl_tx_enqueue(conn, node_tx);
78137821

@@ -7821,6 +7829,10 @@ static inline void event_fex_prep(struct connection *conn)
78217829

78227830
static inline void event_vex_prep(struct connection *conn)
78237831
{
7832+
/* If waiting for response, do nothing */
7833+
if (!((conn->llcp_version.ack - conn->llcp_version.req) & 0x01)) {
7834+
return;
7835+
}
78247836

78257837
if (conn->llcp_version.tx == 0) {
78267838
struct radio_pdu_node_tx *node_tx;
@@ -7830,8 +7842,8 @@ static inline void event_vex_prep(struct connection *conn)
78307842
struct pdu_data *pdu_ctrl_tx = (void *)
78317843
node_tx->pdu_data;
78327844

7833-
/* procedure request acked */
7834-
conn->llcp_ack = conn->llcp_req;
7845+
/* procedure request acked, move to waiting state */
7846+
conn->llcp_version.ack--;
78357847

78367848
/* set version ind tx-ed flag */
78377849
conn->llcp_version.tx = 1U;
@@ -7862,7 +7874,7 @@ static inline void event_vex_prep(struct connection *conn)
78627874
struct pdu_data *pdu_ctrl_rx;
78637875

78647876
/* procedure request acked */
7865-
conn->llcp_ack = conn->llcp_req;
7877+
conn->llcp_version.ack = conn->llcp_version.req;
78667878

78677879
/* Prepare the rx packet structure */
78687880
node_rx = packet_rx_reserve_get(2);
@@ -8769,12 +8781,26 @@ static void event_connection_prepare(u32_t ticks_at_expire,
87698781
/* calc current event counter value */
87708782
event_counter = conn->event_counter + conn->latency_prepare;
87718783

8772-
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) || defined(CONFIG_BT_CTLR_PHY)
87738784
/* Check if no other procedure with instant is requested and not in
87748785
* Encryption setup.
87758786
*/
87768787
if ((conn->llcp_ack == conn->llcp_req) && !conn->pause_rx) {
8777-
if (0) {
8788+
if (conn->llcp_feature.ack != conn->llcp_feature.req) {
8789+
/* Stop previous event, to avoid Radio DMA corrupting
8790+
* the rx queue.
8791+
*/
8792+
event_stop(0, 0, 0, (void *)STATE_ABORT);
8793+
8794+
event_fex_prep(conn);
8795+
8796+
} else if (conn->llcp_version.ack != conn->llcp_version.req) {
8797+
/* Stop previous event, to avoid Radio DMA corrupting
8798+
* the rx queue.
8799+
*/
8800+
event_stop(0, 0, 0, (void *)STATE_ABORT);
8801+
8802+
event_vex_prep(conn);
8803+
87788804
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
87798805
/* check if CPR procedure is requested */
87808806
} else if (conn->llcp_conn_param.ack !=
@@ -8789,20 +8815,8 @@ static void event_connection_prepare(u32_t ticks_at_expire,
87898815
ticks_at_expire);
87908816
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
87918817

8792-
#if defined(CONFIG_BT_CTLR_PHY)
8793-
/* check if PHY Req procedure is requested */
8794-
} else if (conn->llcp_phy.ack != conn->llcp_phy.req) {
8795-
/* Stop previous event, to avoid Radio DMA corrupting
8796-
* the rx queue.
8797-
*/
8798-
event_stop(0, 0, 0, (void *)STATE_ABORT);
8799-
8800-
/* handle PHY Upd state machine */
8801-
event_phy_req_prep(conn);
8802-
#endif /* CONFIG_BT_CTLR_PHY */
8803-
88048818
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
8805-
/* check if procedure is requested */
8819+
/* check if DLE procedure is requested */
88068820
} else if (conn->llcp_length.ack != conn->llcp_length.req) {
88078821
/* Stop previous event, to avoid Radio DMA corrupting
88088822
* the rx queue
@@ -8811,18 +8825,28 @@ static void event_connection_prepare(u32_t ticks_at_expire,
88118825

88128826
/* handle DLU state machine */
88138827
if (event_len_prep(conn)) {
8814-
/* NOTE: rx pool could not be resized,
8815-
* lets skip this event and try in the next
8816-
* event.
8828+
/* NOTE: rx pool could not be resized, lets
8829+
* skip this event and try in the next event.
88178830
*/
88188831
_radio.ticker_id_prepare = 0U;
88198832

88208833
goto event_connection_prepare_skip;
88218834
}
88228835
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
8836+
8837+
#if defined(CONFIG_BT_CTLR_PHY)
8838+
/* check if PHY Req procedure is requested */
8839+
} else if (conn->llcp_phy.ack != conn->llcp_phy.req) {
8840+
/* Stop previous event, to avoid Radio DMA corrupting
8841+
* the rx queue.
8842+
*/
8843+
event_stop(0, 0, 0, (void *)STATE_ABORT);
8844+
8845+
/* handle PHY Upd state machine */
8846+
event_phy_req_prep(conn);
8847+
#endif /* CONFIG_BT_CTLR_PHY */
88238848
}
88248849
}
8825-
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ || CONFIG_BT_CTLR_PHY */
88268850

88278851
/* check if procedure is requested */
88288852
if (conn->llcp_ack != conn->llcp_req) {
@@ -8848,14 +8872,6 @@ static void event_connection_prepare(u32_t ticks_at_expire,
88488872
break;
88498873
#endif /* CONFIG_BT_CTLR_LE_ENC */
88508874

8851-
case LLCP_FEATURE_EXCHANGE:
8852-
event_fex_prep(conn);
8853-
break;
8854-
8855-
case LLCP_VERSION_EXCHANGE:
8856-
event_vex_prep(conn);
8857-
break;
8858-
88598875
#if defined(CONFIG_BT_CTLR_LE_PING)
88608876
case LLCP_PING:
88618877
event_ping_prep(conn);
@@ -8917,7 +8933,6 @@ static void event_connection_prepare(u32_t ticks_at_expire,
89178933
}
89188934
}
89198935

8920-
89218936
/* Setup XTAL startup and radio active events */
89228937
event_common_prepare(ticks_at_expire, remainder,
89238938
&conn->hdr.ticks_xtal_to_start,
@@ -9718,6 +9733,8 @@ static bool is_enc_req_pause_tx(struct connection *conn)
97189733
if ((pdu_data_tx->ll_id == PDU_DATA_LLID_CTRL) &&
97199734
(pdu_data_tx->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_ENC_REQ)) {
97209735
if ((conn->llcp_req != conn->llcp_ack) ||
9736+
(conn->llcp_feature.ack != conn->llcp_feature.req) ||
9737+
(conn->llcp_version.ack != conn->llcp_version.req) ||
97219738
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
97229739
(conn->llcp_conn_param.ack != conn->llcp_conn_param.req) ||
97239740
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
@@ -10186,7 +10203,7 @@ static u32_t conn_update_req(struct connection *conn)
1018610203
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
1018710204
} else if (!conn->llcp_conn_param.disabled &&
1018810205
(!conn->common.fex_valid ||
10189-
(conn->llcp_features &
10206+
(conn->llcp_feature.features &
1019010207
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
1019110208
/** Perform slave intiated conn param req */
1019210209
conn->llcp_conn_param.status = 0U;
@@ -10511,7 +10528,7 @@ static u8_t feature_rsp_send(struct connection *conn,
1051110528

1051210529
/* AND the feature set to get Feature USED */
1051310530
req = &pdu_data_rx->llctrl.feature_req;
10514-
conn->llcp_features &= feat_get(&req->features[0]);
10531+
conn->llcp_feature.features &= feat_get(&req->features[0]);
1051510532

1051610533
/* features exchanged */
1051710534
conn->common.fex_valid = 1U;
@@ -10525,11 +10542,11 @@ static u8_t feature_rsp_send(struct connection *conn,
1052510542
(void)memset(&pdu_ctrl_tx->llctrl.feature_rsp.features[0], 0x00,
1052610543
sizeof(pdu_ctrl_tx->llctrl.feature_rsp.features));
1052710544
pdu_ctrl_tx->llctrl.feature_req.features[0] =
10528-
conn->llcp_features & 0xFF;
10545+
conn->llcp_feature.features & 0xFF;
1052910546
pdu_ctrl_tx->llctrl.feature_req.features[1] =
10530-
(conn->llcp_features >> 8) & 0xFF;
10547+
(conn->llcp_feature.features >> 8) & 0xFF;
1053110548
pdu_ctrl_tx->llctrl.feature_req.features[2] =
10532-
(conn->llcp_features >> 16) & 0xFF;
10549+
(conn->llcp_feature.features >> 16) & 0xFF;
1053310550

1053410551
ctrl_tx_sec_enqueue(conn, node_tx);
1053510552

@@ -10568,7 +10585,10 @@ static u8_t version_ind_send(struct connection *conn,
1056810585
empty_tx_enqueue(conn);
1056910586

1057010587
} else if (!conn->llcp_version.rx) {
10588+
LL_ASSERT(conn->llcp_version.ack != conn->llcp_version.req);
10589+
1057110590
/* Procedure complete */
10591+
conn->llcp_version.ack = conn->llcp_version.req;
1057210592
conn->procedure_expire = 0U;
1057310593

1057410594
/* enqueue the version ind */
@@ -11128,7 +11148,7 @@ u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
1112811148
}
1112911149

1113011150
conn->handle = 0xFFFF;
11131-
conn->llcp_features = LL_FEAT;
11151+
conn->llcp_feature.features = LL_FEAT;
1113211152
conn->data_chan_sel = 0U;
1113311153
conn->data_chan_use = 0U;
1113411154
conn->event_counter = 0U;
@@ -11177,6 +11197,10 @@ u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
1117711197

1117811198
conn->llcp_req = 0U;
1117911199
conn->llcp_ack = 0U;
11200+
conn->llcp_feature.req = 0U;
11201+
conn->llcp_feature.ack = 0U;
11202+
conn->llcp_version.req = 0U;
11203+
conn->llcp_version.ack = 0U;
1118011204
conn->llcp_version.tx = 0U;
1118111205
conn->llcp_version.rx = 0U;
1118211206
conn->llcp_terminate.req = 0U;
@@ -11648,7 +11672,7 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
1164811672
328 + RADIO_TIFS + 328);
1164911673

1165011674
conn->handle = 0xFFFF;
11651-
conn->llcp_features = LL_FEAT;
11675+
conn->llcp_feature.features = LL_FEAT;
1165211676
access_addr = access_addr_get();
1165311677
memcpy(&conn->access_addr[0], &access_addr, sizeof(conn->access_addr));
1165411678
bt_rand(&conn->crc_init[0], 3);
@@ -11717,6 +11741,10 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
1171711741

1171811742
conn->llcp_req = 0U;
1171911743
conn->llcp_ack = 0U;
11744+
conn->llcp_feature.req = 0U;
11745+
conn->llcp_feature.ack = 0U;
11746+
conn->llcp_version.req = 0U;
11747+
conn->llcp_version.ack = 0U;
1172011748
conn->llcp_version.tx = 0U;
1172111749
conn->llcp_version.rx = 0U;
1172211750
conn->llcp_terminate.req = 0U;
@@ -11820,7 +11848,7 @@ u8_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval_min,
1182011848
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
1182111849
if (!conn->llcp_conn_param.disabled &&
1182211850
(!conn->common.fex_valid ||
11823-
(conn->llcp_features &
11851+
(conn->llcp_feature.features &
1182411852
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
1182511853
cmd++;
1182611854
} else if (conn->role) {
@@ -12074,12 +12102,11 @@ u8_t ll_feature_req_send(u16_t handle)
1207412102
return BT_HCI_ERR_UNKNOWN_CONN_ID;
1207512103
}
1207612104

12077-
if (conn->llcp_req != conn->llcp_ack) {
12105+
if (conn->llcp_feature.req != conn->llcp_feature.ack) {
1207812106
return BT_HCI_ERR_CMD_DISALLOWED;
1207912107
}
1208012108

12081-
conn->llcp_type = LLCP_FEATURE_EXCHANGE;
12082-
conn->llcp_req++;
12109+
conn->llcp_feature.req++;
1208312110

1208412111
return 0;
1208512112
}
@@ -12093,12 +12120,11 @@ u8_t ll_version_ind_send(u16_t handle)
1209312120
return BT_HCI_ERR_UNKNOWN_CONN_ID;
1209412121
}
1209512122

12096-
if (conn->llcp_req != conn->llcp_ack) {
12123+
if (conn->llcp_version.req != conn->llcp_version.ack) {
1209712124
return BT_HCI_ERR_CMD_DISALLOWED;
1209812125
}
1209912126

12100-
conn->llcp_type = LLCP_VERSION_EXCHANGE;
12101-
conn->llcp_req++;
12127+
conn->llcp_version.req++;
1210212128

1210312129
return 0;
1210412130
}
@@ -12199,8 +12225,7 @@ u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time)
1219912225
return BT_HCI_ERR_UNKNOWN_CONN_ID;
1220012226
}
1220112227

12202-
if ((conn->llcp_req != conn->llcp_ack) ||
12203-
(conn->llcp_length.req != conn->llcp_length.ack)) {
12228+
if (conn->llcp_length.req != conn->llcp_length.ack) {
1220412229
return BT_HCI_ERR_CMD_DISALLOWED;
1220512230
}
1220612231

@@ -12280,8 +12305,7 @@ u8_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx)
1228012305
return BT_HCI_ERR_UNKNOWN_CONN_ID;
1228112306
}
1228212307

12283-
if ((conn->llcp_req != conn->llcp_ack) ||
12284-
(conn->llcp_phy.req != conn->llcp_phy.ack)) {
12308+
if (conn->llcp_phy.req != conn->llcp_phy.ack) {
1228512309
return BT_HCI_ERR_CMD_DISALLOWED;
1228612310
}
1228712311

0 commit comments

Comments
 (0)