Bluetooth: controller: implement connection termination on invalid pdus
When a running procedure receives a REJECT or UNKNOWN_RSP PDU that is not an expected part of the procedure flow this leads to termination of the connection This affects procedures: CU/CPR, CTE, PHY, PING, DLE, FEX, VEX, CHMU Unit tests are updated to cover the updated behaviour. Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
parent
0b87ebbdd3
commit
d8f0c1adf6
15 changed files with 1343 additions and 39 deletions
|
@ -186,6 +186,21 @@ static void lp_chmu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint
|
|||
}
|
||||
}
|
||||
|
||||
void llcp_lp_chmu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx)
|
||||
{
|
||||
struct pdu_data *pdu = (struct pdu_data *)rx->pdu;
|
||||
|
||||
switch (pdu->llctrl.opcode) {
|
||||
default:
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CHMU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void llcp_lp_chmu_init_proc(struct proc_ctx *ctx)
|
||||
{
|
||||
ctx->state = LP_CHMU_STATE_IDLE;
|
||||
|
@ -195,6 +210,7 @@ void llcp_lp_chmu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param)
|
|||
{
|
||||
lp_chmu_execute_fsm(conn, ctx, LP_CHMU_EVT_RUN, param);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
|
@ -285,8 +301,12 @@ void llcp_rp_chmu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_
|
|||
rp_chmu_execute_fsm(conn, ctx, RP_CHMU_EVT_RX_CHAN_MAP_IND, pdu);
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CHMU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -169,18 +169,11 @@ static void lp_comm_ntf_feature_exchange(struct ll_conn *conn, struct proc_ctx *
|
|||
case PDU_DATA_LLCTRL_TYPE_FEATURE_RSP:
|
||||
llcp_ntf_encode_feature_rsp(conn, pdu);
|
||||
break;
|
||||
case PDU_DATA_LLCTRL_TYPE_PER_INIT_FEAT_XCHG:
|
||||
case PDU_DATA_LLCTRL_TYPE_FEATURE_REQ:
|
||||
/*
|
||||
* No notification on feature-request or periph-feature request
|
||||
* TODO: probably handle as an unexpected call
|
||||
*/
|
||||
break;
|
||||
case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP:
|
||||
llcp_ntf_encode_unknown_rsp(ctx, pdu);
|
||||
break;
|
||||
default:
|
||||
/* TODO: define behaviour for unexpected PDU */
|
||||
/* Unexpected PDU, should not get through, so ASSERT */
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +186,7 @@ static void lp_comm_ntf_version_ind(struct ll_conn *conn, struct proc_ctx *ctx,
|
|||
llcp_ntf_encode_version_ind(conn, pdu);
|
||||
break;
|
||||
default:
|
||||
/* TODO: define behaviour for unexpected PDU */
|
||||
/* Unexpected PDU, should not get through, so ASSERT */
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +237,7 @@ static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, stru
|
|||
llcp_ntf_encode_reject_ext_ind(ctx, pdu);
|
||||
break;
|
||||
default:
|
||||
/* TODO (ppryga): Update when behavior for unexpected PDU is defined */
|
||||
/* Unexpected PDU, should not get through, so ASSERT */
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +283,15 @@ static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
|||
ll_rx_sched();
|
||||
}
|
||||
|
||||
static void lp_comm_terminate_invalid_pdu(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||
{
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
}
|
||||
|
||||
static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
|
||||
{
|
||||
switch (ctx->proc) {
|
||||
|
@ -301,17 +303,23 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
|||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
} else {
|
||||
/* Illegal response opcode */
|
||||
LL_ASSERT(0);
|
||||
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_LE_PING */
|
||||
case PROC_FEATURE_EXCHANGE:
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = LP_COMMON_STATE_WAIT_NTF;
|
||||
if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP ||
|
||||
ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FEATURE_RSP) {
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = LP_COMMON_STATE_WAIT_NTF;
|
||||
} else {
|
||||
lp_comm_ntf(conn, ctx);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
}
|
||||
} else {
|
||||
lp_comm_ntf(conn, ctx);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
/* Illegal response opcode */
|
||||
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||
}
|
||||
break;
|
||||
#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL)
|
||||
|
@ -321,12 +329,17 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
|||
break;
|
||||
#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */
|
||||
case PROC_VERSION_EXCHANGE:
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = LP_COMMON_STATE_WAIT_NTF;
|
||||
if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_VERSION_IND) {
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = LP_COMMON_STATE_WAIT_NTF;
|
||||
} else {
|
||||
lp_comm_ntf(conn, ctx);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
}
|
||||
} else {
|
||||
lp_comm_ntf(conn, ctx);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
/* Illegal response opcode */
|
||||
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||
}
|
||||
break;
|
||||
case PROC_TERMINATE:
|
||||
|
@ -339,7 +352,7 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
|||
break;
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
case PROC_DATA_LENGTH_UPDATE:
|
||||
if (ctx->response_opcode != PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) {
|
||||
if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_LENGTH_RSP) {
|
||||
/* Apply changes in data lengths/times */
|
||||
uint8_t dle_changed = ull_dle_update_eff(conn);
|
||||
|
||||
|
@ -353,12 +366,16 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
|||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
}
|
||||
} else {
|
||||
} else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) {
|
||||
/* Peer does not accept DLU, so disable on current connection */
|
||||
feature_unmask_features(conn, LL_FEAT_BIT_DLE);
|
||||
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
} else {
|
||||
/* Illegal response opcode */
|
||||
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ull_cp_remote_dle_pending(conn)) {
|
||||
|
@ -402,6 +419,9 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
|||
*/
|
||||
ull_cp_cte_req_set_disable(conn);
|
||||
ctx->state = LP_COMMON_STATE_IDLE;
|
||||
} else {
|
||||
/* Illegal response opcode */
|
||||
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||
}
|
||||
|
||||
if (ctx->state == LP_COMMON_STATE_IDLE) {
|
||||
|
@ -627,6 +647,9 @@ static void lp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct
|
|||
case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
|
||||
llcp_pdu_decode_reject_ext_ind(ctx, pdu);
|
||||
break;
|
||||
case PDU_DATA_LLCTRL_TYPE_REJECT_IND:
|
||||
/* Empty on purpose, as we don't care about the PDU content, we'll disconnect */
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
|
|
|
@ -212,6 +212,7 @@ static void lp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
|
|||
break;
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
@ -601,8 +602,11 @@ void llcp_lp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
lp_cu_execute_fsm(conn, ctx, LP_CU_EVT_REJECT, pdu);
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -652,6 +656,7 @@ static void rp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
|
|||
llcp_pdu_encode_unknown_rsp(ctx, pdu);
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
@ -1079,8 +1084,11 @@ void llcp_rp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
rp_cu_execute_fsm(conn, ctx, RP_CU_EVT_CONN_UPDATE_IND, pdu);
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,6 +413,7 @@ void llcp_lp_cu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param);
|
|||
/*
|
||||
* LLCP Local Channel Map Update
|
||||
*/
|
||||
void llcp_lp_chmu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx);
|
||||
void llcp_lp_chmu_init_proc(struct proc_ctx *ctx);
|
||||
void llcp_lp_chmu_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param);
|
||||
|
||||
|
|
|
@ -170,6 +170,11 @@ void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *
|
|||
case PROC_TERMINATE:
|
||||
llcp_lp_comm_rx(conn, ctx, rx);
|
||||
break;
|
||||
#if defined(CONFIG_BT_CENTRAL)
|
||||
case PROC_CHAN_MAP_UPDATE:
|
||||
llcp_lp_chmu_rx(conn, ctx, rx);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
|
||||
case PROC_DATA_LENGTH_UPDATE:
|
||||
llcp_lp_comm_rx(conn, ctx, rx);
|
||||
|
|
|
@ -767,8 +767,12 @@ void llcp_lp_pu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
lp_pu_execute_fsm(conn, ctx, LP_PU_EVT_REJECT, pdu);
|
||||
break;
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_PU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1145,8 +1149,12 @@ void llcp_rp_pu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
break;
|
||||
#endif /* CONFIG_BT_PERIPHERAL */
|
||||
default:
|
||||
/* Unknown opcode */
|
||||
LL_ASSERT(0);
|
||||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_PU_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -569,10 +569,10 @@ static void rr_st_idle(struct ll_conn *conn, uint8_t evt, void *param)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rr_st_reject(struct ll_conn *conn, uint8_t evt, void *param)
|
||||
{
|
||||
/* TODO */
|
||||
LL_ASSERT(0);
|
||||
rr_act_reject(conn);
|
||||
}
|
||||
|
||||
static void rr_st_unsupported(struct ll_conn *conn, uint8_t evt, void *param)
|
||||
|
|
|
@ -132,6 +132,77 @@ void test_channel_map_update_central_loc(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_channel_map_update_central_invalid(void)
|
||||
{
|
||||
uint8_t chm[5] = { 0x00, 0x04, 0x05, 0x06, 0x00 };
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_CHAN_MAP_IND
|
||||
};
|
||||
struct pdu_data_llctrl_chan_map_ind chmu_ind = {
|
||||
.instant = 6,
|
||||
.chm = { 0x00, 0x04, 0x05, 0x06, 0x00 },
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
err = ull_cp_chan_map_update(&conn, chm);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CHAN_MAP_UPDATE_IND, &conn, &tx, &chmu_ind);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* There should NOT be a host notification */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Inject invalid 'RSP' */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_channel_map_update_periph_rem(void)
|
||||
{
|
||||
uint8_t chm[5] = { 0x00, 0x04, 0x05, 0x06, 0x00 };
|
||||
|
@ -203,6 +274,65 @@ void test_channel_map_update_periph_rem(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_channel_map_update_periph_invalid(void)
|
||||
{
|
||||
struct pdu_data_llctrl_chan_map_ind chmu_ind = {
|
||||
.instant = 6,
|
||||
.chm = { 0x00, 0x04, 0x05, 0x06, 0x00 },
|
||||
};
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_UNUSED
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* RX */
|
||||
lt_tx(LL_CHAN_MAP_UPDATE_IND, &conn, &chmu_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Inject invalid 'RSP' */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_channel_map_update_periph_loc(void)
|
||||
{
|
||||
uint8_t err;
|
||||
|
@ -226,8 +356,12 @@ void test_main(void)
|
|||
ztest_test_suite(chmu,
|
||||
ztest_unit_test_setup_teardown(test_channel_map_update_central_loc, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_channel_map_update_central_invalid,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_channel_map_update_periph_rem, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_channel_map_update_periph_invalid,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_channel_map_update_periph_loc, setup,
|
||||
unit_test_noop));
|
||||
|
||||
|
|
|
@ -336,7 +336,6 @@ void test_conn_update_central_loc_invalid_param_rsp(void)
|
|||
.error_code = BT_HCI_ERR_INVALID_LL_PARAM
|
||||
};
|
||||
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
|
@ -377,6 +376,72 @@ void test_conn_update_central_loc_invalid_param_rsp(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated Connection Parameters Request procedure.
|
||||
* Central requests change in LE connection parameters, peripheral’s Host accepts.
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_C | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | LE Connection Update | |
|
||||
* |-------------------------->| |
|
||||
* | | LL_CONNECTION_PARAM_REQ |
|
||||
* | |-------------------------->|
|
||||
* | | |
|
||||
* | | LL_REJECT_IND |
|
||||
* | |<--------------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
* | | |
|
||||
*/
|
||||
void test_conn_update_central_loc_invalid_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate a Connection Parameter Request Procedure */
|
||||
err = ull_cp_conn_update(&conn, INTVL_MIN, INTVL_MAX, LATENCY, TIMEOUT);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CONNECTION_PARAM_REQ, &conn, &tx, &conn_param_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated Connection Parameters Request procedure.
|
||||
* Central requests change in LE connection parameters, peripheral’s Host rejects.
|
||||
|
@ -2147,6 +2212,239 @@ void test_conn_update_periph_rem_invalid_req(void)
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated Connection Parameters Request procedure.
|
||||
* Central requests change in LE connection parameters, peripheral’s Host accepts.
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_S | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | | LL_CONNECTION_PARAM_REQ |
|
||||
* | |<--------------------------|
|
||||
* | | |
|
||||
* | LE Remote Connection | |
|
||||
* | Parameter Request | |
|
||||
* |<--------------------------| |
|
||||
* | LE Remote Connection | |
|
||||
* | Parameter Request | |
|
||||
* | Reply | |
|
||||
* |-------------------------->| |
|
||||
* | | |
|
||||
* | | LL_CONNECTION_PARAM_RSP |
|
||||
* | |-------------------------->|
|
||||
* | | |
|
||||
* | | LL_<INVALID_IND> |
|
||||
* | |<--------------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
* | | |
|
||||
*/
|
||||
void test_conn_update_periph_rem_invalid_ind(void)
|
||||
{
|
||||
struct node_tx *tx;
|
||||
struct node_rx_pdu *ntf;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP,
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_CONNECTION_PARAM_REQ, &conn, &conn_param_req);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* There should be one host notification */
|
||||
ut_rx_pdu(LL_CONNECTION_PARAM_REQ, &ntf, &conn_param_req);
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Release Ntf */
|
||||
ull_cp_release_ntf(ntf);
|
||||
|
||||
/*******************/
|
||||
|
||||
ull_cp_conn_param_req_reply(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CONNECTION_PARAM_RSP, &conn, &tx, &conn_param_rsp);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_CONNECTION_PARAM_REQ, &conn, &conn_param_req);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* There should be one host notification */
|
||||
ut_rx_pdu(LL_CONNECTION_PARAM_REQ, &ntf, &conn_param_req);
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Release Ntf */
|
||||
ull_cp_release_ntf(ntf);
|
||||
|
||||
/*******************/
|
||||
|
||||
ull_cp_conn_param_req_reply(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CONNECTION_PARAM_RSP, &conn, &tx, &conn_param_rsp);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_CONNECTION_PARAM_REQ, &conn, &conn_param_req);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* There should be one host notification */
|
||||
ut_rx_pdu(LL_CONNECTION_PARAM_REQ, &ntf, &conn_param_req);
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Release Ntf */
|
||||
ull_cp_release_ntf(ntf);
|
||||
|
||||
/*******************/
|
||||
|
||||
ull_cp_conn_param_req_reply(&conn);
|
||||
|
||||
/*******************/
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CONNECTION_PARAM_RSP, &conn, &tx, &conn_param_rsp);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated Connection Parameters Request procedure.
|
||||
* Central requests change in LE connection parameters, peripheral’s Host rejects.
|
||||
|
@ -2792,6 +3090,8 @@ void test_main(void)
|
|||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_central_loc_invalid_param_rsp,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_central_loc_invalid_rsp,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_central_loc_reject,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_central_loc_remote_legacy,
|
||||
|
@ -2833,6 +3133,8 @@ void test_main(void)
|
|||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_periph_rem_invalid_req,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_periph_rem_invalid_ind,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_periph_rem_reject,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_conn_update_periph_rem_unsupp_feat,
|
||||
|
|
|
@ -114,6 +114,112 @@ void test_cte_req_central_local(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/* Tests of invalid rsp execution of CTE Request Procedure */
|
||||
|
||||
/* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start initiation | |
|
||||
* | CTE Request Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | |
|
||||
* | | LL_LE_CTE_REQ |
|
||||
* | |------------------>|
|
||||
* | | |
|
||||
* | | LL_<INVALID>_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
*/
|
||||
void test_cte_req_central_local_invalid_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_CTE_REQ
|
||||
};
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_cte_req local_cte_req = {
|
||||
.cte_type_req = BT_HCI_LE_AOA_CTE,
|
||||
.min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN,
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate an CTE Request Procedure */
|
||||
err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CTE_REQ, &conn, &tx, &local_cte_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Initiate another CTE Request Procedure */
|
||||
err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_CTE_REQ, &conn, &tx, &local_cte_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
|
@ -1364,6 +1470,8 @@ void test_main(void)
|
|||
ztest_test_suite(
|
||||
cte_req,
|
||||
ztest_unit_test_setup_teardown(test_cte_req_central_local, setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_cte_req_central_local_invalid_rsp, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_cte_req_peripheral_local, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_cte_req_central_remote, setup, unit_test_noop),
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "ull_llcp.h"
|
||||
#include "ull_conn_internal.h"
|
||||
#include "ull_llcp_internal.h"
|
||||
#include "ull_llcp_features.h"
|
||||
|
||||
#include "helper_pdu.h"
|
||||
#include "helper_util.h"
|
||||
|
@ -48,7 +49,7 @@ static void setup(void)
|
|||
test_setup(&conn);
|
||||
}
|
||||
|
||||
/*C
|
||||
/*
|
||||
* Locally triggered Data Length Update procedure
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
|
@ -128,6 +129,189 @@ void test_data_length_update_central_loc(void)
|
|||
conn.lll.event_counter);
|
||||
}
|
||||
|
||||
/*
|
||||
* Locally triggered Data Length Update procedure
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | Data Length Update Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | (251,2120,211,1800) |
|
||||
* | | LL_DATA_LENGTH_UPDATE_REQ |
|
||||
* | |----------------------------->|
|
||||
* | | |
|
||||
* | | LL_UNKNOWN_RSP |
|
||||
* | |<-----------------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~ Unmask DLE support ~~~~~~~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
* | | |
|
||||
*/
|
||||
void test_data_length_update_central_loc_unknown_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_LENGTH_REQ
|
||||
};
|
||||
struct pdu_data_llctrl_length_req local_length_req = { 251, 2120, 211, 1800 };
|
||||
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
/* Init DLE data */
|
||||
ull_conn_default_tx_octets_set(251);
|
||||
ull_conn_default_tx_time_set(2120);
|
||||
ull_dle_init(&conn, PHY_1M);
|
||||
|
||||
/* Confirm DLE is indicated as supported */
|
||||
zassert_equal(feature_dle(&conn), true, "DLE Feature masked out");
|
||||
|
||||
/* Initiate a Data Length Update Procedure */
|
||||
err = ull_cp_data_length_update(&conn, 211, 1800);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
event_prepare(&conn);
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LENGTH_REQ, &conn, &tx, &local_length_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* TX Ack */
|
||||
event_tx_ack(&conn, tx);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Confirm DLE is no longer indicated as supported */
|
||||
zassert_equal(feature_dle(&conn), false, "DLE Feature not masked out");
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* Locally triggered Data Length Update procedure
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | Data Length Update Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | (251,2120,211,1800) |
|
||||
* | | LL_DATA_LENGTH_UPDATE_REQ |
|
||||
* | |----------------------------->|
|
||||
* | | |
|
||||
* | | LL_<INVALID>_RSP |
|
||||
* | |<-----------------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
* | | |
|
||||
*/
|
||||
void test_data_length_update_central_loc_invalid_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_REQ,
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
|
||||
struct pdu_data_llctrl_length_req local_length_req = { 251, 2120, 211, 1800 };
|
||||
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
/* Init DLE data */
|
||||
ull_conn_default_tx_octets_set(251);
|
||||
ull_conn_default_tx_time_set(2120);
|
||||
ull_dle_init(&conn, PHY_1M);
|
||||
|
||||
/* Initiate a Data Length Update Procedure */
|
||||
err = ull_cp_data_length_update(&conn, 211, 1800);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
event_prepare(&conn);
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LENGTH_REQ, &conn, &tx, &local_length_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* TX Ack */
|
||||
event_tx_ack(&conn, tx);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Init DLE data */
|
||||
ull_conn_default_tx_octets_set(251);
|
||||
ull_conn_default_tx_time_set(2120);
|
||||
ull_dle_init(&conn, PHY_1M);
|
||||
|
||||
/* Initiate another Data Length Update Procedure */
|
||||
err = ull_cp_data_length_update(&conn, 211, 1800);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
event_prepare(&conn);
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LENGTH_REQ, &conn, &tx, &local_length_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* TX Ack */
|
||||
event_tx_ack(&conn, tx);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* Locally triggered Data Length Update procedure - with no update to eff and thus no ntf
|
||||
*
|
||||
|
@ -648,6 +832,10 @@ void test_main(void)
|
|||
data_length_update_central,
|
||||
ztest_unit_test_setup_teardown(test_data_length_update_central_loc, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_data_length_update_central_loc_unknown_rsp,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_data_length_update_central_loc_invalid_rsp,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_data_length_update_central_loc_no_eff_change,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_data_length_update_central_loc_no_eff_change2,
|
||||
|
|
|
@ -132,6 +132,106 @@ void test_feat_exchange_central_loc(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | Feature Exchange Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | |
|
||||
* | | LL_FEATURE_REQ |
|
||||
* | |------------------>|
|
||||
* | | |
|
||||
* | | LL_<INVALID>_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
*/
|
||||
void test_feat_exchange_central_loc_invalid_rsp(void)
|
||||
{
|
||||
uint64_t err;
|
||||
struct pdu_data_llctrl_feature_req local_feature_req;
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_FEATURE_REQ,
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct node_tx *tx;
|
||||
|
||||
|
||||
sys_put_le64(DEFAULT_FEATURE, local_feature_req.features);
|
||||
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate a Feature Exchange Procedure */
|
||||
err = ull_cp_feature_exchange(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
event_prepare(&conn);
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_FEATURE_REQ, &conn, &tx, &local_feature_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate another Feature Exchange Procedure */
|
||||
err = ull_cp_feature_exchange(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
event_prepare(&conn);
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_FEATURE_REQ, &conn, &tx, &local_feature_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_feat_exchange_central_loc_2(void)
|
||||
{
|
||||
uint8_t err;
|
||||
|
@ -156,7 +256,7 @@ void test_feat_exchange_central_loc_2(void)
|
|||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | | LL_PERIPH_FEAT_XCHG |
|
||||
* | | LL_PERIPH_FEAT_XCHG |
|
||||
* | |<------------------------|
|
||||
* | | |
|
||||
* | | LL_FEATURE_RSP |
|
||||
|
@ -430,6 +530,8 @@ void test_main(void)
|
|||
ztest_test_suite(feat_exchange_central,
|
||||
ztest_unit_test_setup_teardown(test_feat_exchange_central_loc, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_feat_exchange_central_loc_invalid_rsp,
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_feat_exchange_central_loc_2, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_feat_exchange_central_rem, setup,
|
||||
|
|
|
@ -57,6 +57,15 @@ static void setup(void)
|
|||
* | | LL_LE_PING_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | LE Ping Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | |
|
||||
* | | LL_LE_PING_REQ |
|
||||
* | |------------------>|
|
||||
* | | |
|
||||
* | | LL_UNKNOWN_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
*/
|
||||
void test_ping_central_loc(void)
|
||||
|
@ -68,6 +77,10 @@ void test_ping_central_loc(void)
|
|||
|
||||
struct pdu_data_llctrl_ping_rsp remote_ping_rsp = {};
|
||||
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_PING_REQ
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
|
@ -99,6 +112,135 @@ void test_ping_central_loc(void)
|
|||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Initiate another LE Ping Procedure */
|
||||
err = ull_cp_le_ping(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LE_PING_REQ, &conn, &tx, &local_ping_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
}
|
||||
|
||||
/* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | LE Ping Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | |
|
||||
* | | LL_LE_PING_REQ |
|
||||
* | |------------------>|
|
||||
* | | |
|
||||
* | | LL_<INVALID>_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
*/
|
||||
void test_ping_central_loc_invalid_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_PING_REQ,
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
struct pdu_data_llctrl_ping_req local_ping_req = {};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate an LE Ping Procedure */
|
||||
err = ull_cp_le_ping(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LE_PING_REQ, &conn, &tx, &local_ping_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Initiate another LE Ping Procedure */
|
||||
err = ull_cp_le_ping(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_LE_PING_REQ, &conn, &tx, &local_ping_req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release tx node */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should not be a host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
}
|
||||
|
||||
/* +-----+ +-------+ +-----+
|
||||
|
@ -272,6 +414,8 @@ void test_main(void)
|
|||
ztest_test_suite(ping,
|
||||
ztest_unit_test_setup_teardown(test_ping_central_loc, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_ping_central_loc_invalid_rsp, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_ping_periph_loc, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_ping_central_rem, setup,
|
||||
|
|
|
@ -219,6 +219,54 @@ void test_phy_update_central_loc(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_phy_update_central_loc_invalid(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M };
|
||||
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = { };
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate an PHY Update Procedure */
|
||||
err = ull_cp_phy_update(&conn, PHY_2M, PREFER_S8_CODING, PHY_2M, 1);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_PHY_REQ, &conn, &tx, &req);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* TX Ack */
|
||||
event_tx_ack(&conn, tx);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should be nohost notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_phy_update_central_loc_unsupp_feat(void)
|
||||
{
|
||||
uint8_t err;
|
||||
|
@ -567,6 +615,62 @@ void test_phy_update_periph_rem(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_phy_update_periph_rem_invalid(void)
|
||||
{
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_phy_req req = { .rx_phys = PHY_1M, .tx_phys = PHY_2M };
|
||||
struct pdu_data_llctrl_phy_req rsp = { .rx_phys = PHY_1M | PHY_2M | PHY_CODED,
|
||||
.tx_phys = PHY_1M | PHY_2M | PHY_CODED };
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = { };
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should NOT have a LL Control PDU */
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_PHY_REQ, &conn, &req);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* We received a REQ, so data tx should be paused */
|
||||
zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused");
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_PHY_RSP, &conn, &tx, &rsp);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Inject invalid PDU */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* TX Ack */
|
||||
event_tx_ack(&conn, tx);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_phy_update_central_loc_collision(void)
|
||||
{
|
||||
uint8_t err;
|
||||
|
@ -1044,12 +1148,16 @@ void test_main(void)
|
|||
{
|
||||
ztest_test_suite(
|
||||
phy,
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_loc_invalid, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_loc, setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_loc_unsupp_feat, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_rem, setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_periph_loc, setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_periph_rem, setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_periph_rem_invalid, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_loc_collision, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_phy_update_central_rem_collision, setup,
|
||||
|
|
|
@ -111,6 +111,156 @@ void test_version_exchange_central_loc(void)
|
|||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
/* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_A | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | Start | |
|
||||
* | Version Exchange Proc. | |
|
||||
* |--------------------------->| |
|
||||
* | | |
|
||||
* | | LL_VERSION_IND |
|
||||
* | |------------------>|
|
||||
* | | |
|
||||
* | | LL_<INVALID>_RSP |
|
||||
* | |<------------------|
|
||||
* | | |
|
||||
* ~~~~~~~~~~~~~~~~~~~ TERMINATE CONN ~~~~~~~~~~~~~~~~~~
|
||||
* | | |
|
||||
*/
|
||||
void test_version_exchange_central_loc_invalid_rsp(void)
|
||||
{
|
||||
uint8_t err;
|
||||
struct node_tx *tx;
|
||||
|
||||
struct pdu_data_llctrl_version_ind local_version_ind = {
|
||||
.version_number = LL_VERSION_NUMBER,
|
||||
.company_id = CONFIG_BT_CTLR_COMPANY_ID,
|
||||
.sub_version_number = CONFIG_BT_CTLR_SUBVERSION_NUMBER,
|
||||
};
|
||||
|
||||
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||
.type = PDU_DATA_LLCTRL_TYPE_VERSION_IND
|
||||
};
|
||||
|
||||
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_VERSION_IND,
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
|
||||
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||
};
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Initiate a Version Exchange Procedure */
|
||||
err = ull_cp_version_exchange(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Cheat, to allow second VEX */
|
||||
conn.llcp.vex.sent = 0;
|
||||
|
||||
/* Initiate another Version Exchange Procedure */
|
||||
err = ull_cp_version_exchange(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* Clear termination flag for subsequent test cycle */
|
||||
conn.llcp_terminate.reason_final = 0;
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
|
||||
/* Cheat, to allow second VEX */
|
||||
conn.llcp.vex.sent = 0;
|
||||
|
||||
/* Initiate yet another Version Exchange Procedure */
|
||||
err = ull_cp_version_exchange(&conn);
|
||||
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_VERSION_IND, &conn, &tx, &local_version_ind);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Release Tx */
|
||||
ull_cp_release_tx(&conn, tx);
|
||||
|
||||
/* Termination 'triggered' */
|
||||
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||
|
||||
/* There should be no host notifications */
|
||||
ut_rx_q_is_empty();
|
||||
|
||||
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", ctx_buffers_free());
|
||||
}
|
||||
|
||||
void test_version_exchange_central_loc_2(void)
|
||||
{
|
||||
uint8_t err;
|
||||
|
@ -367,7 +517,10 @@ void test_main(void)
|
|||
ztest_unit_test_setup_teardown(test_version_exchange_central_rem_2, setup,
|
||||
unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(test_version_exchange_central_loc_twice,
|
||||
setup, unit_test_noop));
|
||||
setup, unit_test_noop),
|
||||
ztest_unit_test_setup_teardown(
|
||||
test_version_exchange_central_loc_invalid_rsp, setup,
|
||||
unit_test_noop));
|
||||
|
||||
ztest_run_test_suite(version_exchange);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue