Bluetooth: controller: Fix central enc reject
Add support for both LL_REJECT_IND and LL_REJECT_EXT_IND when waiting for the the response to the LL_ENC_REQ and LL_START_ENC_REQ. Add unit test to test both LL_REJECT_IND and LL_REJECT_EXT_IND as responses to LL_ENC_REQ. Signed-off-by: Thomas Ebert Hansen <thoh@oticon.com>
This commit is contained in:
parent
268d00623b
commit
70e38b1cbb
2 changed files with 239 additions and 3 deletions
|
@ -377,6 +377,23 @@ static void lp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pd
|
||||||
memcpy(&conn->lll.ccm_rx.iv[4], pdu->llctrl.enc_rsp.ivs, sizeof(pdu->llctrl.enc_rsp.ivs));
|
memcpy(&conn->lll.ccm_rx.iv[4], pdu->llctrl.enc_rsp.ivs, sizeof(pdu->llctrl.enc_rsp.ivs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t reject_error_code(struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
if (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) {
|
||||||
|
return 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;
|
||||||
|
#endif /* CONFIG_BT_CTLR_EXT_REJ_IND */
|
||||||
|
} else {
|
||||||
|
/* Called with an invalid PDU */
|
||||||
|
LL_ASSERT(0);
|
||||||
|
|
||||||
|
/* Keep compiler happy */
|
||||||
|
return BT_HCI_ERR_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
|
@ -391,6 +408,21 @@ static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx
|
||||||
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_START_ENC_REQ;
|
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_START_ENC_REQ;
|
||||||
ctx->state = LP_ENC_STATE_WAIT_RX_START_ENC_REQ;
|
ctx->state = LP_ENC_STATE_WAIT_RX_START_ENC_REQ;
|
||||||
break;
|
break;
|
||||||
|
case LP_ENC_EVT_REJECT:
|
||||||
|
/* Encryption is not supported by the Link Layer of the Peripheral */
|
||||||
|
|
||||||
|
/* Resume Tx data */
|
||||||
|
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION);
|
||||||
|
|
||||||
|
/* Store the error reason */
|
||||||
|
ctx->data.enc.error = reject_error_code(pdu);
|
||||||
|
|
||||||
|
/* Resume possibly paused remote procedure */
|
||||||
|
llcp_rr_resume(conn);
|
||||||
|
|
||||||
|
/* Complete the procedure */
|
||||||
|
lp_enc_complete(conn, ctx, evt, param);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Ignore other evts */
|
/* Ignore other evts */
|
||||||
break;
|
break;
|
||||||
|
@ -411,9 +443,10 @@ static void lp_enc_st_wait_rx_start_enc_req(struct ll_conn *conn, struct proc_ct
|
||||||
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION);
|
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION);
|
||||||
/* Resume Rx data */
|
/* Resume Rx data */
|
||||||
ull_conn_resume_rx_data(conn);
|
ull_conn_resume_rx_data(conn);
|
||||||
ctx->data.enc.error = (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) ?
|
|
||||||
pdu->llctrl.reject_ind.error_code :
|
/* Store the error reason */
|
||||||
pdu->llctrl.reject_ext_ind.error_code;
|
ctx->data.enc.error = reject_error_code(pdu);
|
||||||
|
|
||||||
/* Resume possibly paused remote procedure */
|
/* Resume possibly paused remote procedure */
|
||||||
llcp_rr_resume(conn);
|
llcp_rr_resume(conn);
|
||||||
|
|
||||||
|
|
|
@ -519,6 +519,205 @@ void test_encryption_start_central_loc_limited_memory(void)
|
||||||
"Free CTX buffers %d", ctx_buffers_free());
|
"Free CTX buffers %d", 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 | |
|
||||||
|
* |<---------------------------| |
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_encryption_start_central_loc_reject_ext(void)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
ztest_returns_value(lll_csrand_get, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
|
||||||
|
ztest_return_data(lll_csrand_get, buf, exp_enc_req.skdm);
|
||||||
|
ztest_expect_value(lll_csrand_get, len, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code =
|
||||||
|
BT_HCI_ERR_UNSUPP_REMOTE_FEATURE };
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||||
|
.reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ,
|
||||||
|
.error_code = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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, NULL);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
/* There should be one host notification */
|
||||||
|
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind);
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
/* Release Ntf */
|
||||||
|
ull_cp_release_ntf(ntf);
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | Initiate | |
|
||||||
|
* | Encryption Start Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | -----------------\ | |
|
||||||
|
* | | Empty Tx queue |-| |
|
||||||
|
* | |----------------| | |
|
||||||
|
* | | |
|
||||||
|
* | | LL_ENC_REQ |
|
||||||
|
* | |-------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_REJECT_IND |
|
||||||
|
* | |<--------------------|
|
||||||
|
* | | |
|
||||||
|
* | Encryption Start Proc. | |
|
||||||
|
* | Complete | |
|
||||||
|
* |<---------------------------| |
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_encryption_start_central_loc_reject(void)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
ztest_returns_value(lll_csrand_get, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
|
||||||
|
ztest_return_data(lll_csrand_get, buf, exp_enc_req.skdm);
|
||||||
|
ztest_expect_value(lll_csrand_get, len, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code =
|
||||||
|
BT_HCI_ERR_UNSUPP_REMOTE_FEATURE };
|
||||||
|
|
||||||
|
/* 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, NULL);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
/* There should be one host notification */
|
||||||
|
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind);
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
/* Release Ntf */
|
||||||
|
ull_cp_release_ntf(ntf);
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
}
|
||||||
|
|
||||||
/* +-----+ +-------+ +-----+
|
/* +-----+ +-------+ +-----+
|
||||||
* | UT | | LL_A | | LT |
|
* | UT | | LL_A | | LT |
|
||||||
* +-----+ +-------+ +-----+
|
* +-----+ +-------+ +-----+
|
||||||
|
@ -1864,6 +2063,10 @@ void test_main(void)
|
||||||
unit_test_noop),
|
unit_test_noop),
|
||||||
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_limited_memory,
|
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_limited_memory,
|
||||||
setup, unit_test_noop),
|
setup, unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_reject_ext, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_reject, setup,
|
||||||
|
unit_test_noop),
|
||||||
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk, setup,
|
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk, setup,
|
||||||
unit_test_noop),
|
unit_test_noop),
|
||||||
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk_2, setup,
|
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk_2, setup,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue