diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 935b827d32f..db1a26e5b86 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -7908,7 +7908,11 @@ static void le_unknown_rsp(struct pdu_data *pdu_data, uint16_t handle, le_remote_feat_complete(BT_HCI_ERR_UNSUPP_REMOTE_FEATURE, NULL, handle, buf); break; - +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PDU_DATA_LLCTRL_TYPE_CTE_REQ: + le_df_cte_req_failed(BT_HCI_ERR_UNSUPP_REMOTE_FEATURE, handle, buf); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ default: BT_WARN("type: 0x%02x", pdu_data->llctrl.unknown_rsp.type); break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index 54c7bb36b14..85cbafc34de 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -404,7 +404,17 @@ struct llcp_struct { struct { uint8_t sent; uint8_t valid; + /* + * Stores features supported by peer device. The content of the member may be + * verified when feature exchange procedure has completed, valid member is set to 1. + */ uint64_t features_peer; + /* + * Stores features common for two connected devices. Before feature exchange + * procedure is completed, the member stores information about all features + * supported by local device. After completion of the procedure, the feature set + * may be limited to features that are common. + */ uint64_t features_used; } fex; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index e08f4fb20c4..1fea6bf9ea2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -971,6 +971,19 @@ uint8_t ull_cp_cte_req(struct ll_conn *conn, uint8_t min_cte_len, uint8_t cte_ty { struct proc_ctx *ctx; + /* If Controller gained, awareness: + * - by Feature Exchange control procedure that peer device does not support CTE response, + * - by reception LL_UNKNOWN_RSP with unknown type LL_CTE_REQ that peer device does not + * recognize CTE request, + * then response to Host that CTE request enable command is not possible due to unsupported + * remote feature. + */ + if ((conn->llcp.fex.valid && + (!(conn->llcp.fex.features_peer & BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP)))) || + (!conn->llcp.fex.valid && !feature_cte_req(conn))) { + return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; + } + /* The request may be started by periodic CTE request procedure, so it skips earlier * verification of PHY. In case the PHY has changed to CODE the request should be stopped. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index b26a0ced761..e77ed00243d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -219,6 +219,9 @@ static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, stru llcp_ntf_encode_cte_req(pdu); } break; + case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP: + llcp_ntf_encode_unknown_rsp(ctx, pdu); + break; case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: llcp_ntf_encode_reject_ext_ind(ctx, pdu); break; @@ -228,6 +231,17 @@ static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, stru } } +static void lp_comm_ntf_cte_req_tx(struct ll_conn *conn, struct proc_ctx *ctx) +{ + if (llcp_ntf_alloc_is_available()) { + lp_comm_ntf(conn, ctx); + ull_cp_cte_req_set_disable(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + ctx->state = LP_COMMON_STATE_WAIT_NTF; + } +} + static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx) { if (conn->llcp.cte_req.is_enabled) { @@ -238,22 +252,19 @@ static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx) conn->llcp.cte_req.req_interval; } ctx->state = LP_COMMON_STATE_IDLE; - } else if (llcp_ntf_alloc_is_available()) { - lp_comm_ntf(conn, ctx); - ull_cp_cte_req_set_disable(conn); - ctx->state = LP_COMMON_STATE_IDLE; } else { - ctx->state = LP_COMMON_STATE_WAIT_NTF; + lp_comm_ntf_cte_req_tx(conn, ctx); } } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND && - ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ) { - if (llcp_ntf_alloc_is_available()) { - lp_comm_ntf(conn, ctx); - ull_cp_cte_req_set_disable(conn); - ctx->state = LP_COMMON_STATE_IDLE; - } else { - ctx->state = LP_COMMON_STATE_WAIT_NTF; - } + ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ) { + lp_comm_ntf_cte_req_tx(conn, ctx); + } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP && + ctx->unknown_response.type == PDU_DATA_LLCTRL_TYPE_CTE_REQ) { + /* CTE response is unsupported in peer, so disable locally for this + * connection + */ + feature_unmask_features(conn, LL_FEAT_BIT_CONNECTION_CTE_REQ); + lp_comm_ntf_cte_req_tx(conn, ctx); } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNUSED) { /* This path is related with handling disable the CTE REQ when PHY * has been changed to CODED PHY. BT 5.3 Core Vol 4 Part E 7.8.85 diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h index a715ada5df4..1f876412d42 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h @@ -117,6 +117,15 @@ static inline bool feature_phy_coded(struct ll_conn *conn) #endif } +static inline bool feature_cte_req(struct ll_conn *conn) +{ +#if defined(CONFIG_BT_CTLR_DF) && defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + return conn->llcp.fex.features_used & LL_FEAT_BIT_CONNECTION_CTE_REQ; +#else + return 0; +#endif +} + /* * for asymmetric features we can check either if we support it * or if the peer supports it @@ -148,10 +157,6 @@ static inline bool feature_peer_smi_tx(struct ll_conn *conn) * per_adv * pwr_class1 * min_chann - * CTE_req - * CTE_rsp - * CTE_tx - * CTE_rx * ant_sw_CTE_tx * ant_sw_CTE_rx * tone_ext