Skip to content

Commit a520506

Browse files
Andries Kruithofjhedberg
authored andcommitted
Bluetooth: controller: split: Update feature exchange to BTCore V5.0
The existing feature exchange procedure does not give the proper response as specified in the BT core spec 5.0. The old behaviour is that the feature-response returns the logical and of the features for both peers. The behaviour implemented here is that the feature-response returns the featureset of the peer, except for octet 0 which is the logical and of the supported features. Tested by using the bt shell, and having different featuresets on the 2 peers. This fixes #25483 Signed-off-by: Andries Kruithof <[email protected]>
1 parent 2758c33 commit a520506

File tree

5 files changed

+54
-15
lines changed

5 files changed

+54
-15
lines changed

subsys/bluetooth/controller/include/ll_feat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103

104104
#define LL_FEAT_BIT_MASK 0x1FFFF
105105
#define LL_FEAT_BIT_MASK_VALID 0x1CF2F
106+
#define LL_FEAT_FILTER_OCTET0 0x1FF00
106107
#define LL_FEAT (LL_FEAT_BIT_ENC | \
107108
LL_FEAT_BIT_CONN_PARAM_REQ | \
108109
LL_FEAT_BIT_EXT_REJ_IND | \

subsys/bluetooth/controller/ll_sw/ull_adv.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,8 @@ u8_t ll_adv_enable(u8_t enable)
650650
conn->llcp_rx = NULL;
651651
conn->llcp_cu.req = conn->llcp_cu.ack = 0;
652652
conn->llcp_feature.req = conn->llcp_feature.ack = 0;
653-
conn->llcp_feature.features = LL_FEAT;
653+
conn->llcp_feature.features_conn = LL_FEAT;
654+
conn->llcp_feature.features_peer = 0;
654655
conn->llcp_version.req = conn->llcp_version.ack = 0;
655656
conn->llcp_version.tx = conn->llcp_version.rx = 0;
656657
conn->llcp_terminate.reason_peer = 0;

