2021-11-15 09:41:12 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2020 Demant
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zephyr/types.h>
|
|
|
|
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/bluetooth/hci.h>
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
#include <zephyr/sys/slist.h>
|
|
|
|
#include <zephyr/sys/util.h>
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
#include "hal/ccm.h"
|
|
|
|
|
|
|
|
#include "util/util.h"
|
|
|
|
#include "util/mem.h"
|
|
|
|
#include "util/memq.h"
|
2021-10-31 00:40:25 +02:00
|
|
|
#include "util/dbuf.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
#include "pdu.h"
|
|
|
|
#include "ll.h"
|
|
|
|
#include "ll_settings.h"
|
2022-04-06 12:42:21 +02:00
|
|
|
#include "ll_feat.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
#include "lll.h"
|
|
|
|
#include "lll/lll_df_types.h"
|
|
|
|
#include "lll_conn.h"
|
2022-07-06 15:55:16 +02:00
|
|
|
#include "lll_conn_iso.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
#include "ull_tx_queue.h"
|
|
|
|
|
2022-07-06 15:55:16 +02:00
|
|
|
#include "isoal.h"
|
|
|
|
#include "ull_iso_types.h"
|
|
|
|
#include "ull_conn_iso_types.h"
|
|
|
|
#include "ull_conn_iso_internal.h"
|
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
#include "ull_conn_types.h"
|
|
|
|
#include "ull_conn_internal.h"
|
|
|
|
#include "ull_llcp.h"
|
2022-04-06 12:42:21 +02:00
|
|
|
#include "ull_llcp_features.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
#include "ull_llcp_internal.h"
|
|
|
|
|
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
|
|
|
#define LOG_MODULE_NAME bt_ctlr_ull_llcp_remote
|
|
|
|
#include "common/log.h"
|
|
|
|
#include <soc.h>
|
|
|
|
#include "hal/debug.h"
|
|
|
|
|
|
|
|
static void rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx);
|
|
|
|
static struct proc_ctx *rr_dequeue(struct ll_conn *conn);
|
|
|
|
static void rr_abort(struct ll_conn *conn);
|
|
|
|
|
|
|
|
/* LLCP Remote Request FSM State */
|
|
|
|
enum rr_state {
|
|
|
|
RR_STATE_IDLE,
|
|
|
|
RR_STATE_REJECT,
|
2022-01-21 13:07:40 +01:00
|
|
|
RR_STATE_UNSUPPORTED,
|
2021-11-15 09:41:12 +01:00
|
|
|
RR_STATE_ACTIVE,
|
|
|
|
RR_STATE_DISCONNECT,
|
|
|
|
RR_STATE_TERMINATE,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* LLCP Remote Request FSM Event */
|
|
|
|
enum {
|
|
|
|
/* Procedure prepare */
|
|
|
|
RR_EVT_PREPARE,
|
|
|
|
|
|
|
|
/* Procedure run */
|
|
|
|
RR_EVT_RUN,
|
|
|
|
|
|
|
|
/* Procedure completed */
|
|
|
|
RR_EVT_COMPLETE,
|
|
|
|
|
|
|
|
/* Link connected */
|
|
|
|
RR_EVT_CONNECT,
|
|
|
|
|
|
|
|
/* Link disconnected */
|
|
|
|
RR_EVT_DISCONNECT,
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool proc_with_instant(struct proc_ctx *ctx)
|
|
|
|
{
|
|
|
|
switch (ctx->proc) {
|
2022-01-21 13:07:40 +01:00
|
|
|
case PROC_UNKNOWN:
|
2021-11-15 09:41:12 +01:00
|
|
|
case PROC_FEATURE_EXCHANGE:
|
|
|
|
case PROC_MIN_USED_CHANS:
|
|
|
|
case PROC_LE_PING:
|
|
|
|
case PROC_VERSION_EXCHANGE:
|
|
|
|
case PROC_ENCRYPTION_START:
|
|
|
|
case PROC_ENCRYPTION_PAUSE:
|
2022-03-07 14:51:28 +01:00
|
|
|
case PROC_TERMINATE:
|
|
|
|
case PROC_DATA_LENGTH_UPDATE:
|
|
|
|
case PROC_CTE_REQ:
|
2022-07-06 15:55:16 +02:00
|
|
|
case PROC_CIS_TERMINATE:
|
2021-11-15 09:41:12 +01:00
|
|
|
return 0U;
|
|
|
|
case PROC_PHY_UPDATE:
|
|
|
|
case PROC_CONN_UPDATE:
|
|
|
|
case PROC_CONN_PARAM_REQ:
|
|
|
|
case PROC_CHAN_MAP_UPDATE:
|
|
|
|
return 1U;
|
|
|
|
default:
|
|
|
|
/* Unknown procedure */
|
|
|
|
LL_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0U;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_check_done(struct ll_conn *conn, struct proc_ctx *ctx)
|
|
|
|
{
|
|
|
|
if (ctx->done) {
|
|
|
|
struct proc_ctx *ctx_header;
|
|
|
|
|
|
|
|
ctx_header = llcp_rr_peek(conn);
|
|
|
|
LL_ASSERT(ctx_header == ctx);
|
|
|
|
|
|
|
|
rr_dequeue(conn);
|
2022-03-28 12:43:05 +02:00
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
llcp_proc_ctx_release(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* LLCP Remote Request FSM
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void rr_set_state(struct ll_conn *conn, enum rr_state state)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.state = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_set_incompat(struct ll_conn *conn, enum proc_incompat incompat)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.incompat = incompat;
|
|
|
|
}
|
|
|
|
|
2022-01-18 11:42:30 +01:00
|
|
|
void llcp_rr_set_paused_cmd(struct ll_conn *conn, enum llcp_proc proc)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
|
|
|
conn->llcp.remote.paused_cmd = proc;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP || CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
|
|
|
}
|
|
|
|
|
|
|
|
enum llcp_proc llcp_rr_get_paused_cmd(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
|
|
|
return conn->llcp.remote.paused_cmd;
|
|
|
|
#else
|
|
|
|
return PROC_NONE;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP || CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
|
|
|
}
|
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
static enum proc_incompat rr_get_incompat(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
return conn->llcp.remote.incompat;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_set_collision(struct ll_conn *conn, bool collision)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.collision = collision;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool llcp_rr_get_collision(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
return conn->llcp.remote.collision;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx)
|
|
|
|
{
|
|
|
|
sys_slist_append(&conn->llcp.remote.pend_proc_list, &ctx->node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct proc_ctx *rr_dequeue(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
ctx = (struct proc_ctx *)sys_slist_get(&conn->llcp.remote.pend_proc_list);
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct proc_ctx *llcp_rr_peek(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.remote.pend_proc_list);
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2022-03-29 15:35:27 +02:00
|
|
|
bool llcp_rr_ispaused(struct ll_conn *conn)
|
2021-12-14 11:40:51 +01:00
|
|
|
{
|
2022-03-29 15:35:27 +02:00
|
|
|
return conn->llcp.remote.pause == 1U;
|
|
|
|
}
|
2021-12-14 11:40:51 +01:00
|
|
|
|
2022-03-29 15:35:27 +02:00
|
|
|
void llcp_rr_pause(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.pause = 1U;
|
2021-12-14 11:40:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_resume(struct ll_conn *conn)
|
|
|
|
{
|
2022-03-29 15:35:27 +02:00
|
|
|
conn->llcp.remote.pause = 0U;
|
2021-12-14 11:40:51 +01:00
|
|
|
}
|
|
|
|
|
2022-03-28 12:43:05 +02:00
|
|
|
void llcp_rr_prt_restart(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.prt_expire = conn->llcp.prt_reload;
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_prt_stop(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
conn->llcp.remote.prt_expire = 0U;
|
|
|
|
}
|
2021-12-14 11:40:51 +01:00
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx)
|
|
|
|
{
|
|
|
|
switch (ctx->proc) {
|
2022-01-21 13:07:40 +01:00
|
|
|
case PROC_UNKNOWN:
|
|
|
|
/* Do nothing */
|
|
|
|
break;
|
2021-11-15 09:41:12 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_LE_PING)
|
|
|
|
case PROC_LE_PING:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_PING */
|
|
|
|
case PROC_FEATURE_EXCHANGE:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN)
|
|
|
|
case PROC_MIN_USED_CHANS:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN */
|
|
|
|
case PROC_VERSION_EXCHANGE:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
case PROC_ENCRYPTION_START:
|
|
|
|
case PROC_ENCRYPTION_PAUSE:
|
|
|
|
llcp_rp_enc_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_PERIPHERAL */
|
|
|
|
#ifdef CONFIG_BT_CTLR_PHY
|
|
|
|
case PROC_PHY_UPDATE:
|
|
|
|
llcp_rp_pu_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_PHY */
|
|
|
|
case PROC_CONN_UPDATE:
|
|
|
|
case PROC_CONN_PARAM_REQ:
|
|
|
|
llcp_rp_cu_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
case PROC_TERMINATE:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
case PROC_CHAN_MAP_UPDATE:
|
|
|
|
llcp_rp_chmu_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_PERIPHERAL */
|
|
|
|
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
|
|
|
case PROC_DATA_LENGTH_UPDATE:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
2022-01-08 11:01:24 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
2021-11-15 09:41:12 +01:00
|
|
|
case PROC_CTE_REQ:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
2022-01-08 11:01:24 +01:00
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
2022-07-06 15:55:16 +02:00
|
|
|
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
|
|
|
|
case PROC_CIS_TERMINATE:
|
|
|
|
llcp_rp_comm_rx(conn, ctx, rx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
2021-11-15 09:41:12 +01:00
|
|
|
default:
|
|
|
|
/* Unknown procedure */
|
|
|
|
LL_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rr_check_done(conn, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx)
|
|
|
|
{
|
|
|
|
switch (ctx->proc) {
|
|
|
|
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
|
|
|
case PROC_DATA_LENGTH_UPDATE:
|
|
|
|
llcp_rp_comm_tx_ack(conn, ctx, tx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
|
|
|
#ifdef CONFIG_BT_CTLR_PHY
|
|
|
|
case PROC_PHY_UPDATE:
|
|
|
|
llcp_rp_pu_tx_ack(conn, ctx, tx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_PHY */
|
2022-01-18 11:42:30 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
|
|
|
case PROC_CTE_REQ:
|
|
|
|
llcp_rp_comm_tx_ack(conn, ctx, tx);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
2021-11-15 09:41:12 +01:00
|
|
|
default:
|
|
|
|
/* Ignore tx_ack */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rr_check_done(conn, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_act_run(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
ctx = llcp_rr_peek(conn);
|
|
|
|
|
|
|
|
switch (ctx->proc) {
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_PING)
|
|
|
|
case PROC_LE_PING:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_PING */
|
|
|
|
case PROC_FEATURE_EXCHANGE:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN)
|
|
|
|
case PROC_MIN_USED_CHANS:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN */
|
|
|
|
case PROC_VERSION_EXCHANGE:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
case PROC_ENCRYPTION_START:
|
|
|
|
case PROC_ENCRYPTION_PAUSE:
|
|
|
|
llcp_rp_enc_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_PERIPHERAL */
|
|
|
|
#ifdef CONFIG_BT_CTLR_PHY
|
|
|
|
case PROC_PHY_UPDATE:
|
|
|
|
llcp_rp_pu_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_PHY */
|
|
|
|
case PROC_CONN_UPDATE:
|
|
|
|
case PROC_CONN_PARAM_REQ:
|
|
|
|
llcp_rp_cu_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
case PROC_TERMINATE:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
case PROC_CHAN_MAP_UPDATE:
|
|
|
|
llcp_rp_chmu_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_PERIPHERAL */
|
|
|
|
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
|
|
|
case PROC_DATA_LENGTH_UPDATE:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
2022-01-08 11:01:24 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
2021-11-15 09:41:12 +01:00
|
|
|
case PROC_CTE_REQ:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
2022-01-08 11:01:24 +01:00
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
2022-07-06 15:55:16 +02:00
|
|
|
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
|
|
|
|
case PROC_CIS_TERMINATE:
|
|
|
|
llcp_rp_comm_run(conn, ctx, NULL);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
2021-11-15 09:41:12 +01:00
|
|
|
default:
|
|
|
|
/* Unknown procedure */
|
|
|
|
LL_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rr_check_done(conn, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
|
|
|
|
{
|
|
|
|
struct node_tx *tx;
|
|
|
|
struct pdu_data *pdu;
|
2022-05-11 03:24:06 -07:00
|
|
|
struct proc_ctx *ctx_local;
|
|
|
|
uint8_t reject_code;
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
/* Allocate tx node */
|
|
|
|
tx = llcp_tx_alloc(conn, ctx);
|
|
|
|
LL_ASSERT(tx);
|
|
|
|
|
|
|
|
pdu = (struct pdu_data *)tx->pdu;
|
|
|
|
|
|
|
|
/* Encode LL Control PDU */
|
|
|
|
switch (opcode) {
|
|
|
|
case PDU_DATA_LLCTRL_TYPE_REJECT_IND:
|
2022-05-11 03:24:06 -07:00
|
|
|
ctx_local = llcp_lr_peek(conn);
|
|
|
|
if (ctx_local->proc == ctx->proc ||
|
|
|
|
(ctx_local->proc == PROC_CONN_UPDATE &&
|
|
|
|
ctx->proc == PROC_CONN_PARAM_REQ)) {
|
|
|
|
reject_code = BT_HCI_ERR_LL_PROC_COLLISION;
|
|
|
|
} else {
|
|
|
|
reject_code = BT_HCI_ERR_DIFF_TRANS_COLLISION;
|
|
|
|
}
|
|
|
|
|
2022-04-06 12:42:21 +02:00
|
|
|
if (conn->llcp.fex.valid && feature_ext_rej_ind(conn)) {
|
|
|
|
llcp_pdu_encode_reject_ext_ind(pdu, conn->llcp.remote.reject_opcode,
|
2022-05-11 03:24:06 -07:00
|
|
|
reject_code);
|
2022-04-06 12:42:21 +02:00
|
|
|
} else {
|
2022-05-11 03:24:06 -07:00
|
|
|
llcp_pdu_encode_reject_ind(pdu, reject_code);
|
2022-04-06 12:42:21 +02:00
|
|
|
}
|
2021-11-15 09:41:12 +01:00
|
|
|
break;
|
2022-01-21 13:07:40 +01:00
|
|
|
case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP:
|
|
|
|
llcp_pdu_encode_unknown_rsp(ctx, pdu);
|
|
|
|
break;
|
2021-11-15 09:41:12 +01:00
|
|
|
default:
|
|
|
|
LL_ASSERT(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->tx_opcode = pdu->llctrl.opcode;
|
|
|
|
|
|
|
|
/* Enqueue LL Control PDU towards LLL */
|
|
|
|
llcp_tx_enqueue(conn, tx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_act_reject(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx = llcp_rr_peek(conn);
|
|
|
|
|
|
|
|
LL_ASSERT(ctx != NULL);
|
|
|
|
|
2022-03-29 15:35:27 +02:00
|
|
|
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
|
2021-11-15 09:41:12 +01:00
|
|
|
rr_set_state(conn, RR_STATE_REJECT);
|
|
|
|
} else {
|
|
|
|
rr_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_IND);
|
|
|
|
|
|
|
|
ctx->done = 1U;
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-21 13:07:40 +01:00
|
|
|
static void rr_act_unsupported(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx = llcp_rr_peek(conn);
|
|
|
|
|
|
|
|
LL_ASSERT(ctx != NULL);
|
|
|
|
|
2022-03-29 15:35:27 +02:00
|
|
|
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
|
2022-01-21 13:07:40 +01:00
|
|
|
rr_set_state(conn, RR_STATE_UNSUPPORTED);
|
|
|
|
} else {
|
|
|
|
rr_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP);
|
|
|
|
|
|
|
|
ctx->done = 1U;
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
static void rr_act_complete(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
rr_set_collision(conn, 0U);
|
|
|
|
|
|
|
|
ctx = llcp_rr_peek(conn);
|
|
|
|
LL_ASSERT(ctx != NULL);
|
|
|
|
|
2022-03-28 12:43:05 +02:00
|
|
|
/* Stop procedure response timeout timer */
|
|
|
|
llcp_rr_prt_stop(conn);
|
|
|
|
|
|
|
|
/* Mark the procedure as safe to delete */
|
2021-11-15 09:41:12 +01:00
|
|
|
ctx->done = 1U;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_act_connect(struct ll_conn *conn)
|
|
|
|
{
|
2022-03-07 13:55:11 +01:00
|
|
|
/* Empty on purpose */
|
2021-11-15 09:41:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_act_disconnect(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
ctx = rr_dequeue(conn);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we may have been disconnected in the
|
|
|
|
* middle of a control procedure, in which
|
|
|
|
* case we need to release all contexts
|
|
|
|
*/
|
|
|
|
while (ctx != NULL) {
|
|
|
|
llcp_proc_ctx_release(ctx);
|
|
|
|
ctx = rr_dequeue(conn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_st_disconnect(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
switch (evt) {
|
|
|
|
case RR_EVT_CONNECT:
|
|
|
|
rr_act_connect(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Ignore other evts */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_st_idle(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
2022-03-21 06:47:21 -07:00
|
|
|
struct proc_ctx *ctx_local;
|
2021-11-15 09:41:12 +01:00
|
|
|
|
|
|
|
switch (evt) {
|
|
|
|
case RR_EVT_PREPARE:
|
|
|
|
ctx = llcp_rr_peek(conn);
|
|
|
|
if (ctx) {
|
|
|
|
const enum proc_incompat incompat = rr_get_incompat(conn);
|
|
|
|
const bool periph = !!(conn->lll.role == BT_HCI_ROLE_PERIPHERAL);
|
|
|
|
const bool central = !!(conn->lll.role == BT_HCI_ROLE_CENTRAL);
|
|
|
|
const bool with_instant = proc_with_instant(ctx);
|
|
|
|
|
|
|
|
if (ctx->proc == PROC_TERMINATE) {
|
|
|
|
/* Peer terminate overrides all */
|
|
|
|
|
|
|
|
/* Run remote procedure */
|
|
|
|
rr_act_run(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_TERMINATE);
|
2022-01-21 13:07:40 +01:00
|
|
|
} else if (ctx->proc == PROC_UNKNOWN) {
|
|
|
|
/* Unsupported procedure */
|
|
|
|
|
|
|
|
/* Send LL_UNKNOWN_RSP */
|
|
|
|
struct node_rx_pdu *rx = (struct node_rx_pdu *)param;
|
|
|
|
struct pdu_data *pdu = (struct pdu_data *)rx->pdu;
|
|
|
|
|
|
|
|
ctx->unknown_response.type = pdu->llctrl.opcode;
|
|
|
|
rr_act_unsupported(conn);
|
2021-12-15 09:30:02 +01:00
|
|
|
} else if (!with_instant || incompat == INCOMPAT_NO_COLLISION) {
|
2021-11-15 09:41:12 +01:00
|
|
|
/* No collision
|
|
|
|
* => Run procedure
|
|
|
|
*
|
|
|
|
* Local incompatible procedure request is kept pending.
|
|
|
|
*/
|
|
|
|
|
2022-03-21 06:47:21 -07:00
|
|
|
/*
|
|
|
|
* Pause local incompatible procedure
|
|
|
|
* in case we run a procedure with instant
|
|
|
|
*/
|
2021-11-15 09:41:12 +01:00
|
|
|
rr_set_collision(conn, with_instant);
|
|
|
|
|
|
|
|
/* Run remote procedure */
|
|
|
|
rr_act_run(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_ACTIVE);
|
|
|
|
} else if (periph && incompat == INCOMPAT_RESOLVABLE) {
|
2022-02-07 11:44:29 +01:00
|
|
|
/* Peripheral collision
|
2021-11-15 09:41:12 +01:00
|
|
|
* => Run procedure
|
|
|
|
*
|
|
|
|
* Local periph procedure completes with error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Run remote procedure */
|
|
|
|
rr_act_run(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_ACTIVE);
|
2022-03-21 06:47:21 -07:00
|
|
|
} else if (central && incompat == INCOMPAT_RESOLVABLE) {
|
2022-02-07 11:44:29 +01:00
|
|
|
/* Central collision
|
2021-11-15 09:41:12 +01:00
|
|
|
* => Send reject
|
|
|
|
*
|
|
|
|
* Local central incompatible procedure continues unaffected.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Send reject */
|
|
|
|
struct node_rx_pdu *rx = (struct node_rx_pdu *)param;
|
|
|
|
struct pdu_data *pdu = (struct pdu_data *)rx->pdu;
|
|
|
|
|
|
|
|
conn->llcp.remote.reject_opcode = pdu->llctrl.opcode;
|
|
|
|
rr_act_reject(conn);
|
2022-03-21 06:47:21 -07:00
|
|
|
} else if (incompat == INCOMPAT_RESERVED) {
|
2021-11-15 09:41:12 +01:00
|
|
|
/* Protocol violation.
|
|
|
|
* => Disconnect
|
2022-03-21 06:47:21 -07:00
|
|
|
* See Bluetooth Core Specification Version 5.3 Vol 6, Part B
|
|
|
|
* section 5.3 (page 2879) for error codes
|
2021-11-15 09:41:12 +01:00
|
|
|
*/
|
|
|
|
|
2022-03-21 06:47:21 -07:00
|
|
|
ctx_local = llcp_lr_peek(conn);
|
|
|
|
|
|
|
|
if (ctx_local->proc == ctx->proc ||
|
|
|
|
(ctx_local->proc == PROC_CONN_UPDATE &&
|
|
|
|
ctx->proc == PROC_CONN_PARAM_REQ)) {
|
|
|
|
conn->llcp_terminate.reason_final =
|
|
|
|
BT_HCI_ERR_LL_PROC_COLLISION;
|
|
|
|
} else {
|
|
|
|
conn->llcp_terminate.reason_final =
|
|
|
|
BT_HCI_ERR_DIFF_TRANS_COLLISION;
|
|
|
|
}
|
2021-11-15 09:41:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RR_EVT_DISCONNECT:
|
|
|
|
rr_act_disconnect(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_DISCONNECT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Ignore other evts */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-04-05 14:56:19 +02:00
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
static void rr_st_reject(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
2022-04-05 14:56:19 +02:00
|
|
|
rr_act_reject(conn);
|
2021-11-15 09:41:12 +01:00
|
|
|
}
|
|
|
|
|
2022-01-21 13:07:40 +01:00
|
|
|
static void rr_st_unsupported(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
rr_act_unsupported(conn);
|
|
|
|
}
|
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
static void rr_st_active(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
switch (evt) {
|
|
|
|
case RR_EVT_RUN:
|
|
|
|
if (llcp_rr_peek(conn)) {
|
|
|
|
rr_act_run(conn);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RR_EVT_COMPLETE:
|
|
|
|
rr_act_complete(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
break;
|
|
|
|
case RR_EVT_DISCONNECT:
|
|
|
|
rr_act_disconnect(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_DISCONNECT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Ignore other evts */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_st_terminate(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
switch (evt) {
|
|
|
|
case RR_EVT_RUN:
|
|
|
|
if (llcp_rr_peek(conn)) {
|
|
|
|
rr_act_run(conn);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RR_EVT_COMPLETE:
|
|
|
|
rr_act_complete(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
break;
|
|
|
|
case RR_EVT_DISCONNECT:
|
|
|
|
rr_act_disconnect(conn);
|
|
|
|
rr_set_state(conn, RR_STATE_DISCONNECT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Ignore other evts */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_execute_fsm(struct ll_conn *conn, uint8_t evt, void *param)
|
|
|
|
{
|
|
|
|
switch (conn->llcp.remote.state) {
|
|
|
|
case RR_STATE_DISCONNECT:
|
|
|
|
rr_st_disconnect(conn, evt, param);
|
|
|
|
break;
|
|
|
|
case RR_STATE_IDLE:
|
|
|
|
rr_st_idle(conn, evt, param);
|
|
|
|
break;
|
|
|
|
case RR_STATE_REJECT:
|
|
|
|
rr_st_reject(conn, evt, param);
|
|
|
|
break;
|
2022-01-21 13:07:40 +01:00
|
|
|
case RR_STATE_UNSUPPORTED:
|
|
|
|
rr_st_unsupported(conn, evt, param);
|
|
|
|
break;
|
2021-11-15 09:41:12 +01:00
|
|
|
case RR_STATE_ACTIVE:
|
|
|
|
rr_st_active(conn, evt, param);
|
|
|
|
break;
|
|
|
|
case RR_STATE_TERMINATE:
|
|
|
|
rr_st_terminate(conn, evt, param);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Unknown state */
|
|
|
|
LL_ASSERT(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_init(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
rr_set_state(conn, RR_STATE_DISCONNECT);
|
2022-03-28 12:43:05 +02:00
|
|
|
conn->llcp.remote.prt_expire = 0U;
|
2021-11-15 09:41:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_prepare(struct ll_conn *conn, struct node_rx_pdu *rx)
|
|
|
|
{
|
|
|
|
rr_execute_fsm(conn, RR_EVT_PREPARE, rx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_run(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
rr_execute_fsm(conn, RR_EVT_RUN, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_complete(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
rr_execute_fsm(conn, RR_EVT_COMPLETE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_connect(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
rr_execute_fsm(conn, RR_EVT_CONNECT, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llcp_rr_disconnect(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
rr_execute_fsm(conn, RR_EVT_DISCONNECT, NULL);
|
|
|
|
}
|
|
|
|
|
2022-01-21 13:07:40 +01:00
|
|
|
/*
|
|
|
|
* Create procedure lookup table for any given PDU opcode, these are the opcodes
|
|
|
|
* that can initiate a new remote procedure.
|
|
|
|
*
|
|
|
|
* NOTE: All array elements that are not initialized explicitly are
|
|
|
|
* zero-initialized, which matches PROC_UNKNOWN.
|
|
|
|
*
|
|
|
|
* NOTE: When initializing an array of unknown size, the largest subscript for
|
|
|
|
* which an initializer is specified determines the size of the array being
|
|
|
|
* declared.
|
|
|
|
*/
|
|
|
|
BUILD_ASSERT(0 == PROC_UNKNOWN, "PROC_UNKNOWN must have the value ZERO");
|
|
|
|
|
|
|
|
enum accept_role {
|
|
|
|
/* No role accepts this opcode */
|
|
|
|
ACCEPT_ROLE_NONE = 0,
|
|
|
|
/* Central role accepts this opcode */
|
|
|
|
ACCEPT_ROLE_CENTRAL = (1 << BT_HCI_ROLE_CENTRAL),
|
|
|
|
/* Peripheral role accepts this opcode */
|
|
|
|
ACCEPT_ROLE_PERIPHERAL = (1 << BT_HCI_ROLE_PERIPHERAL),
|
|
|
|
/* Both roles accepts this opcode */
|
|
|
|
ACCEPT_ROLE_BOTH = (ACCEPT_ROLE_CENTRAL | ACCEPT_ROLE_PERIPHERAL),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct proc_role {
|
|
|
|
enum llcp_proc proc;
|
|
|
|
enum accept_role accept;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct proc_role new_proc_lut[] = {
|
|
|
|
#if defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND] = { PROC_CONN_UPDATE, ACCEPT_ROLE_PERIPHERAL },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND] = { PROC_CHAN_MAP_UPDATE, ACCEPT_ROLE_PERIPHERAL },
|
|
|
|
#endif /* CONFIG_BT_PERIPHERAL */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_TERMINATE_IND] = { PROC_TERMINATE, ACCEPT_ROLE_BOTH },
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_ENC_REQ] = { PROC_ENCRYPTION_START, ACCEPT_ROLE_PERIPHERAL },
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_PERIPHERAL */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_ENC_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_START_ENC_REQ] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_START_ENC_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_FEATURE_REQ] = { PROC_FEATURE_EXCHANGE, ACCEPT_ROLE_PERIPHERAL },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_FEATURE_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_ENC) && defined(CONFIG_BT_PERIPHERAL)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ] = { PROC_ENCRYPTION_PAUSE, ACCEPT_ROLE_PERIPHERAL },
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_ENC && CONFIG_BT_PERIPHERAL */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_VERSION_IND] = { PROC_VERSION_EXCHANGE, ACCEPT_ROLE_BOTH },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_REJECT_IND] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_PER_INIT_FEAT_XCHG) && defined(CONFIG_BT_CENTRAL)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PER_INIT_FEAT_XCHG] = { PROC_FEATURE_EXCHANGE, ACCEPT_ROLE_CENTRAL },
|
|
|
|
#endif /* CONFIG_BT_CTLR_PER_INIT_FEAT_XCHG && CONFIG_BT_CENTRAL */
|
|
|
|
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ] = { PROC_CONN_PARAM_REQ, ACCEPT_ROLE_BOTH },
|
|
|
|
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_LE_PING)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PING_REQ] = { PROC_LE_PING, ACCEPT_ROLE_BOTH },
|
|
|
|
#endif /* CONFIG_BT_CTLR_LE_PING */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PING_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_LENGTH_REQ] = { PROC_DATA_LENGTH_UPDATE, ACCEPT_ROLE_BOTH },
|
|
|
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_LENGTH_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_PHY)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PHY_REQ] = { PROC_PHY_UPDATE, ACCEPT_ROLE_BOTH },
|
|
|
|
#endif /* CONFIG_BT_CTLR_PHY */
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PHY_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
|
|
|
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_CENTRAL)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND] = { PROC_MIN_USED_CHANS, ACCEPT_ROLE_CENTRAL },
|
|
|
|
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_CENTRAL */
|
2022-03-22 11:29:17 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
2022-01-21 13:07:40 +01:00
|
|
|
[PDU_DATA_LLCTRL_TYPE_CTE_REQ] = { PROC_CTE_REQ, ACCEPT_ROLE_BOTH },
|
2022-03-22 11:29:17 +01:00
|
|
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
2022-01-21 13:07:40 +01:00
|
|
|
[PDU_DATA_LLCTRL_TYPE_CTE_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE },
|
2022-07-06 15:55:16 +02:00
|
|
|
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
|
|
|
|
[PDU_DATA_LLCTRL_TYPE_CIS_TERMINATE_IND] = { PROC_CIS_TERMINATE, ACCEPT_ROLE_BOTH },
|
|
|
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
2022-01-21 13:07:40 +01:00
|
|
|
};
|
|
|
|
|
2022-01-27 09:50:48 +01:00
|
|
|
void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu)
|
2021-11-15 09:41:12 +01:00
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
struct pdu_data *pdu;
|
|
|
|
uint8_t proc = PROC_UNKNOWN;
|
|
|
|
|
|
|
|
pdu = (struct pdu_data *)rx->pdu;
|
|
|
|
|
2022-01-21 13:07:40 +01:00
|
|
|
/* Is this a valid opcode */
|
2022-01-27 09:50:48 +01:00
|
|
|
if (valid_pdu && pdu->llctrl.opcode < ARRAY_SIZE(new_proc_lut)) {
|
2022-01-21 13:07:40 +01:00
|
|
|
/* Lookup procedure */
|
|
|
|
uint8_t role_mask = (1 << conn->lll.role);
|
|
|
|
struct proc_role pr = new_proc_lut[pdu->llctrl.opcode];
|
|
|
|
|
|
|
|
if (pr.accept & role_mask) {
|
|
|
|
proc = pr.proc;
|
|
|
|
}
|
2021-11-15 09:41:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (proc == PROC_TERMINATE) {
|
|
|
|
rr_abort(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = llcp_create_remote_procedure(proc);
|
|
|
|
if (!ctx) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enqueue procedure */
|
|
|
|
rr_enqueue(conn, ctx);
|
|
|
|
|
|
|
|
/* Prepare procedure */
|
|
|
|
llcp_rr_prepare(conn, rx);
|
|
|
|
|
2022-01-21 13:07:40 +01:00
|
|
|
rr_check_done(conn, ctx);
|
|
|
|
|
2021-11-15 09:41:12 +01:00
|
|
|
/* Handle PDU */
|
|
|
|
ctx = llcp_rr_peek(conn);
|
|
|
|
if (ctx) {
|
|
|
|
llcp_rr_rx(conn, ctx, rx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rr_abort(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
struct proc_ctx *ctx;
|
|
|
|
|
|
|
|
/* Flush all pending procedures */
|
|
|
|
ctx = rr_dequeue(conn);
|
|
|
|
while (ctx) {
|
|
|
|
llcp_proc_ctx_release(ctx);
|
|
|
|
ctx = rr_dequeue(conn);
|
|
|
|
}
|
|
|
|
|
2022-03-28 12:43:05 +02:00
|
|
|
llcp_rr_prt_stop(conn);
|
2021-11-15 09:41:12 +01:00
|
|
|
rr_set_collision(conn, 0U);
|
|
|
|
rr_set_state(conn, RR_STATE_IDLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ZTEST_UNITTEST
|
|
|
|
|
|
|
|
bool rr_is_disconnected(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
return conn->llcp.remote.state == RR_STATE_DISCONNECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool rr_is_idle(struct ll_conn *conn)
|
|
|
|
{
|
|
|
|
return conn->llcp.remote.state == RR_STATE_IDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_int_remote_pending_requests(void)
|
|
|
|
{
|
|
|
|
struct ll_conn conn;
|
|
|
|
struct proc_ctx *peek_ctx;
|
|
|
|
struct proc_ctx *dequeue_ctx;
|
|
|
|
struct proc_ctx ctx;
|
|
|
|
|
|
|
|
ull_cp_init();
|
|
|
|
ull_tx_q_init(&conn.tx_q);
|
|
|
|
ull_llcp_init(&conn);
|
|
|
|
|
|
|
|
peek_ctx = llcp_rr_peek(&conn);
|
|
|
|
zassert_is_null(peek_ctx, NULL);
|
|
|
|
|
|
|
|
dequeue_ctx = rr_dequeue(&conn);
|
|
|
|
zassert_is_null(dequeue_ctx, NULL);
|
|
|
|
|
|
|
|
rr_enqueue(&conn, &ctx);
|
|
|
|
peek_ctx = (struct proc_ctx *)sys_slist_peek_head(&conn.llcp.remote.pend_proc_list);
|
|
|
|
zassert_equal_ptr(peek_ctx, &ctx, NULL);
|
|
|
|
|
|
|
|
peek_ctx = llcp_rr_peek(&conn);
|
|
|
|
zassert_equal_ptr(peek_ctx, &ctx, NULL);
|
|
|
|
|
|
|
|
dequeue_ctx = rr_dequeue(&conn);
|
|
|
|
zassert_equal_ptr(dequeue_ctx, &ctx, NULL);
|
|
|
|
|
|
|
|
peek_ctx = llcp_rr_peek(&conn);
|
|
|
|
zassert_is_null(peek_ctx, NULL);
|
|
|
|
|
|
|
|
dequeue_ctx = rr_dequeue(&conn);
|
|
|
|
zassert_is_null(dequeue_ctx, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|