Skip to content

Commit 70e38b1

Browse files
thoh-otcarlescufi
authored andcommitted
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 <[email protected]>
1 parent 268d006 commit 70e38b1

File tree

2 files changed

+239
-3
lines changed

2 files changed

+239
-3
lines changed

subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,23 @@ static void lp_enc_store_s(struct ll_conn *conn, struct proc_ctx *ctx, struct pd
377377
memcpy(&conn->lll.ccm_rx.iv[4], pdu->llctrl.enc_rsp.ivs, sizeof(pdu->llctrl.enc_rsp.ivs));
378378
}
379379

380+
static inline uint8_t reject_error_code(struct pdu_data *pdu)
381+
{
382+
if (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) {
383+
return pdu->llctrl.reject_ind.error_code;
384+
#if defined(CONFIG_BT_CTLR_EXT_REJ_IND)
385+
} else if (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND) {
386+
return pdu->llctrl.reject_ext_ind.error_code;
387+
#endif /* CONFIG_BT_CTLR_EXT_REJ_IND */
388+
} else {
389+
/* Called with an invalid PDU */
390+
LL_ASSERT(0);
391+
392+
/* Keep compiler happy */
393+
return BT_HCI_ERR_UNSPECIFIED;
394+
}
395+
}
396+
380397
static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
381398
void *param)
382399
{
@@ -391,6 +408,21 @@ static void lp_enc_st_wait_rx_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx
391408
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_START_ENC_REQ;
392409
ctx->state = LP_ENC_STATE_WAIT_RX_START_ENC_REQ;
393410
break;
411+
case LP_ENC_EVT_REJECT:
412+
/* Encryption is not supported by the Link Layer of the Peripheral */
413+
414+
/* Resume Tx data */
415+
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION);
416+
417+
/* Store the error reason */
418+
ctx->data.enc.error = reject_error_code(pdu);
419+
420+
/* Resume possibly paused remote procedure */
421+
llcp_rr_resume(conn);
422+
423+
/* Complete the procedure */
424+
lp_enc_complete(conn, ctx, evt, param);
425+
break;
394426
default:
395427
/* Ignore other evts */
396428
break;
@@ -411,9 +443,10 @@ static void lp_enc_st_wait_rx_start_enc_req(struct ll_conn *conn, struct proc_ct
411443
llcp_tx_resume_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_ENCRYPTION);
412444
/* Resume Rx data */
413445
ull_conn_resume_rx_data(conn);
414-
ctx->data.enc.error = (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) ?
415-
pdu->llctrl.reject_ind.error_code :
416-
pdu->llctrl.reject_ext_ind.error_code;
446+
447+
/* Store the error reason */
448+
ctx->data.enc.error = reject_error_code(pdu);
449+
417450
/* Resume possibly paused remote procedure */
418451
llcp_rr_resume(conn);
419452

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

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,205 @@ void test_encryption_start_central_loc_limited_memory(void)
519519
"Free CTX buffers %d", ctx_buffers_free());
520520
}
521521

