From a8ffc03f6eba778db58a1d68179b498793be44d6 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 21 Sep 2020 07:19:42 +0530 Subject: [PATCH] Bluetooth: controller: Fix REJECT_IND PDU handling Fix for handling REJECT_IND PDU received for PHY Update, Connection Parameter Request and Data Length Update control procedures. If a link layer control procedure collision occurs, example with local initiated PHY Update Procedure, and peer sends a REJECT_IND PDU, then the PHY Update Procedure is stalled. Fixes #28282. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_conn.c | 86 ++++++++++++++++---- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 3ebd39c9fe7..3019ed66fc5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -4374,13 +4374,8 @@ static inline int reject_ind_phy_upd_recv(struct ll_conn *conn, #endif /* CONFIG_BT_CTLR_PHY */ #if defined(CONFIG_BT_CTLR_LE_ENC) -static inline int reject_ind_enc_recv(struct ll_conn *conn, - struct pdu_data *pdu_rx) +static inline int reject_ind_enc_recv(struct ll_conn *conn) { - struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind; - - rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind; - /* resume data packet rx and tx */ conn->llcp_enc.pause_rx = 0U; conn->llcp_enc.pause_tx = 0U; @@ -4389,7 +4384,18 @@ static inline int reject_ind_enc_recv(struct ll_conn *conn, conn->llcp_ack = conn->llcp_req; conn->procedure_expire = 0U; + return 0; +} + +static inline int reject_ext_ind_enc_recv(struct ll_conn *conn, + struct pdu_data *pdu_rx) +{ + struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind; + + reject_ind_enc_recv(conn); + /* enqueue as if it were a reject ind */ + rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind; pdu_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_REJECT_IND; pdu_rx->llctrl.reject_ind.error_code = rej_ext_ind->error_code; @@ -4397,6 +4403,64 @@ static inline int reject_ind_enc_recv(struct ll_conn *conn, } #endif /* CONFIG_BT_CTLR_LE_ENC */ +static inline void reject_ind_recv(struct ll_conn *conn, struct node_rx_pdu *rx, + struct pdu_data *pdu_rx) +{ + int err = -EINVAL; + + + if (0) { + +#if defined(CONFIG_BT_CTLR_LE_ENC) + } else if ((conn->llcp_ack != conn->llcp_req) && + (conn->llcp_type == LLCP_ENCRYPTION)) { + err = reject_ind_enc_recv(conn); +#endif /* CONFIG_BT_CTLR_LE_ENC */ + +#if defined(CONFIG_BT_CTLR_PHY) + } else if (conn->llcp_phy.ack != conn->llcp_phy.req) { + struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind; + struct pdu_data_llctrl_reject_ind *rej_ind; + + rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind; + rej_ind = (void *)&pdu_rx->llctrl.reject_ind; + /* NOTE: Do not modify reject_opcode field which overlap with + * error_code field in reject ind PDU structure. Only copy + * error_code from reject ind to reject ext ind PDU + * structure. + */ + rej_ext_ind->error_code = rej_ind->error_code; + err = reject_ind_phy_upd_recv(conn, rx, pdu_rx); +#endif /* CONFIG_BT_CTLR_PHY */ + +#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) + } else if (conn->llcp_conn_param.ack != conn->llcp_conn_param.req) { + struct pdu_data_llctrl_reject_ext_ind *rej_ext_ind; + struct pdu_data_llctrl_reject_ind *rej_ind; + + rej_ext_ind = (void *)&pdu_rx->llctrl.reject_ext_ind; + rej_ind = (void *)&pdu_rx->llctrl.reject_ind; + /* NOTE: Do not modify reject_opcode field which overlap with + * error_code field in reject ind PDU structure. Only copy + * error_code from reject ind to reject ext ind PDU + * structure. + */ + rej_ext_ind->error_code = rej_ind->error_code; + err = reject_ind_conn_upd_recv(conn, rx, pdu_rx); +#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ + +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + } else if (conn->llcp_length.ack != conn->llcp_length.req) { + err = reject_ind_dle_recv(conn, pdu_rx); +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + } + + if (err) { + /* Mark for buffer for release */ + rx->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE; + } +} + static inline void reject_ext_ind_recv(struct ll_conn *conn, struct node_rx_pdu *rx, struct pdu_data *pdu_rx) @@ -4411,7 +4475,7 @@ static inline void reject_ext_ind_recv(struct ll_conn *conn, case PDU_DATA_LLCTRL_TYPE_ENC_REQ: if ((conn->llcp_ack != conn->llcp_req) && (conn->llcp_type == LLCP_ENCRYPTION)) { - err = reject_ind_enc_recv(conn, pdu_rx); + err = reject_ext_ind_enc_recv(conn, pdu_rx); } break; #endif /* CONFIG_BT_CTLR_LE_ENC */ @@ -5473,13 +5537,7 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx, goto ull_conn_rx_unknown_rsp_send; } - /* resume data packet rx and tx */ - conn->llcp_enc.pause_rx = 0U; - conn->llcp_enc.pause_tx = 0U; - - /* Procedure complete */ - conn->llcp_ack = conn->llcp_req; - conn->procedure_expire = 0U; + reject_ind_recv(conn, *rx, pdu_rx); break; #endif /* CONFIG_BT_CTLR_LE_ENC */