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:
parent
bacfd0175f
commit
a3378d1c9f
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue