Bluetooth: controller: Fix ASSERT caused by ULL releasing chain PDUs

When CTE is enabled for periodic advertising and number of CTE is
greater than number of PDUs in a chain, that are needed to transport
advertising data, there are additional empty PDUs used for transport
CTE.

CTE transmission may be disabled when periodic advertising event is
pending in LLL. rem_cte_info_from_per_adv_chain removed CTEInfo field
from extended advertising header in chained PDUs. When there were found
empty PDUs (created to transport CTE only), they were released from
the chain that was currently used by LLL. That caused an assert in
isr_tx handler due to broken advertising chain.

The rem_cte_info_from_per_adv_chain may not relese PDUs that are in
use by LLL. The PDUs may be released by LLL in prepare step when
advertising pdu double buffer is swapped by lll_adv_sync_data_latest-
_get.

This PR fixes that issue.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
This commit is contained in:
Piotr Pryga 2021-09-28 11:47:01 +02:00 committed by Christopher Friedt
parent bacfd0175f
commit a3378d1c9f
3 changed files with 17 additions and 8 deletions

View file

@ -178,6 +178,11 @@ static inline void *lll_adv_sync_extra_data_peek(struct lll_adv_sync *lll)
{
return lll->data.extra_data[lll->data.last];
}
static inline void *lll_adv_sync_extra_data_curr_get(struct lll_adv_sync *lll)
{
return lll->data.extra_data[lll->data.first];
}
#endif /* CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY */
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_EXT */

View file

@ -92,7 +92,7 @@ void lll_df_cte_tx_enable(struct lll_adv_sync *lll_sync, const struct pdu_adv *p
if (ext_hdr->cte_info) {
const struct lll_df_adv_cfg *df_cfg;
df_cfg = lll_adv_sync_extra_data_peek(lll_sync);
df_cfg = lll_adv_sync_extra_data_curr_get(lll_sync);
LL_ASSERT(df_cfg);
df_cte_tx_configure(df_cfg);

View file

@ -835,14 +835,18 @@ static uint8_t rem_cte_info_from_per_adv_chain(struct lll_adv_sync *lll_sync,
while (pdu_chained) {
if (pdu_ext_adv_is_empty_without_cte(pdu_chained)) {
/* If there is an empty PDU then all remaining PDUs shoudl be released. */
lll_adv_pdu_linked_release_all(pdu_chained);
if (!new_chain) {
lll_adv_pdu_linked_release_all(pdu_chained);
/* Set new end of chain in PDUs linked list. If pdu differs from
* prev_pdu then it is already end of a chain. If it doesn't differ,
* then chain end is changed in right place by use of pdu_prev.
* That makes sure there is no PDU released twice (here and when LLL
* swaps PDU buffers).
*/
lll_adv_pdu_linked_append(NULL, *pdu_prev);
}
pdu_chained = NULL;
/* Set new end of chain in PDUs linked list. If pdu differs from prev_pdu
* then it is alread end of a chain. If it doesn't differ, then chain end
* is changed in rigth place by use of pdu_prev. That makes sure there
* is no PDU released twice (here and when LLL swaps PDU buffers).
*/
lll_adv_pdu_linked_append(NULL, *pdu_prev);
} else {
/* Update one before pdu_chained */
err = ull_adv_sync_pdu_set_clear(lll_sync, *pdu_prev, *pdu, 0,