diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index b7b6b25aa49..62a34c501f6 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -6643,6 +6643,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, struct pdu_adv_aux_ptr *aux_ptr = NULL; const struct pdu_adv_adi *adi = NULL; uint8_t cte_type = BT_HCI_LE_NO_CTE; + const struct ll_sync_set *sync; struct pdu_adv_com_ext_adv *p; struct pdu_adv_ext_hdr *h; uint16_t data_len_total; @@ -6664,6 +6665,22 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, return; } + /* NOTE: The timeout_reload field in the sync context is checked under + * race condition between HCI Tx and Rx thread wherein a sync + * terminate was performed which resets the timeout_reload field + * before releasing the sync context back into its memory pool. + * It is important that timeout_reload field is at safe offset + * inside the sync context such that it is not corrupt while being + * in the memory pool. + * + * This check ensures reports are not sent out after sync + * terminate. + */ + sync = HDR_LLL2ULL(ftr->param); + if (unlikely(!sync->timeout_reload)) { + return; + } + if ((le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT) && node_rx->hdr.rx_ftr.aux_failed) { struct bt_hci_evt_le_per_advertising_report *sep; @@ -6787,14 +6804,13 @@ no_ext_hdr: defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) } else if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) && adi) { - const struct ll_sync_set *sync = HDR_LLL2ULL(ftr->param); uint8_t data_status; data_status = (aux_ptr) ? BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL : BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE; - accept = ftr->sync_rx_enabled && + accept = sync->rx_enable && ftr->sync_rx_enabled && (!sync->nodups || !dup_found(PDU_ADV_TYPE_EXT_IND, sync->peer_id_addr_type, @@ -6806,7 +6822,7 @@ no_ext_hdr: */ } else { - accept = ftr->sync_rx_enabled; + accept = sync->rx_enable && ftr->sync_rx_enabled; } data_len_max = CONFIG_BT_BUF_EVT_RX_SIZE - diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index c951fadb96c..82a00c24862 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -52,6 +52,14 @@ #include #include "hal/debug.h" +/* Check that timeout_reload member is at safe offset when ll_sync_set is + * allocated using mem interface. timeout_reload being non-zero is used to + * indicate that a sync is established. And is used to check for sync being + * terminated under race conditions between HCI Tx and Rx thread when + * Periodic Advertising Reports are generated. + */ +MEM_FREE_MEMBER_ACCESS_BUILD_ASSERT(struct ll_sync_set, timeout_reload); + static int init_reset(void); static inline struct ll_sync_set *sync_acquire(void); static void sync_ticker_cleanup(struct ll_sync_set *sync, ticker_op_func stop_op_cb);