You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ry...@apache.org on 2018/12/05 12:24:17 UTC

[mynewt-nimble] 12/13: nimble/ll: Extended scanner - add ref count for aux data

This is an automated email from the ASF dual-hosted git repository.

rymek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 2df0d01fe354ef289d4eb2857e8dbe6b5a1859f4
Author: Ɓukasz Rymanowski <lu...@codecoup.pl>
AuthorDate: Thu Nov 8 12:25:00 2018 +0100

    nimble/ll: Extended scanner - add ref count for aux data
    
    This patch improves scanner by adding ref counter for outstanding
    aux_data. With this we want to make sure aux_data is not freed e.g. when
    being handover to LL and in the same time processed in the interrupt in
    chaining scenario
    
    General idea is that 1 reference is kept as long as event is not
    completed (note: truncated is also completed) and other references are
    use when:
     - aux is scheduled
     - report is sending to the host
     - scan request has been sent
     - when packet is handover to LL
---
 nimble/controller/include/controller/ble_ll_scan.h |   5 +-
 .../controller/include/controller/ble_ll_trace.h   |   2 +
 nimble/controller/src/ble_ll_conn.c                |  56 +++++--
 nimble/controller/src/ble_ll_scan.c                | 179 ++++++++++++++++-----
 nimble/controller/src/ble_ll_sched.c               |   4 +-
 nimble/controller/src/ble_ll_trace.c               |   2 +
 6 files changed, 189 insertions(+), 59 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_scan.h b/nimble/controller/include/controller/ble_ll_scan.h
index 98246fb..5aa34f0 100644
--- a/nimble/controller/include/controller/ble_ll_scan.h
+++ b/nimble/controller/include/controller/ble_ll_scan.h
@@ -95,9 +95,11 @@ struct ble_ll_scan_params
 #define BLE_LL_AUX_IGNORE_BIT           0x10
 #define BLE_LL_AUX_HAS_DIR_ADDRA        0x20
 
+#define BLE_LL_SET_AUX_FLAG(aux_data, flag) ((aux_data)->flags |= flag)
 #define BLE_LL_CHECK_AUX_FLAG(aux_data, flag) (!!((aux_data)->flags & flag))
 
 struct ble_ll_aux_data {
+    uint8_t ref_cnt;
     uint8_t chan;
     uint8_t aux_phy;
     uint8_t aux_primary_phy;
@@ -245,7 +247,8 @@ int ble_ll_scan_parse_ext_hdr(struct os_mbuf *om,
                               struct ble_mbuf_hdr *ble_hdr,
                               struct ble_ll_ext_adv_report *parsed_evt);
 
-void ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan);
+void ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan);
+int ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan);
 #endif
 
 /* Called to clean up current aux data */
diff --git a/nimble/controller/include/controller/ble_ll_trace.h b/nimble/controller/include/controller/ble_ll_trace.h
index b2556d8..7545b57 100644
--- a/nimble/controller/include/controller/ble_ll_trace.h
+++ b/nimble/controller/include/controller/ble_ll_trace.h
@@ -38,6 +38,8 @@ extern "C" {
 #define BLE_LL_TRACE_ID_CONN_RX                 9
 #define BLE_LL_TRACE_ID_ADV_TXDONE              10
 #define BLE_LL_TRACE_ID_ADV_HALT                11
+#define BLE_LL_TRACE_ID_AUX_REF                 12
+#define BLE_LL_TRACE_ID_AUX_UNREF               13
 
 #if MYNEWT_VAL(BLE_LL_SYSVIEW)
 
diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c
index f170000..3c407c5 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -842,7 +842,9 @@ ble_ll_conn_init_wfr_timer_exp(void)
 
     scansm = connsm->scansm;
     if (scansm && scansm->cur_aux_data) {
-        ble_ll_scan_aux_data_free(scansm->cur_aux_data);
+        if (ble_ll_scan_aux_data_unref(scansm->cur_aux_data)) {
+            ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
+        }
         scansm->cur_aux_data = NULL;
         STATS_INC(ble_ll_stats, aux_missed_adv);
         ble_ll_event_send(&scansm->scan_sched_ev);
@@ -2931,6 +2933,18 @@ ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
     uint8_t *adv_addr;
     struct ble_ll_conn_sm *connsm;
     int ext_adv_mode = -1;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+    struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data;
+
+    /*
+     * Let's take the reference for handover to LL.
+     * There shall be one more, if not something went very wrong
+     */
+    if (!ble_ll_scan_aux_data_unref(aux_data)) {
+        BLE_LL_ASSERT(0);
+    }
+
+#endif
 
     /* Get the connection state machine we are trying to create */
     connsm = g_ble_ll_conn_create_sm;
@@ -2946,13 +2960,14 @@ ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
     if (BLE_MBUF_HDR_AUX_INVALID(ble_hdr)) {
         goto scan_continue;
     }
+
     if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
         if (BLE_MBUF_HDR_WAIT_AUX(ble_hdr)) {
             /* Just continue scanning. We are waiting for AUX */
-            if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm,
-                                      ble_hdr->rxinfo.user_data)) {
-               /* Wait for aux conn response */
-                ble_hdr->rxinfo.user_data = NULL;
+            if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm, aux_data)) {
+                ble_ll_scan_aux_data_ref(aux_data);
+                ble_ll_scan_chk_resume();
+                return;
             }
             goto scan_continue;
         }
@@ -2963,7 +2978,6 @@ ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
         if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) {
             return;
         }
-        ble_ll_scan_aux_data_free(ble_hdr->rxinfo.user_data);
     }
 #endif
 
@@ -3028,6 +3042,7 @@ ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
         /* Lets take last used phy */
         ble_ll_conn_init_phy(connsm, ble_hdr->rxinfo.phy);
 #endif
+        ble_ll_scan_aux_data_unref(aux_data);
 #endif
         ble_ll_conn_created(connsm, NULL);
         return;
@@ -3035,7 +3050,8 @@ ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
 
 scan_continue:
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-    ble_ll_scan_aux_data_free(ble_hdr->rxinfo.user_data);
+    /* Drop last reference and keep continue to connect */
+    ble_ll_scan_aux_data_unref(aux_data);
 #endif
     ble_ll_scan_chk_resume();
 }
@@ -3177,16 +3193,22 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
     /* Get connection state machine to use if connection to be established */
     connsm = g_ble_ll_conn_create_sm;
 
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-    scansm = connsm->scansm;
-    ble_hdr->rxinfo.user_data =scansm->cur_aux_data;
-    scansm->cur_aux_data = NULL;
-#endif
-
     rc = -1;
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
     pyld_len = rxbuf[1];
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+    scansm = connsm->scansm;
+    if (scansm->cur_aux_data) {
+        ble_hdr->rxinfo.user_data = scansm->cur_aux_data;
+        scansm->cur_aux_data = NULL;
+        if (ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data) == 0) {
+            ble_hdr->rxinfo.user_data = 0;
+            goto init_rx_isr_exit;
+        }
+    }
+#endif
+
     if (!crcok) {
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
         /* Invalid packet - make sure we do not wait for AUX_CONNECT_RSP */
@@ -3225,7 +3247,7 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
         if (rc < 0) {
             /* No memory or broken packet */
             ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
-            ble_ll_scan_aux_data_free(ble_hdr->rxinfo.user_data);
+            ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data);
             ble_hdr->rxinfo.user_data = NULL;
             goto init_rx_isr_exit;
         }
@@ -3434,6 +3456,12 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
     STATS_INC(ble_ll_conn_stats, conn_req_txd);
 
 init_rx_isr_exit:
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+    if (ble_hdr->rxinfo.user_data) {
+        ble_ll_scan_aux_data_ref(ble_hdr->rxinfo.user_data);
+    }
+#endif
     /*
      * We have to restart receive if we cant hand up pdu. We return 0 so that
      * the phy does not get disabled.
diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c
index 64e0152..e3996c4 100644
--- a/nimble/controller/src/ble_ll_scan.c
+++ b/nimble/controller/src/ble_ll_scan.c
@@ -38,6 +38,7 @@
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_resolv.h"
 #include "controller/ble_ll_xcvr.h"
+#include "controller/ble_ll_trace.h"
 #include "ble_ll_conn_priv.h"
 
 /*
@@ -168,13 +169,13 @@ ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch)
      * just drop the scheduled item
      */
     if (!scansm->scan_enabled || scansm->cur_aux_data) {
-        ble_ll_scan_aux_data_free(sch->cb_arg);
+        ble_ll_scan_aux_data_unref(sch->cb_arg);
         goto done;
     }
 
     /* Check if there is no aux connect sent. If so drop the sched item */
     if (lls == BLE_LL_STATE_INITIATING && ble_ll_conn_init_pending_aux_conn_rsp()) {
-        ble_ll_scan_aux_data_free(sch->cb_arg);
+        ble_ll_scan_aux_data_unref(sch->cb_arg);
         goto done;
     }
 
