diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 95160e0aa35..d324e0c68ac 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -2495,8 +2495,15 @@ struct bt_hci_evt_le_connection_iq_report { struct bt_hci_le_iq_sample sample[0]; } __packed; +#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 + #define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 struct bt_hci_evt_le_cte_req_failed { + /* According to BT 5.3 Core Spec the status field may have following + * values: + * - BT_HCI_CTE_REQ_STATUS_RSP_WIHOUT_CTE when received LL_CTE_RSP_PDU without CTE. + * - Other Controller error code for peer rejected request. + */ uint8_t status; uint16_t conn_handle; } __packed; diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 93fe92acaad..4cad95c2bc1 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -2991,6 +2991,21 @@ static void le_df_set_conn_cte_req_enable(struct net_buf *buf, struct net_buf ** rp->status = status; rp->handle = handle_le16; } + +static void le_df_cte_req_failed(uint8_t error_code, uint16_t handle, struct net_buf *buf) +{ + struct bt_hci_evt_le_cte_req_failed *sep; + + if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || + !(le_event_mask & BT_EVT_MASK_LE_CTE_REQUEST_FAILED)) { + return; + } + + sep = meta_evt(buf, BT_HCI_EVT_LE_CTE_REQUEST_FAILED, sizeof(*sep)); + + sep->status = error_code; + sep->conn_handle = sys_cpu_to_le16(handle); +} #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) @@ -7350,6 +7365,19 @@ static void le_unknown_rsp(struct pdu_data *pdu_data, uint16_t handle, } } +static void le_reject_ext_ind(struct pdu_data *pdu, uint16_t handle, struct net_buf *buf) +{ + switch (pdu->llctrl.reject_ext_ind.reject_opcode) { +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PDU_DATA_LLCTRL_TYPE_CTE_REQ: + le_df_cte_req_failed(pdu->llctrl.reject_ext_ind.error_code, handle, buf); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + default: + BT_WARN("reject opcode: 0x%02x", pdu->llctrl.reject_ext_ind.reject_opcode); + break; + } +} #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) static void le_conn_param_req(struct pdu_data *pdu_data, uint16_t handle, struct net_buf *buf) @@ -7466,10 +7494,20 @@ static void encode_data_ctrl(struct node_rx_pdu *node_rx, break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PDU_DATA_LLCTRL_TYPE_CTE_REQ: + le_df_cte_req_failed(BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE, handle, buf); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP: le_unknown_rsp(pdu_data, handle, buf); break; + case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: + le_reject_ext_ind(pdu_data, handle, buf); + break; + default: LL_ASSERT(0); return; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index dc0425f5cdb..0da3d2a3c71 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -424,6 +424,7 @@ struct llcp_struct { uint16_t req_interval; uint16_t req_expire; } cte_req; + #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) struct llcp_df_rsp_cfg { diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index 045c0ee24d0..acfbf6367ea 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -210,9 +210,12 @@ static void lp_comm_ntf_length_change(struct ll_conn *conn, struct proc_ctx *ctx #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) { - /* TODO (ppryga): Add handling of rejections in HCI: HCI_LE_CTE_Request_Failed. */ switch (ctx->response_opcode) { case PDU_DATA_LLCTRL_TYPE_CTE_RSP: + /* Notify host that received LL_CTE_RSP does not have CTE */ + if (!ctx->data.cte_remote_rsp.has_cte) { + llcp_ntf_encode_cte_req(pdu); + } break; case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: llcp_ntf_encode_reject_ext_ind(ctx, pdu); @@ -346,10 +349,12 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_CTE_RSP) { - if (conn->llcp.cte_req.req_interval != 0U) { + if (ctx->data.cte_remote_rsp.has_cte && + conn->llcp.cte_req.req_interval != 0U) { conn->llcp.cte_req.req_expire = conn->llcp.cte_req.req_interval; } else { conn->llcp.cte_req.is_enabled = 0U; + lp_comm_ntf(conn, ctx); } ctx->state = LP_COMMON_STATE_IDLE; } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND && @@ -556,9 +561,11 @@ static void lp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct llcp_pdu_decode_length_rsp(conn, pdu); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PDU_DATA_LLCTRL_TYPE_CTE_RSP: - /* CTE Response PDU had no data */ + llcp_pdu_decode_cte_rsp(ctx, pdu); break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: llcp_pdu_decode_reject_ext_ind(ctx, pdu); break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 36960946209..770e883c97e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -220,6 +220,11 @@ struct proc_ctx { uint8_t type:2; uint8_t min_len:5; } cte_req; + + struct llcp_df_cte_remote_rsp { + /* Storage for information that received LL_CTE_RSP PDU includes CTE */ + uint8_t has_cte; + } cte_remote_rsp; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) @@ -591,7 +596,8 @@ void llcp_ntf_encode_length_change(struct ll_conn *conn, * Constant Tone Request Procedure Helper */ void llcp_pdu_encode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu); -void llcp_ntf_encode_cte_req(struct ll_conn *conn, struct pdu_data *pdu); +void llcp_pdu_decode_cte_rsp(struct proc_ctx *ctx, const struct pdu_data *pdu); +void llcp_ntf_encode_cte_req(struct pdu_data *pdu); #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 224c4ae9b4d..54c56a713e5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -727,14 +727,24 @@ void llcp_pdu_encode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu) p->cte_type_req = ctx->data.cte_req.type; } -void llcp_ntf_encode_cte_req(struct ll_conn *conn, struct pdu_data *pdu) +void llcp_pdu_decode_cte_rsp(struct proc_ctx *ctx, const struct pdu_data *pdu) +{ + if (pdu->cp == 0U || pdu->cte_info.time == 0U) { + ctx->data.cte_remote_rsp.has_cte = false; + } else { + ctx->data.cte_remote_rsp.has_cte = true; + } +} + +void llcp_ntf_encode_cte_req(struct pdu_data *pdu) { pdu->ll_id = PDU_DATA_LLID_CTRL; pdu->len = offsetof(struct pdu_data_llctrl, cte_rsp) + sizeof(struct pdu_data_llctrl_cte_rsp); pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP; - /* TODO add handling of IQ samples forwarding */ + /* Received LL_CTE_RSP PDU didn't have CTE */ + pdu->cp = 0U; } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */