From 5d80dbd388d93d65fe9faf18ab4094356d1780d8 Mon Sep 17 00:00:00 2001 From: Thomas Ebert Hansen Date: Thu, 19 May 2022 18:19:17 +0200 Subject: [PATCH] Bluetooth: controller: llcp: Fix terminate timer Add the missing terminate timer for the ACL Termination procedure. Signed-off-by: Thomas Ebert Hansen --- subsys/bluetooth/controller/ll_sw/ull_conn.c | 6 ++-- subsys/bluetooth/controller/ll_sw/ull_llcp.c | 28 ++++++++++++++++--- subsys/bluetooth/controller/ll_sw/ull_llcp.h | 3 +- .../controller/ll_sw/ull_llcp_common.c | 11 +++++++- .../controller/ll_sw/ull_llcp_internal.h | 1 + .../controller/ll_sw/ull_llcp_local.c | 5 ++++ 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 000f17f6c43..0fec916a8bc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1592,8 +1592,10 @@ void ull_conn_done(struct node_rx_event_done *done) } } #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ - if (-ETIMEDOUT == ull_cp_prt_elapse(conn, elapsed_event)) { - conn_cleanup(conn, BT_HCI_ERR_LL_RESP_TIMEOUT); + uint8_t error_code; + + if (-ETIMEDOUT == ull_cp_prt_elapse(conn, elapsed_event, &error_code)) { + conn_cleanup(conn, error_code); return; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 1fea6bf9ea2..4f176868e0b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -542,20 +542,40 @@ static int prt_elapse(uint16_t *expire, uint16_t elapsed_event) return 0; } -int ull_cp_prt_elapse(struct ll_conn *conn, uint16_t elapsed_event) +int ull_cp_prt_elapse(struct ll_conn *conn, uint16_t elapsed_event, uint8_t *error_code) { int loc_ret; int rem_ret; loc_ret = prt_elapse(&conn->llcp.local.prt_expire, elapsed_event); - rem_ret = prt_elapse(&conn->llcp.remote.prt_expire, elapsed_event); + if (loc_ret == -ETIMEDOUT) { + /* Local Request Machine timed out */ - if (loc_ret == -ETIMEDOUT || rem_ret == -ETIMEDOUT) { - /* One of the timers expired */ + struct proc_ctx *ctx; + + ctx = llcp_lr_peek(conn); + LL_ASSERT(ctx); + + if (ctx->proc == PROC_TERMINATE) { + /* Active procedure is ACL Termination */ + *error_code = ctx->data.term.error_code; + } else { + *error_code = BT_HCI_ERR_LL_RESP_TIMEOUT; + } + + return -ETIMEDOUT; + } + + rem_ret = prt_elapse(&conn->llcp.remote.prt_expire, elapsed_event); + if (rem_ret == -ETIMEDOUT) { + /* Remote Request Machine timed out */ + + *error_code = BT_HCI_ERR_LL_RESP_TIMEOUT; return -ETIMEDOUT; } /* Both timers are still running */ + *error_code = BT_HCI_ERR_SUCCESS; return 0; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index 961323335b7..011bd3e0c6c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -38,9 +38,10 @@ void ull_cp_release_ntf(struct node_rx_pdu *ntf); /** * @brief Procedure Response Timeout Check * @param elapsed_event The number of elapsed events. + * @param[out] error_code The error code for this timeout. * @return 0 on success, -ETIMEDOUT if timer expired. */ -int ull_cp_prt_elapse(struct ll_conn *conn, uint16_t elapsed_event); +int ull_cp_prt_elapse(struct ll_conn *conn, uint16_t elapsed_event, uint8_t *error_code); void ull_cp_prt_reload_set(struct ll_conn *conn, uint32_t conn_intv); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index d783dc92cc0..a6e0a53d987 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -162,7 +162,16 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) llcp_tx_enqueue(conn, tx); /* Restart procedure response timeout timer */ - llcp_lr_prt_restart(conn); + if (ctx->proc != PROC_TERMINATE) { + /* Use normal timeout value of 40s */ + llcp_lr_prt_restart(conn); + } else { + /* Use supervision timeout value + * NOTE: As the supervision timeout is at most 32s the normal procedure response + * timeout of 40s will never come into play for the ACL Termination procedure. + */ + llcp_lr_prt_restart_with_value(conn, conn->supervision_reload); + } } static void lp_comm_ntf_feature_exchange(struct ll_conn *conn, struct proc_ctx *ctx, diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 38f0e6f7441..c52853d0ea9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -359,6 +359,7 @@ void llcp_tx_resume_data(struct ll_conn *conn, enum llcp_tx_q_pause_data_mask re * LLCP Procedure Response Timeout */ void llcp_lr_prt_restart(struct ll_conn *conn); +void llcp_lr_prt_restart_with_value(struct ll_conn *conn, uint16_t value); void llcp_lr_prt_stop(struct ll_conn *conn); void llcp_rr_prt_restart(struct ll_conn *conn); void llcp_rr_prt_stop(struct ll_conn *conn); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index 12a4f509130..67e94327f06 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -128,6 +128,11 @@ void llcp_lr_prt_restart(struct ll_conn *conn) conn->llcp.local.prt_expire = conn->llcp.prt_reload; } +void llcp_lr_prt_restart_with_value(struct ll_conn *conn, uint16_t value) +{ + conn->llcp.local.prt_expire = value; +} + void llcp_lr_prt_stop(struct ll_conn *conn) { conn->llcp.local.prt_expire = 0U;