nimble/ll: Fix MIC failure during encryption start

This fixes unexpected MIC failure when retransmission happens during
encryption start procedure as follows:
- peripheral sends LL_START_ENC_REQ unencrypted, central acks
- central sends LL_START_ENC_RSP encrypted, peripheral acks
- central retransmits LL_START_ENC_RSP for whatever reason

The problem is that peripheral increments rx packet counter after 1st
LL_START_ENC_RSP is received, so retransmission is decrypted with
different rx packet counter and thus is not valid. We properly ignore
MIC failure for retransmission, but then code checks if received PDU is
valid in currect state, i.e. encryption start procedure. Since it was
not properly decrypted, the PDU type is likely garbage and thus
considered as not allowed so we terminate connection with MIC failure.

The "ultimate" fix for such issues is to simply ignore any retransmitted
PDU with MIC failure since basically contents of such PDUs are garbage
and not really useful for any checks.
This commit is contained in:
Andrzej Kaczmarek
2022-09-27 21:39:00 +02:00
parent ef7c30dcbe
commit 4c5c48e70b
+9 -3
View File
@@ -3434,9 +3434,15 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
if (BLE_MBUF_HDR_MIC_FAILURE(hdr) && (rxd_sn != connsm->last_rxd_sn)) {
STATS_INC(ble_ll_conn_stats, mic_failures);
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) {
/* MIC failure is expected on retransmissions since packet counter does
* not match, so we simply ignore retransmitted PDU with MIC failure as
* they do not have proper decrypted contents.
*/
if (rxd_sn != connsm->last_rxd_sn) {
STATS_INC(ble_ll_conn_stats, mic_failures);
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
}
goto conn_rx_data_pdu_end;
}
#endif