Bluetooth: controller: llcp: Fix terminate timer

Add the missing terminate timer for the ACL Termination procedure.

Signed-off-by: Thomas Ebert Hansen <thoh@oticon.com>
This commit is contained in:
Thomas Ebert Hansen 2022-05-19 18:19:17 +02:00 committed by Carles Cufí
commit 5d80dbd388
6 changed files with 46 additions and 8 deletions

View file

@ -1592,8 +1592,10 @@ void ull_conn_done(struct node_rx_event_done *done)
} }
} }
#else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */
if (-ETIMEDOUT == ull_cp_prt_elapse(conn, elapsed_event)) { uint8_t error_code;
conn_cleanup(conn, BT_HCI_ERR_LL_RESP_TIMEOUT);
if (-ETIMEDOUT == ull_cp_prt_elapse(conn, elapsed_event, &error_code)) {
conn_cleanup(conn, error_code);
return; return;
} }

View file

@ -542,20 +542,40 @@ static int prt_elapse(uint16_t *expire, uint16_t elapsed_event)
return 0; 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 loc_ret;
int rem_ret; int rem_ret;
loc_ret = prt_elapse(&conn->llcp.local.prt_expire, elapsed_event); 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) { struct proc_ctx *ctx;
/* One of the timers expired */
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; return -ETIMEDOUT;
} }
/* Both timers are still running */ /* Both timers are still running */
*error_code = BT_HCI_ERR_SUCCESS;
return 0; return 0;
} }

View file

@ -38,9 +38,10 @@ void ull_cp_release_ntf(struct node_rx_pdu *ntf);
/** /**
* @brief Procedure Response Timeout Check * @brief Procedure Response Timeout Check
* @param elapsed_event The number of elapsed events. * @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. * @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); void ull_cp_prt_reload_set(struct ll_conn *conn, uint32_t conn_intv);

View file

@ -162,7 +162,16 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
llcp_tx_enqueue(conn, tx); llcp_tx_enqueue(conn, tx);
/* Restart procedure response timeout timer */ /* 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, static void lp_comm_ntf_feature_exchange(struct ll_conn *conn, struct proc_ctx *ctx,

View file

@ -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 * LLCP Procedure Response Timeout
*/ */
void llcp_lr_prt_restart(struct ll_conn *conn); 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_lr_prt_stop(struct ll_conn *conn);
void llcp_rr_prt_restart(struct ll_conn *conn); void llcp_rr_prt_restart(struct ll_conn *conn);
void llcp_rr_prt_stop(struct ll_conn *conn); void llcp_rr_prt_stop(struct ll_conn *conn);

View file

@ -128,6 +128,11 @@ void llcp_lr_prt_restart(struct ll_conn *conn)
conn->llcp.local.prt_expire = conn->llcp.prt_reload; 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) void llcp_lr_prt_stop(struct ll_conn *conn)
{ {
conn->llcp.local.prt_expire = 0U; conn->llcp.local.prt_expire = 0U;