Skip to content

Commit 06feb02

Browse files
thoh-otcarlescufi
authored andcommitted
Bluetooth: controller: Fix periph enc termination
Terminate connection with a MIC failure if an unexpected control PDU is received during the Encryption Start procedure. Add unit test inspired by Bluetooth Qualification test LL/SEC/PER/BI-05-C, Peripheral Receiving unexpected PDU during encryption start Signed-off-by: Thomas Ebert Hansen <[email protected]>
1 parent 934279a commit 06feb02

File tree

2 files changed

+169
-1
lines changed

2 files changed

+169
-1
lines changed

subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,23 @@ void llcp_rp_enc_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_p
11681168
break;
11691169
default:
11701170
/* Unknown opcode */
1171-
LL_ASSERT(0);
1171+
1172+
/*
1173+
* BLUETOOTH CORE SPECIFICATION Version 5.3
1174+
* Vol 6, Part B, 5.1.3.1 Encryption Start procedure
1175+
*
1176+
* [...]
1177+
*
1178+
* If, at any time during the encryption start procedure after the Peripheral has
1179+
* received the LL_ENC_REQ PDU or the Central has received the
1180+
* LL_ENC_RSP PDU, the Link Layer of the Central or the Peripheral receives an
1181+
* unexpected Data Physical Channel PDU from the peer Link Layer, it shall
1182+
* immediately exit the Connection state, and shall transition to the Standby state.
1183+
* The Host shall be notified that the link has been disconnected with the error
1184+
* code Connection Terminated Due to MIC Failure (0x3D).
1185+
*/
1186+
1187+
conn->llcp_terminate.reason_final = BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL;
11721188
}
11731189
}
11741190

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

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,156 @@ void test_encryption_start_periph_rem_no_ltk(void)
13841384
"Free CTX buffers %d", ctx_buffers_free());
13851385
}
13861386

1387+
/* +-----+ +-------+ +-----+
1388+
* | UT | | LL_A | | LT |
1389+
* +-----+ +-------+ +-----+
1390+
* | | |
1391+
* | | LL_ENC_REQ |
1392+
* | |<--------------------|
1393+
* | -----------------\ | |
1394+
* | | Empty Tx queue |-| |
1395+
* | |----------------| | |
1396+
* | | |
1397+
* | | LL_ENC_RSP |
1398+
* | |-------------------->|
1399+
* | | |
1400+
* | | LL_VERSION_IND |
1401+
* | |<--------------------|
1402+
* | | |
1403+
*/
1404+
void test_encryption_start_periph_rem_mic(void)
1405+
{
1406+
struct node_tx *tx;
1407+
struct node_rx_pdu *ntf;
1408+
1409+
/* Prepare LL_ENC_REQ */
1410+
struct pdu_data_llctrl_enc_req enc_req = {
1411+
.rand = { RAND },
1412+
.ediv = { EDIV },
1413+
.skdm = { SKDM },
1414+
.ivm = { IVM },
1415+
};
1416+
1417+
struct pdu_data_llctrl_enc_rsp exp_enc_rsp = {
1418+
.skds = { SKDS },
1419+
.ivs = { IVS },
1420+
};
1421+
1422+
struct pdu_data_llctrl_version_ind remote_version_ind = {
1423+
.version_number = 0x55,
1424+
.company_id = 0xABCD,
1425+
.sub_version_number = 0x1234,
1426+
};
1427+
1428+
/* Prepare mocked call to lll_csrand_get */
1429+
ztest_returns_value(lll_csrand_get, sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs));
1430+
ztest_return_data(lll_csrand_get, buf, exp_enc_rsp.skds);
1431+
ztest_expect_value(lll_csrand_get, len, sizeof(exp_enc_rsp.skds) + sizeof(exp_enc_rsp.ivs));
1432+
1433+
/* Role */
1434+
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
1435+
1436+
/* Connect */
1437+
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
1438+
1439+
/* Check state */
1440+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
1441+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
1442+
1443+
/* Prepare */
1444+
event_prepare(&conn);
1445+
1446+
/* Rx */
1447+
lt_tx(LL_ENC_REQ, &conn, &enc_req);
1448+
1449+
/* Check state */
1450+
CHECK_RX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Rx unenc. */
1451+
CHECK_TX_PE_STATE(conn, RESUMED, UNENCRYPTED); /* Tx unenc. */
1452+
1453+
/* Done */
1454+
event_done(&conn);
1455+
1456+
/* Check state */
1457+
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
1458+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
1459+
1460+
/* Prepare */
1461+
event_prepare(&conn);
1462+
1463+
/* Tx Queue should have one LL Control PDU */
1464+
lt_rx(LL_ENC_RSP, &conn, &tx, &exp_enc_rsp);
1465+
lt_rx_q_is_empty(&conn);
1466+
1467+
/* Check state */
1468+
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
1469+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
1470+
1471+
/* Done */
1472+
event_done(&conn);
1473+
1474+
/* Check state */
1475+
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
1476+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
1477+
1478+
/* Release Tx */
1479+
ull_cp_release_tx(&conn, tx);
1480+
1481+
/* There should be a host notification */
1482+
ut_rx_pdu(LL_ENC_REQ, &ntf, &enc_req);
1483+
ut_rx_q_is_empty();
1484+
1485+
/* Release Ntf */
1486+
ull_cp_release_ntf(ntf);
1487+
1488+
/* Prepare */
1489+
event_prepare(&conn);
1490+
1491+
/* Rx */
1492+
lt_tx(LL_VERSION_IND, &conn, &remote_version_ind);
1493+
1494+
/* Done */
1495+
event_done(&conn);
1496+
1497+
/* Check state */
1498+
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
1499+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
1500+
1501+
/* There should not be a host notification */
1502+
ut_rx_q_is_empty();
1503+
1504+
/**/
1505+
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL,
1506+
"Expected termination due to MIC failure");
1507+
1508+
/*
1509+
* For a 40s procedure response timeout with a connection interval of
1510+
* 7.5ms, a total of 5333.33 connection events are needed, verify that
1511+
* the state doesn't change for that many invocations.
1512+
*/
1513+
for (int n = 5334; n > 0; n--) {
1514+
/* Prepare */
1515+
event_prepare(&conn);
1516+
1517+
/* Tx Queue should NOT have a LL Control PDU */
1518+
lt_rx_q_is_empty(&conn);
1519+
1520+
/* Done */
1521+
event_done(&conn);
1522+
1523+
/* Check state */
1524+
CHECK_RX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Rx paused & unenc. */
1525+
CHECK_TX_PE_STATE(conn, PAUSED, UNENCRYPTED); /* Tx paused & unenc. */
1526+
1527+
/* There should NOT be a host notification */
1528+
ut_rx_q_is_empty();
1529+
}
1530+
1531+
/* Note that for this test the context is not released */
1532+
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt() - 1,
1533+
"Free CTX buffers %d", ctx_buffers_free());
1534+
}
1535+
1536+
13871537
void test_encryption_pause_central_loc(void)
13881538
{
13891539
uint8_t err;
@@ -1718,6 +1868,8 @@ void test_main(void)
17181868
ztest_unit_test_setup_teardown(test_encryption_start_periph_rem_limited_memory,
17191869
setup, unit_test_noop),
17201870
ztest_unit_test_setup_teardown(test_encryption_start_periph_rem_no_ltk, setup,
1871+
unit_test_noop),
1872+
ztest_unit_test_setup_teardown(test_encryption_start_periph_rem_mic, setup,
17211873
unit_test_noop));
17221874

17231875
ztest_test_suite(encryption_pause,

0 commit comments

Comments
 (0)