Skip to content

Commit 9681716

Browse files
erbr-otcarlescufi
authored andcommitted
Bluetooth: controller: llcp: phy update proc, validate phys and instant
Implementing proper validation of PHY selection for PHY UPDATE procedure Implement connection termination on PHY UPDATE with instant in the past Signed-off-by: Erik Brockhoff <[email protected]>
1 parent 11e238a commit 9681716

File tree

1 file changed

+48
-12
lines changed

1 file changed

+48
-12
lines changed

subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,25 @@ static void pu_reset_timing_restrict(struct ll_conn *conn)
175175
}
176176

177177
#if defined(CONFIG_BT_PERIPHERAL)
178+
static inline bool phy_valid(uint8_t phy)
179+
{
180+
/* This is equivalent to:
181+
* maximum one bit set, and no bit set is rfu's
182+
*/
183+
return (phy < 5 && phy != 3);
184+
}
185+
178186
static uint8_t pu_check_update_ind(struct ll_conn *conn, struct proc_ctx *ctx)
179187
{
180188
uint8_t ret = 0;
181189

190+
/* Check if either phy selected is invalid */
191+
if (!phy_valid(ctx->data.pu.c_to_p_phy) || !phy_valid(ctx->data.pu.p_to_c_phy)) {
192+
/* more than one or any rfu bit selected in either phy */
193+
ctx->data.pu.error = BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
194+
ret = 1;
195+
}
196+
182197
/* Both tx and rx PHY unchanged */
183198
if (!((ctx->data.pu.c_to_p_phy | ctx->data.pu.p_to_c_phy) & 0x07)) {
184199
/* if no phy changes, quit procedure, and possibly signal host */
@@ -199,29 +214,41 @@ static uint8_t pu_check_update_ind(struct ll_conn *conn, struct proc_ctx *ctx)
199214
static uint8_t pu_apply_phy_update(struct ll_conn *conn, struct proc_ctx *ctx)
200215
{
201216
struct lll_conn *lll = &conn->lll;
217+
uint8_t phy_bitmask = PHY_1M;
218+
const uint8_t old_tx = lll->phy_tx;
219+
const uint8_t old_rx = lll->phy_rx;
220+
221+
#if defined(CONFIG_BT_CTLR_PHY_2M)
222+
phy_bitmask |= PHY_2M;
223+
#endif
224+
#if defined(CONFIG_BT_CTLR_PHY_CODED)
225+
phy_bitmask |= PHY_CODED;
226+
#endif
227+
const uint8_t p_to_c_phy = ctx->data.pu.p_to_c_phy & phy_bitmask;
228+
const uint8_t c_to_p_phy = ctx->data.pu.c_to_p_phy & phy_bitmask;
202229

203230
if (0) {
204231
#if defined(CONFIG_BT_PERIPHERAL)
205232
} else if (lll->role == BT_HCI_ROLE_PERIPHERAL) {
206-
if (ctx->data.pu.p_to_c_phy) {
207-
lll->phy_tx = ctx->data.pu.p_to_c_phy;
233+
if (p_to_c_phy) {
234+
lll->phy_tx = p_to_c_phy;
208235
}
209-
if (ctx->data.pu.c_to_p_phy) {
210-
lll->phy_rx = ctx->data.pu.c_to_p_phy;
236+
if (c_to_p_phy) {
237+
lll->phy_rx = c_to_p_phy;
211238
}
212239
#endif /* CONFIG_BT_PERIPHERAL */
213240
#if defined(CONFIG_BT_CENTRAL)
214241
} else if (lll->role == BT_HCI_ROLE_CENTRAL) {
215-
if (ctx->data.pu.p_to_c_phy) {
216-
lll->phy_rx = ctx->data.pu.p_to_c_phy;
242+
if (p_to_c_phy) {
243+
lll->phy_rx = p_to_c_phy;
217244
}
218-
if (ctx->data.pu.c_to_p_phy) {
219-
lll->phy_tx = ctx->data.pu.c_to_p_phy;
245+
if (c_to_p_phy) {
246+
lll->phy_tx = c_to_p_phy;
220247
}
221248
#endif /* CONFIG_BT_CENTRAL */
222249
}
223250

224-
return (ctx->data.pu.c_to_p_phy || ctx->data.pu.p_to_c_phy);
251+
return ((old_tx != lll->phy_tx) || (old_rx != lll->phy_rx));
225252
}
226253

227254
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
@@ -313,8 +340,9 @@ static void pu_prepare_instant(struct ll_conn *conn, struct proc_ctx *ctx)
313340
/* Set instance only in case there is actual PHY change. Otherwise the instant should be
314341
* set to 0.
315342
*/
316-
if (ctx->data.pu.c_to_p_phy != 0 || ctx->data.pu.p_to_c_phy != 0) {
317-
ctx->data.pu.instant = ull_conn_event_counter(conn) + PHY_UPDATE_INSTANT_DELTA;
343+
if (ctx->data.pu.c_to_p_phy != 0 || ctx->data.pu.p_to_c_phy != 0) {
344+
ctx->data.pu.instant = ull_conn_event_counter(conn) + conn->lll.latency +
345+
PHY_UPDATE_INSTANT_DELTA;
318346
} else {
319347
ctx->data.pu.instant = 0;
320348
}
@@ -650,6 +678,10 @@ static void lp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
650678
ctx->state = LP_PU_STATE_WAIT_INSTANT;
651679
} else {
652680
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
681+
if (ctx->data.pu.error != BT_HCI_ERR_SUCCESS) {
682+
/* Mark the connection for termination */
683+
conn->llcp_terminate.reason_final = ctx->data.pu.error;
684+
}
653685
ctx->data.pu.ntf_pu = ctx->data.pu.host_initiated;
654686
lp_pu_complete(conn, ctx, evt, param);
655687
}
@@ -1045,8 +1077,12 @@ static void rp_pu_st_wait_rx_phy_update_ind(struct ll_conn *conn, struct proc_ct
10451077
*/
10461078
llcp_rr_prt_stop(conn);
10471079

1048-
ctx->state = LP_PU_STATE_WAIT_INSTANT;
1080+
ctx->state = RP_PU_STATE_WAIT_INSTANT;
10491081
} else {
1082+
if (ctx->data.pu.error == BT_HCI_ERR_INSTANT_PASSED) {
1083+
/* Mark the connection for termination */
1084+
conn->llcp_terminate.reason_final = BT_HCI_ERR_INSTANT_PASSED;
1085+
}
10501086
rp_pu_complete(conn, ctx, evt, param);
10511087
}
10521088
break;

0 commit comments

Comments
 (0)