@@ -196,7 +197,7 @@ ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch)
     scansm->cur_aux_data->scanning = 1;
 
     if (ble_ll_scan_start(scansm, sch)) {
-        ble_ll_scan_aux_data_free(scansm->cur_aux_data);
+        ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
         scansm->cur_aux_data = NULL;
         ble_ll_scan_chk_resume();
         goto done;
@@ -226,6 +227,8 @@ ble_ll_scan_ext_adv_init(struct ble_ll_aux_data **aux_data)
     e->sch.sched_cb = ble_ll_aux_scan_cb;
     e->sch.cb_arg = e;
     e->sch.sched_type = BLE_LL_SCHED_TYPE_AUX_SCAN;
+    e->ref_cnt = 1;
+    ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t)e, e->ref_cnt);
 
     *aux_data = e;
     STATS_INC(ble_ll_stats, aux_allocated);
@@ -419,7 +422,7 @@ ble_ll_scan_clean_cur_aux_data(void)
 
     /* If scanner was reading aux ptr, we need to clean it up */
     if (scansm && scansm->cur_aux_data) {
-        ble_ll_scan_aux_data_free(scansm->cur_aux_data);
+        ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
         scansm->cur_aux_data = NULL;
     }
 #endif
@@ -1114,6 +1117,59 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
 }
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
 static void
+ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan)
+{
+    if (aux_scan) {
+        if (aux_scan->evt) {
+            ble_hci_trans_buf_free((uint8_t *)aux_scan->evt);
+            aux_scan->evt = NULL;
+        }
+        os_memblock_put(&ext_adv_pool, aux_scan);
+        STATS_INC(ble_ll_stats, aux_freed);
+    }
+}
+
+void
+ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_data)
+{
+    os_sr_t sr;
+
+    if (!aux_data) {
+        return;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    aux_data->ref_cnt++;
+    ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t) aux_data, aux_data->ref_cnt);
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+int
+ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_data)
+{
+    os_sr_t sr;
+    int ret;
+
+    if (!aux_data) {
+        return 0;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    aux_data->ref_cnt--;
+    ret = aux_data->ref_cnt;
+    ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_UNREF, (uint32_t) aux_data, aux_data->ref_cnt);
+
+    if (aux_data->ref_cnt == 0) {
+        ble_ll_scan_aux_data_free(aux_data);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    return ret;
+}
+
+static void
 ble_ll_scan_sched_remove(struct ble_ll_sched_item *sch)
 {
     ble_ll_scan_aux_data_free(sch->cb_arg);
@@ -2074,18 +2130,27 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
         return 0;
     }
 
+    rc = -1;
+
     ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-    ble_hdr->rxinfo.user_data = scansm->cur_aux_data;
-    scansm->cur_aux_data = NULL;
+    if (scansm->cur_aux_data) {
+        ble_hdr->rxinfo.user_data = scansm->cur_aux_data;
+        scansm->cur_aux_data = NULL;
+        if (ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data) == 0) {
+            ble_hdr->rxinfo.user_data = NULL;
+            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
+            goto scan_rx_isr_exit;
+        }
+    }
 #endif
 
     /* Just leave if the CRC is not OK. */
-    rc = -1;
     if (!crcok) {
-        ble_ll_scan_aux_data_free(ble_hdr->rxinfo.user_data);
-        ble_hdr->rxinfo.user_data = NULL;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+        ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
+#endif
         goto scan_rx_isr_exit;
     }
 
@@ -2111,10 +2176,6 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
             ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT;
         }
 
-        /* If the ble_ll_scan_get_aux_data() succeed, scansm->cur_aux_data is NULL
-         * and aux_data contains correct data
-         */
-        BLE_LL_ASSERT(scansm->cur_aux_data == NULL);
         rc = -1;
     }
 #endif
@@ -2227,6 +2288,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
                 if (ble_hdr->rxinfo.channel <  BLE_PHY_NUM_DATA_CHANS) {
                     /* Let's keep the aux ptr as a reference to scan rsp */
                     scansm->cur_aux_data = ble_hdr->rxinfo.user_data;
+                    ble_ll_scan_aux_data_ref(scansm->cur_aux_data);
                     STATS_INC(ble_ll_stats, aux_scan_req_tx);
                 }
 #endif
@@ -2238,6 +2300,12 @@ scan_rx_isr_exit:
     if (rc) {
         ble_ll_state_set(BLE_LL_STATE_STANDBY);
     }
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+    /* On handover lets increase ref count */
+    if (ble_hdr->rxinfo.user_data) {
+        ble_ll_scan_aux_data_ref(ble_hdr->rxinfo.user_data);
+    }
+#endif
     return rc;
 }
 
@@ -2318,7 +2386,7 @@ ble_ll_scan_wfr_timer_exp(void)
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
     if (scansm->cur_aux_data) {
         /*TODO handle chain incomplete, data truncated */
-        ble_ll_scan_aux_data_free(scansm->cur_aux_data);
+        ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
         scansm->cur_aux_data = NULL;
         STATS_INC(ble_ll_stats, aux_missed_adv);
         ble_ll_scan_chk_resume();
@@ -2329,18 +2397,6 @@ ble_ll_scan_wfr_timer_exp(void)
 }
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-void
-ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan)
-{
-    if (aux_scan) {
-        if (aux_scan->evt) {
-            ble_hci_trans_buf_free((uint8_t *)aux_scan->evt);
-        }
-        os_memblock_put(&ext_adv_pool, aux_scan);
-        STATS_INC(ble_ll_stats, aux_freed);
-    }
-}
-
 /*
  * Send extended advertising report
  *
@@ -2364,7 +2420,8 @@ ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
     uint8_t max_event_len;
 
     if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
-        return -1;
+        rc = -1;
+        goto done;
     }
 
     /*
@@ -2378,7 +2435,8 @@ ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
     } else {
         evt = ble_ll_scan_init_ext_adv_report(NULL);
         if (!evt) {
-            return -1;
+            rc = -1;
+            goto done;
         }
     }
 
@@ -2386,7 +2444,8 @@ ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
     if (datalen < 0) {
         /* XXX what should we do here? send some trimmed event? */
         ble_hci_trans_buf_free((uint8_t *)evt);
-        return -1;
+        rc = -1;
+        goto done;
     }
 
     offset = 0;
@@ -2460,6 +2519,12 @@ ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
         BLE_LL_ASSERT(!evt);
     }
 
+done:
+    /* If advertising event is completed or failed, we can drop the reference */
+    if (rc <= 0) {
+        ble_ll_scan_aux_data_unref(aux_data);
+    }
+
     return rc;
 }
 #endif
@@ -2542,6 +2607,9 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
     if (ble_ll_scan_chk_filter_policy(ptype, adv_addr, txadd, init_addr,
                                       init_addr_type,
                                       BLE_MBUF_HDR_DEVMATCH(hdr))) {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+        ble_ll_scan_aux_data_unref(aux_data);
+#endif
         goto scan_continue;
     }
 
@@ -2582,6 +2650,11 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
     /* Filter duplicates */
     if (scansm->scan_filt_dups) {
         if (ble_ll_scan_is_dup_adv(ptype, ident_addr_type, ident_addr)) {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+            if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
+                ble_ll_scan_aux_data_unref(aux_data);
+            }
+#endif
             goto scan_continue;
         }
     }
@@ -2589,6 +2662,7 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
     if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
         if (!scansm->ext_scanning) {
+            ble_ll_scan_aux_data_unref(aux_data);
             goto scan_continue;
         }
 
@@ -2596,8 +2670,9 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
             goto scan_continue;
         }
 
-
+        /* If it is ignore it means event is already truncated, just unref aux */
         if (aux_data && BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_IGNORE_BIT)) {
+            ble_ll_scan_aux_data_unref(aux_data);
             goto scan_continue;
         }
 
@@ -2609,13 +2684,22 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
                 hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
                 /* Mark that chain is trimmed */
                 aux_data->flags |= BLE_LL_AUX_INCOMPLETE_ERR_BIT;
+                /* Note: aux_data unref will be done when truncated is sent to the host or
+                 * below if we failed to schedule for the very first aux packet.
+                 */
+            } else {
+                /* We are here because successfully scheduled for next aux */
+                ble_ll_scan_aux_data_ref(aux_data);
             }
 
