Bluetooth: Controller: Fix missing Broadcast ISO Sync MIC failure

Fix missing implementation to handle Broadcast ISO MIC
failure during Broadcast ISO establishment, and during an
already established Broadcast ISO sync.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2024-08-17 03:28:12 +02:00 committed by Carles Cufí
commit f05d16dabb
2 changed files with 55 additions and 9 deletions

View file

@ -10,6 +10,7 @@
#include <soc.h> #include <soc.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
#include <zephyr/bluetooth/hci_types.h>
#include "hal/cpu.h" #include "hal/cpu.h"
#include "hal/ccm.h" #include "hal/ccm.h"
@ -435,6 +436,7 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
static void isr_rx_estab(void *param) static void isr_rx_estab(void *param)
{ {
struct event_done_extra *e; struct event_done_extra *e;
struct lll_sync_iso *lll;
uint8_t trx_done; uint8_t trx_done;
uint8_t crc_ok; uint8_t crc_ok;
@ -454,6 +456,36 @@ static void isr_rx_estab(void *param)
/* Clear radio rx status and events */ /* Clear radio rx status and events */
lll_isr_rx_status_reset(); lll_isr_rx_status_reset();
/* Get reference to LLL context */
lll = param;
/* Check for MIC failures for encrypted Broadcast ISO streams */
if (IS_ENABLED(CONFIG_BT_CTLR_BROADCAST_ISO_ENC) && crc_ok && lll->enc) {
struct node_rx_pdu *node_rx;
struct pdu_bis *pdu;
/* By design, there shall always be one free node rx available when setting up radio
* for new PDU reception.
*/
node_rx = ull_iso_pdu_rx_alloc_peek(1U);
LL_ASSERT(node_rx);
/* Get reference to received PDU and validate MIC for non-empty PDU */
pdu = (void *)node_rx->pdu;
if (pdu->len) {
bool mic_failure;
uint32_t done;
done = radio_ccm_is_done();
LL_ASSERT(done);
mic_failure = !radio_ccm_mic_is_valid();
if (mic_failure) {
lll->term_reason = BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL;
}
}
}
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
lll_prof_cputime_capture(); lll_prof_cputime_capture();
} }
@ -463,14 +495,11 @@ static void isr_rx_estab(void *param)
LL_ASSERT(e); LL_ASSERT(e);
e->type = EVENT_DONE_EXTRA_TYPE_SYNC_ISO_ESTAB; e->type = EVENT_DONE_EXTRA_TYPE_SYNC_ISO_ESTAB;
e->estab_failed = 0U; e->estab_failed = lll->term_reason ? 1U : 0U;
e->trx_cnt = trx_cnt; e->trx_cnt = trx_cnt;
e->crc_valid = crc_ok; e->crc_valid = crc_ok;
if (trx_cnt) { if (trx_cnt) {
struct lll_sync_iso *lll;
lll = param;
e->drift.preamble_to_addr_us = addr_us_get(lll->phy); e->drift.preamble_to_addr_us = addr_us_get(lll->phy);
e->drift.start_to_address_actual_us = e->drift.start_to_address_actual_us =
radio_tmr_aa_get() - radio_tmr_ready_get(); radio_tmr_aa_get() - radio_tmr_ready_get();
@ -492,7 +521,6 @@ static void isr_rx_estab(void *param)
static void isr_rx(void *param) static void isr_rx(void *param)
{ {
struct lll_sync_iso_stream *stream; struct lll_sync_iso_stream *stream;
struct node_rx_pdu *node_rx;
struct lll_sync_iso *lll; struct lll_sync_iso *lll;
uint8_t access_addr[4]; uint8_t access_addr[4];
uint16_t data_chan_id; uint16_t data_chan_id;
@ -562,6 +590,7 @@ static void isr_rx(void *param)
/* Check CRC and generate ISO Data PDU */ /* Check CRC and generate ISO Data PDU */
if (crc_ok) { if (crc_ok) {
struct lll_sync_iso_stream *sync_stream; struct lll_sync_iso_stream *sync_stream;
struct node_rx_pdu *node_rx;
uint32_t payload_offset; uint32_t payload_offset;
uint16_t payload_index; uint16_t payload_index;
uint16_t stream_handle; uint16_t stream_handle;
@ -631,14 +660,18 @@ static void isr_rx(void *param)
if (IS_ENABLED(CONFIG_BT_CTLR_BROADCAST_ISO_ENC) && if (IS_ENABLED(CONFIG_BT_CTLR_BROADCAST_ISO_ENC) &&
lll->enc) { lll->enc) {
uint32_t mic_failure; bool mic_failure;
uint32_t done; uint32_t done;
done = radio_ccm_is_done(); done = radio_ccm_is_done();
LL_ASSERT(done); LL_ASSERT(done);
mic_failure = !radio_ccm_mic_is_valid(); mic_failure = !radio_ccm_mic_is_valid();
LL_ASSERT(!mic_failure); if (mic_failure) {
lll->term_reason = BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL;
goto isr_rx_mic_failure;
}
} }
ull_iso_pdu_rx_alloc(); ull_iso_pdu_rx_alloc();
@ -893,6 +926,7 @@ isr_rx_find_subevent:
goto isr_rx_next_subevent; goto isr_rx_next_subevent;
} }
isr_rx_mic_failure:
isr_rx_done(param); isr_rx_done(param);
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
@ -972,6 +1006,8 @@ isr_rx_next_subevent:
payload_count = lll->payload_count - lll->bn; payload_count = lll->payload_count - lll->bn;
if (bis) { if (bis) {
struct node_rx_pdu *node_rx;
payload_count += (lll->bn_curr - 1U) + payload_count += (lll->bn_curr - 1U) +
(lll->ptc_curr * lll->pto); (lll->ptc_curr * lll->pto);
@ -1000,6 +1036,8 @@ isr_rx_next_subevent:
struct pdu_bis *pdu; struct pdu_bis *pdu;
if (bis) { if (bis) {
struct node_rx_pdu *node_rx;
/* By design, there shall always be one free node rx /* By design, there shall always be one free node rx
* available for setting up radio for new PDU reception. * available for setting up radio for new PDU reception.
*/ */

View file

@ -698,9 +698,17 @@ void ull_sync_iso_estab_done(struct node_rx_event_done *done)
rx->hdr.handle = sync_iso_handle_get(sync_iso); rx->hdr.handle = sync_iso_handle_get(sync_iso);
rx->rx_ftr.param = sync_iso; rx->rx_ftr.param = sync_iso;
/* status value is stored in the PDU member of the node rx */
se = (void *)rx->pdu; se = (void *)rx->pdu;
se->status = done->extra.estab_failed ? if (done->extra.estab_failed) {
BT_HCI_ERR_CONN_FAIL_TO_ESTAB : BT_HCI_ERR_SUCCESS; if (sync_iso->lll.term_reason != BT_HCI_ERR_SUCCESS) {
se->status = sync_iso->lll.term_reason;
} else {
se->status = BT_HCI_ERR_CONN_FAIL_TO_ESTAB;
}
} else {
se->status = BT_HCI_ERR_SUCCESS;
}
ll_rx_put_sched(rx->hdr.link, rx); ll_rx_put_sched(rx->hdr.link, rx);
} }