Commit 70e38b1c authored by Thomas Ebert Hansen's avatar Thomas Ebert Hansen Committed by Carles Cufi
Browse files

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: default avatarThomas Ebert Hansen <thoh@oticon.com>
parent 268d0062
Loading
Loading
Loading
Loading
+36 −3
Original line number Diff line number Diff line
@@ -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));
}

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,
				      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->state = LP_ENC_STATE_WAIT_RX_START_ENC_REQ;
		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:
		/* Ignore other evts */
		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);
		/* Resume Rx data */
		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 :
						    pdu->llctrl.reject_ext_ind.error_code;

		/* Store the error reason */
		ctx->data.enc.error = reject_error_code(pdu);

		/* Resume possibly paused remote procedure */
		llcp_rr_resume(conn);

+203 −0
Original line number Diff line number Diff line
@@ -519,6 +519,205 @@ void test_encryption_start_central_loc_limited_memory(void)
				  "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  |
 * +-----+                     +-------+              +-----+
@@ -1864,6 +2063,10 @@ void test_main(void)
					       unit_test_noop),
		ztest_unit_test_setup_teardown(test_encryption_start_central_loc_limited_memory,
					       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,
					       unit_test_noop),
		ztest_unit_test_setup_teardown(test_encryption_start_central_loc_no_ltk_2, setup,