522+
/* +-----+ +-------+ +-----+
523+
* | UT | | LL_A | | LT |
524+
* +-----+ +-------+ +-----+
525+
* | | |
526+
* | Initiate | |
527+
* | Encryption Start Proc. | |
528+
* |--------------------------->| |
529+
* | -----------------\ | |
530+
* | | Empty Tx queue |-| |
531+
* | |----------------| | |
532+
* | | |
533+
* | | LL_ENC_REQ |
534+
* | |-------------------->|
535+
* | | |
536+
* | | LL_REJECT_EXT_IND |
537+
* | |<--------------------|
538+
* | | |
539+
* | Encryption Start Proc. | |
540+
* | Complete | |
541+
* |<---------------------------| |
542+
* | | |
543+
*/
544+
void test_encryption_start_central_loc_reject_ext(void)
545+
{
546+
uint8_t err;
547+
struct node_tx *tx;
548+
struct node_rx_pdu *ntf;
549+
550+
const uint8_t rand[] = { RAND };
551+
const uint8_t ediv[] = { EDIV };
552+
const uint8_t ltk[] = { LTK };
553+
554+
/* Prepare expected LL_ENC_REQ */
555+
struct pdu_data_llctrl_enc_req exp_enc_req = {
556+
.rand = { RAND },
557+
.ediv = { EDIV },
558+
.skdm = { SKDM },
559+
.ivm = { IVM },
560+
};
561+
562+
/* Prepare mocked call to lll_csrand_get */
563+
ztest_returns_value(lll_csrand_get, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
564+
ztest_return_data(lll_csrand_get, buf, exp_enc_req.skdm);
565+
ztest_expect_value(lll_csrand_get, len, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
566+
567+
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code =
568+
BT_HCI_ERR_UNSUPP_REMOTE_FEATURE };
569+
570+
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
571+
.reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ,
572+
.error_code = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE
573+
};
574+
575+
/* Role */
576+
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
577+
578+
/* Connect */
579+
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
580+
581+
/* Check state */
582+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
583+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
584+
585+
/* Initiate an Encryption Start Procedure */
586+
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
587+
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
588+
589+
/* Prepare */
590+
event_prepare(&conn);
591+
592+
/* Tx Queue should have one LL Control PDU */
593+
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
594+
lt_rx_q_is_empty(&conn);
595+
596+
/* Check state */
597+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
598+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
599+
600+
/* Release Tx */
601+
ull_cp_release_tx(&conn, tx);
602+
603+
/* Rx */
604+
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
605+
606+
/* Done */
607+
event_done(&conn);
608+
609+
/* Check state */
610+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
611+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
612+
613+
/* There should be one host notification */
614+
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind);
615+
ut_rx_q_is_empty();
616+
617+
/* Release Ntf */
618+
ull_cp_release_ntf(ntf);
619+
620+
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
621+
"Free CTX buffers %d", ctx_buffers_free());
622+
}
623+
624+
/* +-----+ +-------+ +-----+
625+
* | UT | | LL_A | | LT |
626+
* +-----+ +-------+ +-----+
627+
* | | |
628+
* | Initiate | |
629+
* | Encryption Start Proc. | |
630+
* |--------------------------->| |
631+
* | -----------------\ | |
632+
* | | Empty Tx queue |-| |
633+
* | |----------------| | |
634+
* | | |
635+
* | | LL_ENC_REQ |
636+
* | |-------------------->|
637+
* | | |
638+
* | | LL_REJECT_IND |
639+
* | |<--------------------|
640+
* | | |
641+
* | Encryption Start Proc. | |
642+
* | Complete | |
643+
* |<---------------------------| |
644+
* | | |
645+
*/
646+
void test_encryption_start_central_loc_reject(void)
647+
{
648+
uint8_t err;
649+
struct node_tx *tx;
650+
struct node_rx_pdu *ntf;
651+
652+
const uint8_t rand[] = { RAND };
653+
const uint8_t ediv[] = { EDIV };
654+
const uint8_t ltk[] = { LTK };
655+
656+
/* Prepare expected LL_ENC_REQ */
657+
struct pdu_data_llctrl_enc_req exp_enc_req = {
658+
.rand = { RAND },
659+
.ediv = { EDIV },
660+
.skdm = { SKDM },
661+
.ivm = { IVM },
662+
};
663+
664+
/* Prepare mocked call to lll_csrand_get */
665+
ztest_returns_value(lll_csrand_get, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
666+
ztest_return_data(lll_csrand_get, buf, exp_enc_req.skdm);
667+
ztest_expect_value(lll_csrand_get, len, sizeof(exp_enc_req.skdm) + sizeof(exp_enc_req.ivm));
668+
669+
struct pdu_data_llctrl_reject_ind reject_ind = { .error_code =
670+
BT_HCI_ERR_UNSUPP_REMOTE_FEATURE };
671+
672+
/* Role */
673+
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
674+
675+
/* Connect */
676+
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
677+
678+
/* Check state */
679+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
680+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
681+
682+
/* Initiate an Encryption Start Procedure */
683+
err = ull_cp_encryption_start(&conn, rand, ediv, ltk);
684+
zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL);
685+
686+
/* Prepare */
687+
event_prepare(&conn);
688+
689+
/* Tx Queue should have one LL Control PDU */
690+
lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req);
691+
lt_rx_q_is_empty(&conn);
692+
693+
/* Check state */
694+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
695+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
696+
697+
/* Release Tx */
698+
ull_cp_release_tx(&conn, tx);
699+
700+
/* Rx */
701+
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
702+
703+
/* Done */
704+
event_done(&conn);
705+
706+
/* Check state */
707+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
708+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
709+
710+
/* There should be one host notification */
711+
ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind);
712+
ut_rx_q_is_empty();
713+
714+
/* Release Ntf */
715+
ull_cp_release_ntf(ntf);
716+
717+
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
718+
"Free CTX buffers %d", ctx_buffers_free());
719+
}
720+
522721
/* +-----+ +-------+ +-----+
523722
* | UT | | LL_A | | LT |
524723
* +-----+ +-------+ +-----+
@@ -1864,6 +2063,10 @@ void test_main(void)
18642063
unit_test_noop),
18652064
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_limited_memory,
18662065
setup, unit_test_noop),
2066+
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_reject_ext, setup,
2067+
unit_test_noop),
2068+
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_reject, setup,
2069+
unit_test_noop),
18672070
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk, setup,
18682071
unit_test_noop),
18692072
ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk_2, setup,

0 commit comments

Comments
 (0)