Bluetooth: Controller: fix per sync hang if wrong cte and list filter

In case of use of filtering based on: periodic advertising list and
CTE type, the synchronization can hang. That is possible if a periodic
advertiser uses wrong CTE type. In such situation the sync is not
released in ull_sync_done call. What more the sync->timeout_reload
is not cleared and Host is not able to cancel the synchronization.
The periodic advertising is in a semi-sync-established state.
There are no reports send to Host. Host can't use the sync set to
synchronize with other device. It is only able to terminate the
sync (call to ll_sync_terminate).

To fix the issue following changes should be applied:
- isr_rx_adv_sync_estab should call isr_rx_done_cleanup
with sync_term parameter in case the sync_ok isn't SYNC_STAT_ALLOWED.
In any case the CTE type is wrong, no matter is the periodic
advertising list filtering is enabled or not.
- ull_sync_established_report should set sync->is_term to true
in case the CTE type is not allowed. That change is required for devices
that do not support Direction Finding Extension. For those devices CTE
type based filtering is done in ULL by ull_sync_established_report
function. The sync->is_term should be set unconditionally, hence is
moved up in the function.

With these two changes done, ull_sync_done function will execute
sync_ticker_release in case the CTE has wrong type. ULL, depending on
notifications prepared by ull_sync_established_report, will follow up
on sync termination if required.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
This commit is contained in:
Piotr Pryga 2022-05-11 15:08:35 +02:00 committed by Carles Cufí
parent 154b5a1319
commit 3715241bde
2 changed files with 20 additions and 9 deletions

View file

@ -814,7 +814,7 @@ static void isr_rx_adv_sync_estab(void *param)
isr_rx_done:
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \
defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)
isr_rx_done_cleanup(lll, crc_ok, sync_ok == SYNC_STAT_TERM);
isr_rx_done_cleanup(lll, crc_ok, sync_ok != SYNC_STAT_ALLOWED);
#else
isr_rx_done_cleanup(lll, crc_ok, false);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING && CONFIG_BT_CTLR_CTEINLINE_SUPPORT */

View file

@ -808,6 +808,14 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx)
sync_status = lll_sync_cte_is_allowed(lll->cte_type, lll->filter_policy, 0,
BT_HCI_LE_NO_CTE);
}
/* If there is no CTEInline support, notify done event handler to terminate periodic
* advertising sync in case the CTE is not allowed.
* If the periodic filtering list is not used then terminate synchronization and notify
* host. If the periodic filtering list is used then stop synchronization with this
* particular periodic advertised but continue to search for other one.
*/
sync->is_term = (sync_status != SYNC_STAT_ALLOWED);
#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */
/* Send periodic advertisement sync established report when sync has correct CTE type
@ -824,16 +832,10 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx)
rx_establ->hdr.type = NODE_RX_TYPE_SYNC;
rx_establ->hdr.handle = ull_sync_handle_get(sync);
se = (void *)rx_establ->pdu;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING)
se->status = (ftr->sync_status == SYNC_STAT_TERM) ?
BT_HCI_ERR_UNSUPP_REMOTE_FEATURE :
BT_HCI_ERR_SUCCESS;
#if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)
/* Notify done event handler to terminate sync scan if required. */
sync->is_term = (sync_status == SYNC_STAT_TERM);
#endif /* !CONFIG_BT_CTLR_CTEINLINE_SUPPORT */
#else
se->status = BT_HCI_ERR_SUCCESS;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
@ -851,7 +853,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx)
* the sync was found or was established in the past. The report is not send if
* scanning is terminated due to wrong CTE type.
*/
if (sync_status != SYNC_STAT_TERM) {
if (sync_status == SYNC_STAT_ALLOWED) {
#else /* !CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
if (1) {
@ -896,7 +898,16 @@ void ull_sync_done(struct node_rx_event_done *done)
#else
if (sync->is_term) {
#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */
/* Stop periodic advertising scan ticker */
/* In case the periodic advertising list filtering is not used the synchronization
* must be terminated and host notification must be send.
* In case the periodic advertising list filtering is used the synchronization with
* this particular periodic advertiser but search for other one from the list.
*
* Stop periodic advertising sync ticker and clear variables informing the
* sync is pending. That is a step to completely terminate the synchronization.
* In case search for another periodic advertiser it allows to setup new ticker for
* that.
*/
sync_ticker_cleanup(sync, NULL);
} else
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */