Browse Source

Bluetooth: Controller: Add explicit LLCP error code check

Add unit tests to cover explicit LLCP error code check and
cover the same in the Controller implementation.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
(cherry picked from commit d6f2bc9669)
Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
v3.5-branch
Vinayak Kariappa Chettimada 1 year ago committed by Johan Hedberg
parent
commit
ac9c9d2c8d
  1. 16
      subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c
  2. 421
      tests/bluetooth/controller/ctrl_encrypt/src/main.c

16
subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c

@ -382,19 +382,29 @@ static void lp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pd @@ -382,19 +382,29 @@ static void lp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pd
static inline uint8_t reject_error_code(struct pdu_data *pdu)
{
uint8_t error;
if (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) {
return pdu->llctrl.reject_ind.error_code;
error = pdu->llctrl.reject_ind.error_code;
#if defined(CONFIG_BT_CTLR_EXT_REJ_IND)
} else if (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND) {
return pdu->llctrl.reject_ext_ind.error_code;
error = pdu->llctrl.reject_ext_ind.error_code;
#endif /* CONFIG_BT_CTLR_EXT_REJ_IND */
} else {
/* Called with an invalid PDU */
LL_ASSERT(0);
/* Keep compiler happy */
return BT_HCI_ERR_UNSPECIFIED;
error = BT_HCI_ERR_UNSPECIFIED;
}
/* Check expected error code from the peer */
if (error != BT_HCI_ERR_PIN_OR_KEY_MISSING &&
error != BT_HCI_ERR_UNSUPP_REMOTE_FEATURE) {
error = BT_HCI_ERR_UNSPECIFIED;
}
return error;
}
static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,

421
tests/bluetooth/controller/ctrl_encrypt/src/main.c

