@@ -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+
178186static 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)
199214static 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