/* * Copyright (c) 2020 Demant * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include DEFINE_FFF_GLOBALS; #include #include #include #include #include "hal/ccm.h" #include "util/util.h" #include "util/mem.h" #include "util/memq.h" #include "util/dbuf.h" #include "pdu_df.h" #include "lll/pdu_vendor.h" #include "pdu.h" #include "ll.h" #include "ll_feat.h" #include "ll_settings.h" #include "lll.h" #include "lll/lll_df_types.h" #include "lll_conn.h" #include "lll_conn_iso.h" #include "ull_tx_queue.h" #include "isoal.h" #include "ull_iso_types.h" #include "ull_conn_iso_types.h" #include "ull_internal.h" #include "ull_conn_types.h" #include "ull_llcp.h" #include "ull_conn_internal.h" #include "ull_llcp_internal.h" #include "helper_pdu.h" #include "helper_util.h" /* Tx/Rx pause flag */ #define RESUMED 0U #define PAUSED 1U /* Tx/Rx encryption flag */ #define UNENCRYPTED 0U #define ENCRYPTED 1U /* Check Rx Pause and Encryption state */ #define CHECK_RX_PE_STATE(_conn, _pause, _enc) \ do { \ zassert_equal(_conn.pause_rx_data, _pause, "Rx Data pause state is wrong.");\ zassert_equal(_conn.lll.enc_rx, _enc, "Rx Encryption state is wrong."); \ } while (0) /* Check Tx Pause and Encryption state */ #define CHECK_TX_PE_STATE(_conn, _pause, _enc) \ do { \ zassert_equal(_conn.tx_q.pause_data, _pause, "Tx Data pause state is wrong.");\ zassert_equal(_conn.lll.enc_tx, _enc, "Tx Encryption state is wrong."); \ } while (0) /* CCM direction flag */ #define CCM_DIR_M_TO_S 1U #define CCM_DIR_S_TO_M 0U /* Check Rx CCM state */ #define CHECK_RX_CCM_STATE(_conn, _sk_be, _iv, _cnt, _dir) \ do { \ zassert_mem_equal(_conn.lll.ccm_rx.key, _sk_be, sizeof(_sk_be), \ "CCM Rx SK not equal to expected SK"); \ zassert_mem_equal(_conn.lll.ccm_rx.iv, _iv, sizeof(_iv), \ "CCM Rx IV not equal to (IVm | IVs)"); \ zassert_equal(_conn.lll.ccm_rx.counter, _cnt, "CCM Rx Counter is wrong"); \ zassert_equal(_conn.lll.ccm_rx.direction, _dir, "CCM Rx Direction is wrong");\ } while (0) /* Check Tx CCM state */ #define CHECK_TX_CCM_STATE(_conn, _sk_be, _iv, _cnt, _dir) \ do { \ zassert_mem_equal(_conn.lll.ccm_tx.key, _sk_be, sizeof(_sk_be), \ "CCM Tx SK not equal to expected SK"); \ zassert_mem_equal(_conn.lll.ccm_tx.iv, _iv, sizeof(_iv), \ "CCM Tx IV not equal to (IVm | IVs)"); \ zassert_equal(_conn.lll.ccm_tx.counter, _cnt, "CCM Tx Counter is wrong"); \ zassert_equal(_conn.lll.ccm_tx.direction, _dir, "CCM Tx Direction is wrong");\ } while (0) static struct ll_conn conn; /* void ecb_encrypt(uint8_t const *const key_le, uint8_t const *const clear_text_le, * uint8_t *const cipher_text_le, uint8_t *const cipher_text_be); */ FAKE_VOID_FUNC(ecb_encrypt, uint8_t const *const, uint8_t const *const, uint8_t *const, uint8_t *const); struct { /* In */ uint8_t key_le[16]; uint8_t clear_text_le[16]; /* Out */ uint8_t cipher_text_le[16]; uint8_t cipher_text_be[16]; } ecb_encrypt_custom_fake_context; void ecb_encrypt_custom_fake(uint8_t const *const key_le, uint8_t const *const clear_text_le, uint8_t *const cipher_text_le, uint8_t *const cipher_text_be) { zassert_mem_equal(key_le, ecb_encrypt_custom_fake_context.key_le, 16); zassert_mem_equal(clear_text_le, ecb_encrypt_custom_fake_context.clear_text_le, 16); if (cipher_text_le) { memcpy(cipher_text_le, ecb_encrypt_custom_fake_context.cipher_text_le, 16); } if (cipher_text_be) { memcpy(cipher_text_be, ecb_encrypt_custom_fake_context.cipher_text_be, 16); } } /* int lll_csrand_get(void *buf, size_t len); */ FAKE_VALUE_FUNC(int, lll_csrand_get, void *, size_t); struct { /* In */ void *buf; size_t len; } lll_csrand_get_custom_fake_context; int lll_csrand_get_custom_fake(void *buf, size_t len) { zassert_equal(len, lll_csrand_get_custom_fake_context.len); memcpy(buf, lll_csrand_get_custom_fake_context.buf, len); return lll_csrand_get_fake.return_val; } /* struct ll_conn_iso_stream * * ll_conn_iso_stream_get_by_acl(struct ll_conn *conn, uint16_t *cis_iter); */ FAKE_VALUE_FUNC(struct ll_conn_iso_stream *, ll_conn_iso_stream_get_by_acl, struct ll_conn *, uint16_t *); static void enc_setup(void *data) { test_setup(&conn); /* Fake that a Feature exchange proceudre has been executed */ conn.llcp.fex.valid = 1U; conn.llcp.fex.features_used |= LL_FEAT_BIT_EXT_REJ_IND; /* Reset and setup ecb_encrypt fake */ RESET_FAKE(ecb_encrypt); memset(&ecb_encrypt_custom_fake_context, 0, sizeof(ecb_encrypt_custom_fake_context)); ecb_encrypt_fake.custom_fake = ecb_encrypt_custom_fake; /* Reset and setup lll_csrand_get fake */ RESET_FAKE(lll_csrand_get); memset(&lll_csrand_get_custom_fake_context, 0, sizeof(lll_csrand_get_custom_fake_context)); lll_csrand_get_fake.custom_fake = lll_csrand_get_custom_fake; /* Reset ll_conn_iso_stream_get_by_acl fake */ RESET_FAKE(ll_conn_iso_stream_get_by_acl); } /* BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 6, Part C * 1 ENCRYPTION SAMPLE DATA */ #define RAND 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90 #define EDIV 0x24, 0x74 #define LTK \ 0x4C, 0x68, 0x38, 0x41, 0x39, 0xF5, 0x74, 0xD8, 0x36, 0xBC, 0xF3, 0x4E, 0x9D, 0xFB, 0x01,\ 0xBF #define SKDM 0xAC, 0xBD, 0xCE, 0xDF, 0xE0, 0xF1, 0x02, 0x13 #define SKDS 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79 #define IVM 0xBA, 0xDC, 0xAB, 0x24 #define IVS 0xDE, 0xAF, 0xBA, 0xBE #define SK_BE \ 0x66, 0xC6, 0xC2, 0x27, 0x8E, 0x3B, 0x8E, 0x05, 0x3E, 0x7E, 0xA3, 0x26, 0x52, 0x1B, 0xAD,\ 0x99 /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | | | * | Initiate | | * | Encryption Start Proc. | | * |--------------------------->| | * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_REQ | * | |-------------------->| * | | | * | | LL_ENC_RSP | * | |<--------------------| * | | | * | | LL_START_ENC_REQ | * | |<--------------------| * | ----------------\ | | * | | Tx Encryption |-| | * | | Rx Decryption | | | * | |---------------| | | * | | | * | | LL_START_ENC_RSP | * | |-------------------->| * | | | * | | LL_START_ENC_RSP | * | |<--------------------| * | | | * | Encryption Start Proc. | | * | Complete | | * |<---------------------------| | * | | | */ ZTEST(encryption_start, test_encryption_start_central_loc) { 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 }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* 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); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* 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_START_ENC_REQ, &conn, NULL); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Tx paused & enc. */ /* CCM Tx/Rx SK should match SK */ /* CCM Tx/Rx IV should match the IV */ /* CCM Tx/Rx Counter should be zero */ /* CCM Rx Direction should be S->M */ /* CCM Tx Direction should be M->S */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Tx paused & enc. */ /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* There should be one host notification */ ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL); 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 | * +-----+ +-------+ +-----+ * | -----------------\ | | * | | Reserver all |-| | * | | Tx/Ntf buffers | | | * | |----------------| | | * | | | * | Initiate | | * | Encryption Start Proc. | | * |--------------------------->| | * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_REQ | * | |-------------------->| * | | | * | | LL_ENC_RSP | * | |<--------------------| * | | | * | | LL_START_ENC_REQ | * | |<--------------------| * | ----------------\ | | * | | Tx Encryption |-| | * | | Rx Decryption | | | * | |---------------| | | * | | | * | | LL_START_ENC_RSP | * | |-------------------->| * | | | * | | LL_START_ENC_RSP | * | |<--------------------| * | | | * | Encryption Start Proc. | | * | Complete | | * |<---------------------------| | * | | | */ ZTEST(encryption_start, test_encryption_start_central_loc_limited_memory) { uint8_t err; struct node_tx *tx; struct node_rx_pdu *ntf; struct proc_ctx *ctx = NULL; const uint8_t rand[] = { RAND }; const uint8_t ediv[] = { EDIV }; const uint8_t ltk[] = { LTK }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* 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); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* 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. */ /* Allocate dummy procedure used to steal all buffers */ ctx = llcp_create_local_procedure(PROC_VERSION_EXCHANGE); /* Steal all tx buffers */ while (llcp_tx_alloc_peek(&conn, ctx)) { tx = llcp_tx_alloc(&conn, ctx); zassert_not_null(tx, NULL); } /* Dummy remove, as above loop might queue up ctx */ llcp_tx_alloc_unpeek(ctx); /* 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 no LL Control PDU */ 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. */ /* Done */ event_done(&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); /* 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. */ /* Rx */ lt_tx(LL_ENC_RSP, &conn, &enc_rsp); /* Rx */ lt_tx(LL_START_ENC_REQ, &conn, NULL); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Tx Queue should have no LL Control PDU */ lt_rx_q_is_empty(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Prepare */ event_prepare(&conn); /* Tx Queue should have no LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Tx paused & enc. */ /* CCM Tx/Rx SK should match SK */ /* CCM Tx/Rx IV should match the IV */ /* CCM Tx/Rx Counter should be zero */ /* CCM Tx Direction should be M->S */ /* CCM Rx Direction should be S->M */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* There should be one host notification */ ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* Tx Encryption should be enabled */ zassert_equal(conn.lll.enc_tx, 1U); /* Rx Decryption should be enabled */ zassert_equal(conn.lll.enc_rx, 1U); /* Release dummy procedure */ llcp_proc_ctx_release(ctx); 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_EXT_IND | * | |<--------------------| * | | | * | Encryption Start Proc. | | * | Complete | | * |<---------------------------| | * | | | */ ZTEST(encryption_start, test_encryption_start_central_loc_reject_ext) { 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_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); /* 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 */ 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) { 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_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); /* 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 */ 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) { 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_PIN_OR_KEY_MISSING }; struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = { .reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ, .error_code = BT_HCI_ERR_PIN_OR_KEY_MISSING }; /* 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. */ /* There should be one host notification */ ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind); 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) { 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_PIN_OR_KEY_MISSING }; /* 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. */ /* There should be one host notification */ ut_rx_pdu(LL_REJECT_IND, &ntf, &reject_ind); 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_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 | * +-----+ +-------+ +-----+ * | | | * | Initiate | | * | Encryption Start Proc. | | * |--------------------------->| | * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_REQ | * | |-------------------->| * | | | * | | LL_ENC_RSP | * | |<--------------------| * | | | * | | LL_VERSION_IND | * | |<--------------------| * | | | * | Encryption Start Proc. | | * | Complete | | * |<---------------------------| | * | | | */ ZTEST(encryption_start, test_encryption_start_central_loc_mic) { uint8_t err; struct node_tx *tx; 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 } }; struct pdu_data_llctrl_version_ind remote_version_ind = { .version_number = 0x55, .company_id = 0xABCD, .sub_version_number = 0x1234, }; /* 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); /* 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_VERSION_IND, &conn, &remote_version_ind); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should not be a host notification */ ut_rx_q_is_empty(); /**/ zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL, "Expected termination due to MIC failure"); /* * For a 40s procedure response timeout with a connection interval of * 7.5ms, a total of 5333.33 connection events are needed, verify that * the state doesn't change for that many invocations. */ for (int n = 5334; n > 0; n--) { /* Prepare */ event_prepare(&conn); /* Tx Queue should NOT have a LL Control PDU */ lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should NOT be a host notification */ ut_rx_q_is_empty(); } /* Note that for this test the context is not released */ zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt() - 1, "Free CTX buffers %d", llcp_ctx_buffers_free()); } /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | | | * | | LL_ENC_REQ | * | |<--------------------| * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_RSP | * | |-------------------->| * | | | * | LTK Request | | * |<----------------------| | * | | | * | LTK Request Reply | | * |---------------------->| | * | | | * | | LL_START_ENC_REQ | * | |-------------------->| * | ----------------\ | | * | | Rx Decryption |-| | * | |---------------| | | * | | | * | | LL_START_ENC_RSP | * | |<--------------------| * | | | * | Encryption Change | | * |<----------------------| | * | | | * | | LL_START_ENC_RSP | * | |-------------------->| * | ----------------\ | | * | | Tx Encryption |-| | * | |---------------| | | * | | | */ ZTEST(encryption_start, test_encryption_start_periph_rem) { struct node_tx *tx; struct node_rx_pdu *ntf; const uint8_t ltk[] = { LTK }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* Prepare LL_ENC_REQ */ struct pdu_data_llctrl_enc_req enc_req = { .rand = { RAND }, .ediv = { EDIV }, .skdm = { SKDM }, .ivm = { IVM }, }; struct pdu_data_llctrl_enc_rsp exp_enc_rsp = { .skds = { SKDS }, .ivs = { IVS }, }; /* Prepare mocked call to lll_csrand_get */ lll_csrand_get_fake.return_val = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); lll_csrand_get_custom_fake_context.buf = exp_enc_rsp.skds; lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* 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. */ /* Prepare */ event_prepare(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Rx */ lt_tx(LL_ENC_REQ, &conn, &enc_req); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp); lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* There should be a host notification */ ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* LTK request reply */ ull_cp_ltk_req_reply(&conn, ltk); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_REQ, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* CCM Rx SK should match SK */ /* CCM Rx IV should match the IV */ /* CCM Rx Counter should be zero */ /* CCM Rx Direction should be M->S */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Prepare */ event_prepare(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* There should be a host notification */ ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL); ut_rx_q_is_empty(); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* CCM Tx SK should match SK */ /* CCM Tx IV should match the IV */ /* CCM Tx Counter should be zero */ /* CCM Tx Direction should be S->M */ CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | -----------------\ | | * | | Reserver all |-| | * | | Tx/Ntf buffers | | | * | |----------------| | | * | | | * | | LL_ENC_REQ | * | |<--------------------| * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_RSP | * | |-------------------->| * | | | * | LTK Request | | * |<----------------------| | * | | | * | LTK Request Reply | | * |---------------------->| | * | | | * | | LL_START_ENC_REQ | * | |-------------------->| * | ----------------\ | | * | | Rx Decryption |-| | * | |---------------| | | * | | | * | | LL_START_ENC_RSP | * | |<--------------------| * | | | * | Encryption Change | | * |<----------------------| | * | | | * | | LL_START_ENC_RSP | * | |-------------------->| * | ----------------\ | | * | | Tx Encryption |-| | * | |---------------| | | * | | | */ ZTEST(encryption_start, test_encryption_start_periph_rem_limited_memory) { struct node_tx *tx; struct node_rx_pdu *ntf; struct proc_ctx *ctx = NULL; const uint8_t ltk[] = { LTK }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* Prepare LL_ENC_REQ */ struct pdu_data_llctrl_enc_req enc_req = { .rand = { RAND }, .ediv = { EDIV }, .skdm = { SKDM }, .ivm = { IVM }, }; struct pdu_data_llctrl_enc_rsp exp_enc_rsp = { .skds = { SKDS }, .ivs = { IVS }, }; /* Prepare mocked call to lll_csrand_get */ lll_csrand_get_fake.return_val = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); lll_csrand_get_custom_fake_context.buf = exp_enc_rsp.skds; lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* Connect */ ull_cp_state_set(&conn, ULL_CP_CONNECTED); /* Allocate dummy procedure used to steal all buffers */ ctx = llcp_create_local_procedure(PROC_VERSION_EXCHANGE); /* Steal all tx buffers */ while (llcp_tx_alloc_peek(&conn, ctx)) { tx = llcp_tx_alloc(&conn, ctx); zassert_not_null(tx, NULL); } /* Dummy remove, as above loop might queue up ctx */ llcp_tx_alloc_unpeek(ctx); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_ENC_REQ, &conn, &enc_req); /* Tx Queue should not have a LL Control PDU */ lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release tx */ ull_cp_release_tx(&conn, tx); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should be one host notification */ ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); ut_rx_q_is_empty(); /* Release ntf */ release_ntf(ntf); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* LTK request reply */ ull_cp_ltk_req_reply(&conn, ltk); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should not have one LL Control PDU */ lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release tx */ ull_cp_release_tx(&conn, tx); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_REQ, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* CCM Rx SK should match SK */ /* CCM Rx IV should match the IV */ /* CCM Rx Counter should be zero */ /* CCM Rx Direction should be M->S */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should be one host notification */ ut_rx_pdu(LL_START_ENC_RSP, &ntf, NULL); ut_rx_q_is_empty(); /* Prepare */ event_prepare(&conn); /* Tx Queue should not have a LL Control PDU */ lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, ENCRYPTED); /* Rx paused & enc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release tx */ ull_cp_release_tx(&conn, tx); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* CCM Tx SK should match SK */ /* CCM Tx IV should match the IV */ /* CCM Tx Counter should be zero */ /* CCM Tx Direction should be S->M */ CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); /* Release dummy procedure */ llcp_proc_ctx_release(ctx); zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | | | * | | LL_ENC_REQ | * | |<--------------------| * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_RSP | * | |-------------------->| * | | | * | LTK Request | | * |<----------------------| | * | | | * | LTK Request Reply | | * |---------------------->| | * | | | * | | LL_REJECT_EXT_IND | * | |-------------------->| */ ZTEST(encryption_start, test_encryption_start_periph_rem_no_ltk) { struct node_tx *tx; struct node_rx_pdu *ntf; /* Prepare LL_ENC_REQ */ struct pdu_data_llctrl_enc_req enc_req = { .rand = { RAND }, .ediv = { EDIV }, .skdm = { SKDM }, .ivm = { IVM }, }; struct pdu_data_llctrl_enc_rsp exp_enc_rsp = { .skds = { SKDS }, .ivs = { IVS }, }; struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = { .reject_opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ, .error_code = BT_HCI_ERR_PIN_OR_KEY_MISSING }; /* Prepare mocked call to lll_csrand_get */ lll_csrand_get_fake.return_val = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); lll_csrand_get_custom_fake_context.buf = exp_enc_rsp.skds; lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* 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. */ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_ENC_REQ, &conn, &enc_req); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* There should be a host notification */ ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* LTK request reply */ ull_cp_ltk_req_neq_reply(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &reject_ext_ind); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* There should not be a host notification */ ut_rx_q_is_empty(); /* All contexts should be released until now. This is a side-effect of a call to * ull_cp_tx_ntf that internall calls rr_check_done and lr_check_done. */ zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | | | * | | LL_ENC_REQ | * | |<--------------------| * | -----------------\ | | * | | Empty Tx queue |-| | * | |----------------| | | * | | | * | | LL_ENC_RSP | * | |-------------------->| * | | | * | | LL_VERSION_IND | * | |<--------------------| * | | | */ ZTEST(encryption_start, test_encryption_start_periph_rem_mic) { struct node_tx *tx; struct node_rx_pdu *ntf; /* Prepare LL_ENC_REQ */ struct pdu_data_llctrl_enc_req enc_req = { .rand = { RAND }, .ediv = { EDIV }, .skdm = { SKDM }, .ivm = { IVM }, }; struct pdu_data_llctrl_enc_rsp exp_enc_rsp = { .skds = { SKDS }, .ivs = { IVS }, }; struct pdu_data_llctrl_version_ind remote_version_ind = { .version_number = 0x55, .company_id = 0xABCD, .sub_version_number = 0x1234, }; /* Prepare mocked call to lll_csrand_get */ lll_csrand_get_fake.return_val = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); lll_csrand_get_custom_fake_context.buf = exp_enc_rsp.skds; lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* 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. */ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_ENC_REQ, &conn, &enc_req); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */ CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp); lt_rx_q_is_empty(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /* There should be a host notification */ ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_VERSION_IND, &conn, &remote_version_ind); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should not be a host notification */ ut_rx_q_is_empty(); /**/ zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL, "Expected termination due to MIC failure"); /* * For a 40s procedure response timeout with a connection interval of * 7.5ms, a total of 5333.33 connection events are needed, verify that * the state doesn't change for that many invocations. */ for (int n = 5334; n > 0; n--) { /* Prepare */ event_prepare(&conn); /* Tx Queue should NOT have a LL Control PDU */ lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* There should NOT be a host notification */ ut_rx_q_is_empty(); } /* Note that for this test the context is not released */ zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt() - 1, "Free CTX buffers %d", llcp_ctx_buffers_free()); } ZTEST(encryption_pause, test_encryption_pause_central_loc) { 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 }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* 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); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* Role */ test_set_role(&conn, BT_HCI_ROLE_CENTRAL); /* Connect */ ull_cp_state_set(&conn, ULL_CP_CONNECTED); /* Fake that encryption is already active */ conn.lll.enc_rx = 1U; conn.lll.enc_tx = 1U; /**** ENCRYPTED ****/ /* Initiate an Encryption Pause Procedure */ err = ull_cp_encryption_pause(&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_PAUSE_ENC_REQ, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Rx */ lt_tx(LL_PAUSE_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_PAUSE_ENC_RSP, &conn, &tx, NULL); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Tx Encryption should be disabled */ zassert_equal(conn.lll.enc_tx, 0U); /* Rx Decryption should be disabled */ zassert_equal(conn.lll.enc_rx, 0U); /**** UNENCRYPTED ****/ /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_REQ, &conn, &tx, &exp_enc_req); lt_rx_q_is_empty(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Rx */ lt_tx(LL_ENC_RSP, &conn, &enc_rsp); /* Rx */ lt_tx(LL_START_ENC_REQ, &conn, NULL); /* Done */ event_done(&conn); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* CCM Tx/Rx SK should match SK */ /* CCM Tx/Rx IV should match the IV */ /* CCM Tx/Rx Counter should be zero */ /* CCM Rx Direction should be S->M */ /* CCM Tx Direction should be M->S */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Tx Encryption should be enabled */ zassert_equal(conn.lll.enc_tx, 1U); /* Rx Decryption should be enabled */ zassert_equal(conn.lll.enc_rx, 1U); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* There should be one host notification */ ut_rx_node(NODE_ENC_REFRESH, &ntf, NULL); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* Tx Encryption should be enabled */ zassert_equal(conn.lll.enc_tx, 1U); /* Rx Decryption should be enabled */ zassert_equal(conn.lll.enc_rx, 1U); zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } ZTEST(encryption_pause, test_encryption_pause_periph_rem) { struct node_tx *tx; struct node_rx_pdu *ntf; const uint8_t ltk[] = { LTK }; const uint8_t skd[] = { SKDM, SKDS }; const uint8_t sk_be[] = { SK_BE }; const uint8_t iv[] = { IVM, IVS }; /* Prepare LL_ENC_REQ */ struct pdu_data_llctrl_enc_req enc_req = { .rand = { RAND }, .ediv = { EDIV }, .skdm = { SKDM }, .ivm = { IVM }, }; struct pdu_data_llctrl_enc_rsp exp_enc_rsp = { .skds = { SKDS }, .ivs = { IVS }, }; /* Prepare mocked call to lll_csrand_get */ lll_csrand_get_fake.return_val = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); lll_csrand_get_custom_fake_context.buf = exp_enc_rsp.skds; lll_csrand_get_custom_fake_context.len = sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs); /* Prepare mocked call to ecb_encrypt */ memcpy(ecb_encrypt_custom_fake_context.key_le, ltk, 16); memcpy(ecb_encrypt_custom_fake_context.clear_text_le, skd, 16); memcpy(ecb_encrypt_custom_fake_context.cipher_text_be, sk_be, 16); /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* Connect */ ull_cp_state_set(&conn, ULL_CP_CONNECTED); /* Fake that encryption is already active */ conn.lll.enc_rx = 1U; conn.lll.enc_tx = 1U; /**** ENCRYPTED ****/ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_PAUSE_ENC_REQ, &conn, NULL); /* Done */ event_done(&conn); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_PAUSE_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Rx Decryption should be disabled */ zassert_equal(conn.lll.enc_rx, 0U); /* Rx */ lt_tx(LL_PAUSE_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* Tx Encryption should be disabled */ zassert_equal(conn.lll.enc_tx, 0U); /**** UNENCRYPTED ****/ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_ENC_REQ, &conn, &enc_req); /* Done */ event_done(&conn); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp); lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* There should be a host notification */ ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req); ut_rx_q_is_empty(); /* Release Ntf */ release_ntf(ntf); /* LTK request reply */ ull_cp_ltk_req_reply(&conn, ltk); /* Check state */ CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */ CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */ /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_REQ, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* CCM Rx SK should match SK */ /* CCM Rx IV should match the IV */ /* CCM Rx Counter should be zero */ /* CCM Rx Direction should be M->S */ CHECK_RX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_M_TO_S); /* Rx Decryption should be enabled */ zassert_equal(conn.lll.enc_rx, 1U); /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_START_ENC_RSP, &conn, NULL); /* Done */ event_done(&conn); /* There should be a host notification */ ut_rx_node(NODE_ENC_REFRESH, &ntf, NULL); ut_rx_q_is_empty(); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_START_ENC_RSP, &conn, &tx, NULL); lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Release Tx */ ull_cp_release_tx(&conn, tx); /* CCM Tx SK should match SK */ /* CCM Tx IV should match the IV */ /* CCM Tx Counter should be zero */ /* CCM Tx Direction should be S->M */ CHECK_TX_CCM_STATE(conn, sk_be, iv, 0U, CCM_DIR_S_TO_M); /* Tx Encryption should be enabled */ zassert_equal(conn.lll.enc_tx, 1U); zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } /* +-----+ +-------+ +-----+ * | UT | | LL_A | | LT | * +-----+ +-------+ +-----+ * | | | * /------------------------------------------------------\ * | Encrypted & CIS Established | * \------------------------------------------------------/ * | | | * | Initiate | | * | Encryption Pause Proc. | | * |--------------------------->| | * | | | * | Command Disallowed | | * |<---------------------------| | * | | | * | | LL_PAUSE_ENC_REQ | * | |<--------------------| * | | | * | | LL_REJECT_EXT_IND | * | |-------------------->| * | | | */ ZTEST(encryption_pause, test_encryption_pause_periph_rem_invalid) { uint8_t err; struct node_tx *tx; struct ll_conn_iso_stream cis = { 0 }; const uint8_t rand[] = { RAND }; const uint8_t ediv[] = { EDIV }; const uint8_t ltk[] = { LTK }; struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = { .reject_opcode = PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ, .error_code = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED }; /* Prepare mocked call to ll_conn_iso_stream_get_by_acl() */ ll_conn_iso_stream_get_by_acl_fake.return_val = &cis; /* Role */ test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL); /* Connect */ ull_cp_state_set(&conn, ULL_CP_CONNECTED); /* Fake that encryption is already active */ conn.lll.enc_rx = 1U; conn.lll.enc_tx = 1U; /**** ENCRYPTED ****/ /* Initiate an Encryption Pause Procedure */ err = ull_cp_encryption_pause(&conn, rand, ediv, ltk); zassert_equal(err, BT_HCI_ERR_CMD_DISALLOWED); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /**** *****/ /* Prepare */ event_prepare(&conn); /* Rx */ lt_tx(LL_PAUSE_ENC_REQ, &conn, NULL); /* Done */ event_done(&conn); /* Prepare */ event_prepare(&conn); /* Tx Queue should have one LL Control PDU */ lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &reject_ext_ind); lt_rx_q_is_empty(&conn); /* Done */ event_done(&conn); /* Check state */ CHECK_RX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Rx enc. */ CHECK_TX_PE_STATE(conn, RESUMED, ENCRYPTED); /* Tx enc. */ /* Release Tx */ ull_cp_release_tx(&conn, tx); /**** *****/ zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(), "Free CTX buffers %d", llcp_ctx_buffers_free()); } ZTEST_SUITE(encryption_start, NULL, NULL, enc_setup, NULL, NULL); ZTEST_SUITE(encryption_pause, NULL, NULL, enc_setup, NULL, NULL);