@ -962,6 +962,426 @@ ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk_2) @@ -962,6 +962,426 @@ ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk_2)
"Free CTX buffers %d", llcp_ctx_buffers_free());
}
/* +-----+ +-------+ +-----+
* | UT | | LL_A | | LT |
* +-----+ +-------+ +-----+
* | | |
* | Initiate | |
* | Encryption Start Proc. | |
* |--------------------------->| |
* | -----------------\ | |
* | | Empty Tx queue |-| |
* | |----------------| | |
* | | |
* | | LL_ENC_REQ |
* | |-------------------->|
* | | |
* | | LL_REJECT_EXT_IND |
* | |<--------------------|
* | | |
* | Encryption Start Proc. | |
* | Complete | |
* |<---------------------------| |
* | | |
*/
ZTEST(encryption_start, test_encryption_start_central_loc_reject_ext_success)
{
uint8_t err;
struct node_tx *tx;
struct node_rx_pdu *ntf;
const uint8_t rand[] = { RAND };
const uint8_t ediv[] = { EDIV };
const uint8_t ltk[] = { LTK };
/* Prepare expected LL_ENC_REQ */
struct pdu_data_llctrl_enc_req exp_enc_req = {
.rand = { RAND },
.ediv = { EDIV },
.skdm = { SKDM },
.ivm = { IVM },
};
/* Prepare mocked call to lll_csrand_get */
lll_csrand_get_fake.return_val = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
lll_csrand_get_custom_fake_context.buf = exp_enc_req.skdm;
lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
.reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ,
.error_code = BT_HCI_ERR_SUCCESS
};
/* Role */
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
/* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
/* Initiate an Encryption Start Procedure */
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
zassert_equal(err, BT_HCI_ERR_SUCCESS);
/* Prepare */
event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
lt_rx_q_is_empty(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* Release Tx */
ull_cp_release_tx(&conn, tx);
/* Rx */
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
/* Done */
event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
struct pdu_data_llctrl_reject_ind reject_ind_expected = {
.error_code = BT_HCI_ERR_UNSPECIFIED };
/* There should be one host notification */
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind_expected);
ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free());
}
/* +-----+ +-------+ +-----+
* | UT | | LL_A | | LT |
* +-----+ +-------+ +-----+
* | | |
* | Initiate | |
* | Encryption Start Proc. | |
* |--------------------------->| |
* | -----------------\ | |
* | | Empty Tx queue |-| |
* | |----------------| | |
* | | |
* | | LL_ENC_REQ |
* | |-------------------->|
* | | |
* | | LL_REJECT_IND |
* | |<--------------------|
* | | |
* | Encryption Start Proc. | |
* | Complete | |
* |<---------------------------| |
* | | |
*/
ZTEST(encryption_start, test_encryption_start_central_loc_reject_success)
{
uint8_t err;
struct node_tx *tx;
struct node_rx_pdu *ntf;
const uint8_t rand[] = { RAND };
const uint8_t ediv[] = { EDIV };
const uint8_t ltk[] = { LTK };
/* Prepare expected LL_ENC_REQ */
struct pdu_data_llctrl_enc_req exp_enc_req = {
.rand = { RAND },
.ediv = { EDIV },
.skdm = { SKDM },
.ivm = { IVM },
};
/* Prepare mocked call to lll_csrand_get */
lll_csrand_get_fake.return_val = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
lll_csrand_get_custom_fake_context.buf = exp_enc_req.skdm;
lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code = BT_HCI_ERR_SUCCESS };
/* Role */
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
/* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
/* Initiate an Encryption Start Procedure */
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
zassert_equal(err, BT_HCI_ERR_SUCCESS);
/* Prepare */
event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
lt_rx_q_is_empty(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* Release Tx */
ull_cp_release_tx(&conn, tx);
/* Rx */
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
/* Done */
event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
struct pdu_data_llctrl_reject_ind reject_ind_expected = {
.error_code = BT_HCI_ERR_UNSPECIFIED };
/* There should be one host notification */
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind_expected);
ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free());
}
/* +-----+ +-------+ +-----+
* | UT | | LL_A | | LT |
* +-----+ +-------+ +-----+
* | | |
* | Initiate | |
* | Encryption Start Proc. | |
* |--------------------------->| |
* | -----------------\ | |
* | | Empty Tx queue |-| |
* | |----------------| | |
* | | |
* | | LL_ENC_REQ |
* | |-------------------->|
* | | |
* | | LL_ENC_RSP |
* | |<--------------------|
* | | |
* | | LL_REJECT_EXT_IND |
* | |<--------------------|
* | | |
* | Encryption Start Proc. | |
* | Complete | |
* |<---------------------------| |
* | | |
*/
ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk_reject_ext_success)
{
uint8_t err;
struct node_tx *tx;
struct node_rx_pdu *ntf;
const uint8_t rand[] = { RAND };
const uint8_t ediv[] = { EDIV };
const uint8_t ltk[] = { LTK };
/* Prepare expected LL_ENC_REQ */
struct pdu_data_llctrl_enc_req exp_enc_req = {
.rand = { RAND },
.ediv = { EDIV },
.skdm = { SKDM },
.ivm = { IVM },
};
/* Prepare LL_ENC_RSP */
struct pdu_data_llctrl_enc_rsp enc_rsp = { .skds = { SKDS }, .ivs = { IVS } };
/* Prepare mocked call to lll_csrand_get */
lll_csrand_get_fake.return_val = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
lll_csrand_get_custom_fake_context.buf = exp_enc_req.skdm;
lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
.reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ,
.error_code = BT_HCI_ERR_SUCCESS
};
/* Role */
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
/* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
/* Initiate an Encryption Start Procedure */
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
zassert_equal(err, BT_HCI_ERR_SUCCESS);
/* Prepare */
event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
lt_rx_q_is_empty(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* Release Tx */
ull_cp_release_tx(&conn, tx);
/* Rx */
lt_tx(LL_ENC_RSP, &conn, &enc_rsp);
/* Rx */
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
/* Done */
event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
struct pdu_data_llctrl_reject_ind reject_ind_expected = {
.error_code = BT_HCI_ERR_UNSPECIFIED };
/* There should be one host notification */
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind_expected);
ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free());
}
/* +-----+ +-------+ +-----+
* | UT | | LL_A | | LT |
* +-----+ +-------+ +-----+
* | | |
* | Initiate | |
* | Encryption Start Proc. | |
* |--------------------------->| |
* | -----------------\ | |
* | | Empty Tx queue |-| |
* | |----------------| | |
* | | |
* | | LL_ENC_REQ |
* | |-------------------->|
* | | |
* | | LL_ENC_RSP |
* | |<--------------------|
* | | |
* | | LL_REJECT_IND |
* | |<--------------------|
* | | |
* | Encryption Start Proc. | |
* | Complete | |
* |<---------------------------| |
* | | |
*/
ZTEST(encryption_start, test_encryption_start_central_loc_no_ltk_2_reject_success)
{
uint8_t err;
struct node_tx *tx;
struct node_rx_pdu *ntf;
const uint8_t rand[] = { RAND };
const uint8_t ediv[] = { EDIV };
const uint8_t ltk[] = { LTK };
/* Prepare expected LL_ENC_REQ */
struct pdu_data_llctrl_enc_req exp_enc_req = {
.rand = { RAND },
.ediv = { EDIV },
.skdm = { SKDM },
.ivm = { IVM },
};
/* Prepare LL_ENC_RSP */
struct pdu_data_llctrl_enc_rsp enc_rsp = { .skds = { SKDS }, .ivs = { IVS } };
/* Prepare mocked call to lll_csrand_get */
lll_csrand_get_fake.return_val = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
lll_csrand_get_custom_fake_context.buf = exp_enc_req.skdm;
lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm);
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code = BT_HCI_ERR_SUCCESS };
/* Role */
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
/* Connect */
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
/* Initiate an Encryption Start Procedure */
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
zassert_equal(err, BT_HCI_ERR_SUCCESS);
/* Prepare */
event_prepare(&conn);
/* Tx Queue should have one LL Control PDU */
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
lt_rx_q_is_empty(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
/* Release Tx */
ull_cp_release_tx(&conn, tx);
/* Rx */
lt_tx(LL_ENC_RSP, &conn, &enc_rsp);
/* Rx */
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
/* Done */
event_done(&conn);
/* Check state */
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
struct pdu_data_llctrl_reject_ind reject_ind_expected = {
.error_code = BT_HCI_ERR_UNSPECIFIED };
/* There should be one host notification */
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind_expected);
ut_rx_q_is_empty();
/* Release Ntf */
release_ntf(ntf);
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
"Free CTX buffers %d", llcp_ctx_buffers_free());
}
/* +-----+ +-------+ +-----+
* | UT | | LL_A | | LT |
* +-----+ +-------+ +-----+
@ -2216,7 +2636,6 @@ ZTEST(encryption_pause, test_encryption_pause_periph_rem_invalid) @@ -2216,7 +2636,6 @@ ZTEST(encryption_pause, test_encryption_pause_periph_rem_invalid)
uint8_t err;
struct node_tx *tx;
struct node_rx_pdu *ntf;
struct ll_conn_iso_stream cis = { 0 };
const uint8_t rand[] = { RAND };

Loading…
Cancel
Save