subsys/bluetooth/controller/ll_sw/ull_conn.c

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ u8_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval_min,
275275
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
276276
if (!conn->llcp_conn_param.disabled &&
277277
(!conn->common.fex_valid ||
278-
(conn->llcp_feature.features &
278+
(conn->llcp_feature.features_conn &
279279
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
280280
cmd++;
281281
} else if (conn->lll.role) {
@@ -2499,7 +2499,8 @@ static inline void event_enc_reject_prep(struct ll_conn *conn,
24992499
pdu->ll_id = PDU_DATA_LLID_CTRL;
25002500

25012501
if (conn->common.fex_valid &&
2502-
(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_EXT_REJ_IND))) {
2502+
(conn->llcp_feature.features_conn &
2503+
BIT(BT_LE_FEAT_BIT_EXT_REJ_IND))) {
25032504
struct pdu_data_llctrl_reject_ext_ind *p;
25042505

25052506
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
@@ -2727,7 +2728,7 @@ static inline void event_fex_prep(struct ll_conn *conn)
27272728
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP;
27282729
(void)memset(&pdu->llctrl.feature_rsp.features[0], 0x00,
27292730
sizeof(pdu->llctrl.feature_rsp.features));
2730-
sys_put_le24(conn->llcp_feature.features,
2731+
sys_put_le24(conn->llcp_feature.features_peer,
27312732
pdu->llctrl.feature_req.features);
27322733

27332734
/* enqueue feature rsp structure into rx queue */
@@ -2745,7 +2746,7 @@ static inline void event_fex_prep(struct ll_conn *conn)
27452746
conn->llcp_feature.ack--;
27462747

27472748
/* use initial feature bitmap */
2748-
conn->llcp_feature.features = LL_FEAT;
2749+
conn->llcp_feature.features_conn = LL_FEAT;
27492750

27502751
/* place the feature exchange req packet as next in tx queue */
27512752
pdu->ll_id = PDU_DATA_LLID_CTRL;
@@ -2757,7 +2758,7 @@ static inline void event_fex_prep(struct ll_conn *conn)
27572758
(void)memset(&pdu->llctrl.feature_req.features[0],
27582759
0x00,
27592760
sizeof(pdu->llctrl.feature_req.features));
2760-
sys_put_le24(conn->llcp_feature.features,
2761+
sys_put_le24(conn->llcp_feature.features_conn,
27612762
pdu->llctrl.feature_req.features);
27622763

27632764
ctrl_tx_enqueue(conn, tx);
@@ -3162,14 +3163,14 @@ static inline void dle_max_time_get(const struct ll_conn *conn,
31623163

31633164
#if defined(CONFIG_BT_CTLR_PHY)
31643165
#if defined(CONFIG_BT_CTLR_PHY_CODED)
3165-
feature_coded_phy = (conn->llcp_feature.features &
3166+
feature_coded_phy = (conn->llcp_feature.features_conn &
31663167
BIT(BT_LE_FEAT_BIT_PHY_CODED));
31673168
#else
31683169
feature_coded_phy = 0;
31693170
#endif
31703171

31713172
#if defined(CONFIG_BT_CTLR_PHY_2M)
3172-
feature_phy_2m = (conn->llcp_feature.features &
3173+
feature_phy_2m = (conn->llcp_feature.features_conn &
31733174
BIT(BT_LE_FEAT_BIT_PHY_2M));
31743175
#else
31753176
feature_phy_2m = 0;
@@ -4007,12 +4008,28 @@ static inline u32_t feat_get(u8_t *features)
40074008
return feat;
40084009
}
40094010

4011+
/*
4012+
* Perform a logical and on octet0 and keep the remaining bits of the
4013+
* first input parameter
4014+
*/
4015+
static inline u32_t feat_land_octet0(u32_t feat_to_keep, u32_t feat_octet0)
4016+
{
4017+
u32_t feat_result;
4018+
4019+
feat_result = feat_to_keep & feat_octet0;
4020+
feat_result &= 0xFF;
4021+
feat_result |= feat_to_keep & LL_FEAT_FILTER_OCTET0;
4022+
4023+
return feat_result;
4024+
}
4025+
40104026
static int feature_rsp_send(struct ll_conn *conn, struct node_rx_pdu *rx,
40114027
struct pdu_data *pdu_rx)
40124028
{
40134029
struct pdu_data_llctrl_feature_req *req;
40144030
struct node_tx *tx;
40154031
struct pdu_data *pdu_tx;
4032+
u32_t feat;
40164033

40174034
/* acquire tx mem */
40184035
tx = mem_acquire(&mem_conn_tx_ctrl.free);
@@ -4022,7 +4039,14 @@ static int feature_rsp_send(struct ll_conn *conn, struct node_rx_pdu *rx,
40224039

40234040
/* AND the feature set to get Feature USED */
40244041
req = &pdu_rx->llctrl.feature_req;
4025-
conn->llcp_feature.features &= feat_get(&req->features[0]);
4042+
conn->llcp_feature.features_conn &= feat_get(&req->features[0]);
4043+
/*
4044+
* Get all the features of peer, except octet 0.
4045+
* Octet 0 is the actual features used on the link
4046+
* See BTCore V5.2, Vol. 6, Part B, chapter 5.1.4
4047+
*/
4048+
conn->llcp_feature.features_peer =
4049+
feat_land_octet0(feat_get(&req->features[0]), LL_FEAT);
40264050

40274051
/* features exchanged */
40284052
conn->common.fex_valid = 1U;
@@ -4031,12 +4055,16 @@ static int feature_rsp_send(struct ll_conn *conn, struct node_rx_pdu *rx,
40314055
pdu_tx = (void *)tx->pdu;
40324056
pdu_tx->ll_id = PDU_DATA_LLID_CTRL;
40334057
pdu_tx->len = offsetof(struct pdu_data_llctrl, feature_rsp) +
4034-
sizeof(struct pdu_data_llctrl_feature_rsp);
4058+
sizeof(struct pdu_data_llctrl_feature_rsp);
40354059
pdu_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FEATURE_RSP;
40364060
(void)memset(&pdu_tx->llctrl.feature_rsp.features[0], 0x00,
40374061
sizeof(pdu_tx->llctrl.feature_rsp.features));
4038-
sys_put_le24(conn->llcp_feature.features,
4039-
pdu_tx->llctrl.feature_req.features);
4062+
/*
4063+
* On feature response we send the local supported features.
4064+
* See BTCore V5.2 VOl 6 Part B, chapter 5.1.4
4065+
*/
4066+
feat = feat_land_octet0(LL_FEAT, conn->llcp_feature.features_conn);
4067+
sys_put_le24(feat, pdu_tx->llctrl.feature_rsp.features);
40404068

40414069
ctrl_tx_sec_enqueue(conn, tx);
40424070

@@ -4053,7 +4081,14 @@ static void feature_rsp_recv(struct ll_conn *conn, struct pdu_data *pdu_rx)
40534081
rsp = &pdu_rx->llctrl.feature_rsp;
40544082

40554083
/* AND the feature set to get Feature USED */
4056-
conn->llcp_feature.features &= feat_get(&rsp->features[0]);
4084+
conn->llcp_feature.features_conn &= feat_get(&rsp->features[0]);
4085+
/*
4086+
* Get all the features of peer, except octet 0.
4087+
* Octet 0 is the actual features used on the link
4088+
* See BTCore V5.2, Vol. 6, Part B, chapter 5.1.4
4089+
*/
4090+
conn->llcp_feature.features_peer =
4091+
feat_land_octet0(feat_get(&rsp->features[0]), LL_FEAT);
40574092

40584093
/* features exchanged */
40594094
conn->common.fex_valid = 1U;

subsys/bluetooth/controller/ll_sw/ull_conn_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ struct ll_conn {
140140
struct {
141141
u8_t req;
142142
u8_t ack;
143-
u32_t features;
143+
u32_t features_conn;
144+
u32_t features_peer;
144145
} llcp_feature;
145146

146147
struct {

subsys/bluetooth/controller/ll_sw/ull_master.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
197197
conn->llcp_rx = NULL;
198198
conn->llcp_cu.req = conn->llcp_cu.ack = 0;
199199
conn->llcp_feature.req = conn->llcp_feature.ack = 0;
200-
conn->llcp_feature.features = LL_FEAT;
200+
conn->llcp_feature.features_conn = LL_FEAT;
201+
conn->llcp_feature.features_peer = 0;
201202
conn->llcp_version.req = conn->llcp_version.ack = 0;
202203
conn->llcp_version.tx = conn->llcp_version.rx = 0U;
203204
conn->llcp_terminate.reason_peer = 0U;

0 commit comments

Comments
 (0)