+            /*
+             * If this is ext adv, there is nothing to do here but just leave and wait
+             * for aux packet. However, if we was not able to schedule for first aux packet,
+             * make sure to unref aux_data here
+             */
             if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_CHAIN_BIT)) {
-                /* This is just beacon. Let's wait for more data */
-                if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
-                    /* If scheduled for aux let's don't remove aux data */
-                    hdr->rxinfo.user_data = NULL;
+                if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
+                    ble_ll_scan_aux_data_unref(aux_data);
                 }
                 goto scan_continue;
             }
@@ -2623,6 +2707,8 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
             STATS_INC(ble_ll_stats, aux_chain_cnt);
         }
 
+        /* For the time when sending events up, lets increase ref count */
+        ble_ll_scan_aux_data_ref(aux_data);
         rc = ble_ll_hci_send_ext_adv_report(ptype, ident_addr, ident_addr_type,
                                             init_addr, init_addr_type, om, hdr);
         if (rc < 0) {
@@ -2631,19 +2717,25 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
              * make sure we do not send any more events for this chain, just in
              * case we managed to scan something before events were processed.
              */
-            ble_ll_sched_rmv_elem(&aux_data->sch);
-            hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
+            if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
+                hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
+                if (ble_ll_sched_rmv_elem(&aux_data->sch) == 0) {
+                    ble_ll_scan_aux_data_unref(aux_data);
+                }
+            }
             aux_data->flags |= BLE_LL_AUX_IGNORE_BIT;
         }
-        ble_ll_scan_switch_phy(scansm);
+        ble_ll_scan_aux_data_unref(aux_data);
 
-        if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
-            /* If scheduled for aux let's don't remove aux data */
-            hdr->rxinfo.user_data = NULL;
-        }
+        ble_ll_scan_switch_phy(scansm);
 
         if (scansm->scan_rsp_pending) {
             if (!scan_rsp_chk) {
+                /* We are here because we sent SCAN_REQ and wait for SCAN_RSP.
+                 * We do not drop reference here by purpose, because
+                 * it was already dropped in ble_ll_hci_send_ext_adv_report() as
+                 * very first advertising report for scannable report is "completed"
+                 */
                 return;
             }
 
@@ -2661,7 +2753,10 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
 scan_continue:
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-        ble_ll_scan_aux_data_free(hdr->rxinfo.user_data);
+    if (aux_data) {
+        /* This is ref for handover to LL */
+        ble_ll_scan_aux_data_unref(aux_data);
+    }
 #endif
     /*
      * If the scan response check bit is set and we are pending a response,
diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c
index 04e630c..9a22ede 100644
--- a/nimble/controller/src/ble_ll_sched.c
+++ b/nimble/controller/src/ble_ll_sched.c
@@ -250,7 +250,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
                 break;
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
             case BLE_LL_SCHED_TYPE_AUX_SCAN:
-                ble_ll_scan_aux_data_free((struct ble_ll_aux_data *)
+                ble_ll_scan_aux_data_unref((struct ble_ll_aux_data *)
                                           entry->cb_arg);
                 break;
 #endif
@@ -1361,7 +1361,7 @@ ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode)
             return 1;
         }
 
-        ble_ll_scan_aux_data_free((struct ble_ll_aux_data *)sch->cb_arg);
+        ble_ll_scan_aux_data_unref((struct ble_ll_aux_data *)sch->cb_arg);
         TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
         sch->enqueued = 0;
         sch = TAILQ_FIRST(&g_ble_ll_sched_q);
diff --git a/nimble/controller/src/ble_ll_trace.c b/nimble/controller/src/ble_ll_trace.c
index bdea2bf..330b3d4 100644
--- a/nimble/controller/src/ble_ll_trace.c
+++ b/nimble/controller/src/ble_ll_trace.c
@@ -41,6 +41,8 @@ ble_ll_trace_module_send_desc(void)
     os_trace_module_desc(&g_ble_ll_trace_mod, "9 ll_conn_rx conn_sn=%u pdu_nesn=%u");
     os_trace_module_desc(&g_ble_ll_trace_mod, "10 ll_adv_txdone inst=%u chanset=%x");
     os_trace_module_desc(&g_ble_ll_trace_mod, "11 ll_adv_halt inst=%u");
+    os_trace_module_desc(&g_ble_ll_trace_mod, "12 ll_aux_ref aux=%p ref=%u");
+    os_trace_module_desc(&g_ble_ll_trace_mod, "13 ll_aux_unref aux=%p ref=%u");
 }
 
 void