You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2019/12/03 22:37:19 UTC

[mynewt-nimble] 01/08: nimble/ll: Refactor periodic sync synchronization

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

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

commit 914e044327abe2387a16c83d4436130f8a5d1ffe
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Tue Oct 22 14:08:01 2019 +0200

    nimble/ll: Refactor periodic sync synchronization
    
    This is a preparation for adding transfer sync support which is
    independent of synchronization procesure. This also fixes
    HCI/CCO/BV-17-C qualification test case.
    
    This includes:
     - adding separate periodic device list
     - SM struct is only used for synchronized syncs
---
 nimble/controller/include/controller/ble_ll_sync.h |   1 +
 nimble/controller/src/ble_ll.c                     |   1 +
 nimble/controller/src/ble_ll_sync.c                | 535 +++++++++++----------
 nimble/controller/syscfg.yml                       |   5 +
 4 files changed, 281 insertions(+), 261 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h
index 803fb60..c217437 100644
--- a/nimble/controller/include/controller/ble_ll_sync.h
+++ b/nimble/controller/include/controller/ble_ll_sync.h
@@ -56,6 +56,7 @@ uint32_t ble_ll_sync_get_event_end_time(void);
 bool ble_ll_sync_enabled(void);
 
 void ble_ll_sync_reset(void);
+void ble_ll_sync_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index 3d53096..c990ad0 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -1651,6 +1651,7 @@ ble_ll_init(void)
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
     features |= BLE_LL_FEAT_PERIODIC_ADV;
+    ble_ll_sync_init();
 #endif
 
     /* Initialize random number generation */
diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c
index 8524790..e5b4d01 100644
--- a/nimble/controller/src/ble_ll_sync.c
+++ b/nimble/controller/src/ble_ll_sync.c
@@ -45,15 +45,15 @@
 #define BLE_LL_SYNC_ESTABLISH_CNT 6
 
 #define BLE_LL_SYNC_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT)
+#define BLE_LL_SYNC_LIST_CNT MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT)
 
-#define BLE_LL_SYNC_SM_FLAG_ON_LIST         0x01
-#define BLE_LL_SYNC_SM_FLAG_PENDING         0x02
-#define BLE_LL_SYNC_SM_FLAG_ESTABLISHING    0x04
-#define BLE_LL_SYNC_SM_FLAG_ESTABLISHED     0x08
-#define BLE_LL_SYNC_SM_FLAG_SET_ANCHOR      0x10
-#define BLE_LL_SYNC_SM_FLAG_OFFSET_300      0x20
-#define BLE_LL_SYNC_SM_FLAG_SYNC_INFO       0x40
-#define BLE_LL_SYNC_SM_FLAG_DISABLED        0x80
+#define BLE_LL_SYNC_SM_FLAG_RESERVED        0x01
+#define BLE_LL_SYNC_SM_FLAG_ESTABLISHING    0x02
+#define BLE_LL_SYNC_SM_FLAG_ESTABLISHED     0x04
+#define BLE_LL_SYNC_SM_FLAG_SET_ANCHOR      0x08
+#define BLE_LL_SYNC_SM_FLAG_OFFSET_300      0x10
+#define BLE_LL_SYNC_SM_FLAG_SYNC_INFO       0x20
+#define BLE_LL_SYNC_SM_FLAG_DISABLED        0x40
 
 #define BLE_LL_SYNC_CHMAP_LEN               5
 #define BLE_LL_SYNC_ITVL_USECS              1250
@@ -74,6 +74,8 @@ struct ble_ll_sync_sm {
 
     uint8_t phy_mode;
 
+    uint8_t sync_pending_cnt;
+
     uint32_t timeout;
     uint16_t skip;
 
@@ -100,11 +102,65 @@ struct ble_ll_sync_sm {
 
 static struct ble_ll_sync_sm g_ble_ll_sync_sm[BLE_LL_SYNC_CNT];
 
-static unsigned int g_ble_ll_sync_pending;
+static struct {
+    uint8_t adv_sid;
+    uint8_t adv_addr[BLE_DEV_ADDR_LEN];
+    uint8_t adv_addr_type;
+} g_ble_ll_sync_adv_list[BLE_LL_SYNC_LIST_CNT];
+
+static struct {
+    uint32_t timeout;
+    uint16_t max_skip;
+    uint16_t options;
+} g_ble_ll_sync_create_params;
+
+/* if this is set HCI LE Sync Create is pending */
+static uint8_t *g_ble_ll_sync_create_comp_ev;
 
-static struct ble_ll_sync_sm *g_ble_ll_sync_sm_establishing;
 static struct ble_ll_sync_sm *g_ble_ll_sync_sm_current;
-static uint8_t *g_ble_ll_sync_comp_ev;
+
+static int
+ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        if ((g_ble_ll_sync_adv_list[i].adv_sid == sid) &&
+                (g_ble_ll_sync_adv_list[i].adv_addr_type == addr_type) &&
+                !memcmp(g_ble_ll_sync_adv_list[i].adv_addr, addr, BLE_DEV_ADDR_LEN)) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+static int
+ble_ll_sync_list_get_free(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        if (g_ble_ll_sync_adv_list[i].adv_sid == 0xff) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+static bool
+ble_ll_sync_list_empty(void) {
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        if (g_ble_ll_sync_adv_list[i].adv_sid != 0xff) {
+            return false;
+        }
+    }
+
+    return true;
+}
 
 static uint8_t
 ble_ll_sync_get_handle(struct ble_ll_sync_sm *sm)
@@ -126,6 +182,20 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm)
         ble_hci_trans_buf_free(sm->next_report);
     }
 
+    if (g_ble_ll_sync_sm_current == sm) {
+        ble_phy_disable();
+        ble_ll_wfr_disable();
+        ble_ll_state_set(BLE_LL_STATE_STANDBY);
+        g_ble_ll_sync_sm_current = NULL;
+        ble_ll_scan_chk_resume();
+    }
+
+#ifdef BLE_XCVR_RFCLK
+        ble_ll_sched_rfclk_chk_restart();
+#endif
+
+    BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0);
+    BLE_LL_ASSERT(sm->sch.enqueued == 0);
     memset(sm, 0, sizeof(*sm));
 }
 
@@ -160,10 +230,10 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
     struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev;
     struct ble_hci_ev *hci_ev;
 
-    BLE_LL_ASSERT(g_ble_ll_sync_comp_ev);
+    BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev);
 
     if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) {
-        hci_ev = (void *) g_ble_ll_sync_comp_ev;
+        hci_ev = (void *) g_ble_ll_sync_create_comp_ev;
 
         hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
         hci_ev->length = sizeof(*ev);
@@ -181,10 +251,10 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
 
         ble_ll_hci_event_send(hci_ev);
     } else {
-        ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
+        ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
     }
 
-    g_ble_ll_sync_comp_ev = NULL;
+    g_ble_ll_sync_create_comp_ev = NULL;
 }
 
 static void
@@ -193,10 +263,10 @@ ble_ll_sync_est_event_failed(uint8_t status)
     struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev;
     struct ble_hci_ev *hci_ev;
 
-    BLE_LL_ASSERT(g_ble_ll_sync_comp_ev);
+    BLE_LL_ASSERT(g_ble_ll_sync_create_comp_ev);
 
     if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB)) {
-        hci_ev = (void *) g_ble_ll_sync_comp_ev;
+        hci_ev = (void *) g_ble_ll_sync_create_comp_ev;
 
         hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
         hci_ev->length = sizeof(*ev);
@@ -209,10 +279,10 @@ ble_ll_sync_est_event_failed(uint8_t status)
 
         ble_ll_hci_event_send(hci_ev);
     } else {
-        ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
+        ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
     }
 
-    g_ble_ll_sync_comp_ev = NULL;
+    g_ble_ll_sync_create_comp_ev = NULL;
 }
 
 static void
@@ -234,8 +304,6 @@ ble_ll_sync_lost_event(struct ble_ll_sync_sm *sm)
             ble_ll_hci_event_send(hci_ev);
         }
     }
-
-    ble_ll_sync_sm_clear(sm);
 }
 
 static struct ble_ll_sync_sm *
@@ -259,31 +327,6 @@ ble_ll_sync_find(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
     return NULL;
 }
 
-static struct ble_ll_sync_sm *
-ble_ll_sync_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
-{
-    struct ble_ll_sync_sm *sm;
-    int i;
-
-    sm = ble_ll_sync_find(addr, addr_type, sid);
-    if (sm) {
-        return sm;
-    }
-
-    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-        sm = &g_ble_ll_sync_sm[i];
-
-        if (!sm->flags) {
-            sm->adv_sid = sid;
-            sm->adv_addr_type = addr_type;
-            memcpy(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN);
-            return sm;
-        }
-    }
-
-    return NULL;
-}
-
 static void
 ble_ll_sync_current_sm_over(void)
 {
@@ -310,9 +353,10 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch)
 
     /* Set current connection state machine */
     sm = sch->cb_arg;
-    g_ble_ll_sync_sm_current = sm;
     BLE_LL_ASSERT(sm);
 
+    g_ble_ll_sync_sm_current = sm;
+
     /* Disable whitelisting */
     ble_ll_whitelist_disable();
 
@@ -378,30 +422,16 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch)
 int
 ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr)
 {
-    struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current;
-
     BLE_LL_ASSERT(g_ble_ll_sync_sm_current);
 
     /* this also handles chains as those have same PDU type */
     if (pdu_type != BLE_ADV_PDU_TYPE_AUX_SYNC_IND) {
-        ble_ll_event_send(&sm->sync_ev_end);
+        ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end);
         ble_ll_sync_current_sm_over();
         STATS_INC(ble_ll_stats, sched_invalid_pdu);
         return -1;
     }
 
-    /* Set anchor point (and last) if 1st rxd frame in sync event.
-     * According to spec this should be done even if CRC is not valid so we
-     * can store it here
-     */
-    if (sm->flags & BLE_LL_SYNC_SM_FLAG_SET_ANCHOR) {
-        sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR;
-
-        sm->anchor_point = rxhdr->beg_cputime;
-        sm->anchor_point_usecs = rxhdr->rem_usecs;
-        sm->last_anchor_point = sm->anchor_point;
-    }
-
     STATS_INC(ble_ll_stats, sync_received);
     return 0;
 }
@@ -631,13 +661,10 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu,
 int
 ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
 {
-    struct ble_ll_sync_sm *sm = g_ble_ll_sync_sm_current;
     struct ble_mbuf_hdr *ble_hdr;
     struct os_mbuf *rxpdu;
 
-    BLE_LL_ASSERT(sm);
-
-    ble_ll_sync_current_sm_over();
+    BLE_LL_ASSERT(g_ble_ll_sync_sm_current);
 
     /* type was verified in isr_start */
 
@@ -646,14 +673,16 @@ ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
         ble_phy_rxpdu_copy(rxbuf, rxpdu);
 
         ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
-        ble_hdr->rxinfo.user_data = sm;
+        ble_hdr->rxinfo.user_data = g_ble_ll_sync_sm_current;
 
         ble_ll_rx_pdu_in(rxpdu);
     } else {
         STATS_INC(ble_ll_stats, sync_rx_buf_err);
-        ble_ll_event_send(&sm->sync_ev_end);
+        ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end);
     }
 
+    ble_ll_sync_current_sm_over();
+
     return -1;
 }
 
@@ -843,49 +872,29 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr,
 static void
 ble_ll_sync_established(struct ble_ll_sync_sm *sm)
 {
-    int i;
-
-    BLE_LL_ASSERT(sm == g_ble_ll_sync_sm_establishing);
-    BLE_LL_ASSERT(g_ble_ll_sync_pending);
+    BLE_LL_ASSERT(sm->sync_pending_cnt);
 
     /* mark as established */
     ble_ll_sync_est_event_success(sm);
     sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHED;
     sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
 
-    /* clear as we are not longer pending sync here */
-    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-        g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
-    }
-
-    g_ble_ll_sync_sm_establishing = NULL;
-    g_ble_ll_sync_pending = 0;
+    sm->sync_pending_cnt = 0;
 }
 
 static void
 ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm)
 {
-    int i;
-
-    BLE_LL_ASSERT(sm == g_ble_ll_sync_sm_establishing);
-    BLE_LL_ASSERT(g_ble_ll_sync_pending);
+    BLE_LL_ASSERT(sm->sync_pending_cnt);
 
     /* if we can retry on next event */
-    if (--g_ble_ll_sync_pending) {
+    if (--sm->sync_pending_cnt) {
         return;
     }
 
     ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
 
     sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
-
-    /* clear as we are not longer pending sync here */
-    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-        g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
-    }
-
-    g_ble_ll_sync_sm_establishing = NULL;
-    g_ble_ll_sync_pending = 0;
 }
 
 void
@@ -896,14 +905,26 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
 
     BLE_LL_ASSERT(sm);
 
-    /* this could happen if sync was terminated while pkt_in was already
-     * in LL queue, just drop in that case
+    /* this could happen if sync was cancelled or terminated while pkt_in was
+     * already in LL queue, just drop in that case
      */
     if (!sm->flags) {
         ble_ll_scan_chk_resume();
         return;
     }
 
+    /* Set anchor point (and last) if 1st rxd frame in sync event.
+     * According to spec this should be done even if CRC is not valid so we
+     * can store it here
+     */
+    if (sm->flags & BLE_LL_SYNC_SM_FLAG_SET_ANCHOR) {
+        sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR;
+
+        sm->anchor_point = hdr->beg_cputime;
+        sm->anchor_point_usecs = hdr->rem_usecs;
+        sm->last_anchor_point = sm->anchor_point;
+    }
+
     /* CRC error, end event */
     if (!BLE_MBUF_HDR_CRC_OK(hdr)) {
         STATS_INC(ble_ll_stats, sync_crc_err);
@@ -1045,9 +1066,12 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
     /* Remove any end events that might be enqueued */
     ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end);
 
-    /* don't schedule next event if sync is not established nor establishing */
+    /* don't schedule next event if sync is not established nor establishing
+     * at this point SM is no longer valid
+     */
     if (!(sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHED |
                        BLE_LL_SYNC_SM_FLAG_ESTABLISHING))) {
+        ble_ll_sync_sm_clear(sm);
         return;
     }
 
@@ -1067,11 +1091,14 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
         if (ble_ll_sync_next_event(sm) < 0) {
             if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
                 /* don't allow any retry if this failed */
-                g_ble_ll_sync_pending = 1;
+                sm->sync_pending_cnt = 1;
                 ble_ll_sync_check_failed(sm);
             } else {
                 ble_ll_sync_lost_event(sm);
             }
+
+            /* at this point SM is no longer valid */
+            ble_ll_sync_sm_clear(sm);
             return;
         }
     } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->anchor_point,
@@ -1096,29 +1123,46 @@ void
 ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
                        struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo)
 {
-    struct ble_ll_sync_sm *sm;
+    struct ble_ll_sync_sm *sm = NULL;
     uint16_t max_skip;
     uint32_t offset;
     uint32_t usecs;
+    uint16_t itvl;
+    int i;
 
-    if (!g_ble_ll_sync_pending || g_ble_ll_sync_sm_establishing) {
+    /* ignore if not synchronizing */
+    if (!g_ble_ll_sync_create_comp_ev) {
         return;
     }
 
-    sm = ble_ll_sync_find(addr, addr_type, sid);
+    /* get reserved SM */
+    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
+        if (g_ble_ll_sync_sm[i].flags & BLE_LL_SYNC_SM_FLAG_RESERVED) {
+            sm = &g_ble_ll_sync_sm[i];
+            break;
+        }
+    }
+
+    /* this means we already got sync info event and pending sync */
     if (!sm) {
         return;
     }
 
-    /* don't attempt to synchronize again if already synchronized */
-    if (sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING |
-                     BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) {
+    /* check peer */
+    if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) {
+        if (ble_ll_sync_on_list(addr, addr_type, sid) < 0) {
             return;
-    }
+        }
 
-    /* check if this SM is allowed to establish new sync */
-    if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_PENDING)) {
+        /* set addr and sid in sm */
+        sm->adv_sid = sid;
+        sm->adv_addr_type = addr_type;
+        memcpy(sm->adv_addr, addr, BLE_DEV_ADDR_LEN);
+    } else {
+        if ((sm->adv_sid != sid) || (sm->adv_addr_type != addr_type) ||
+                memcmp(sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
             return;
+        }
     }
 
     /* Sync Packet Offset (13 bits), Offset Units (1 bit), RFU (2 bits) */
@@ -1130,6 +1174,17 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
         return;
     }
 
+    /* Interval (2 bytes), ignore if invalid */
+    itvl = get_le16(&syncinfo[2]);
+    if (itvl < 6) {
+        return;
+    }
+
+    /* set params from HCI LE Create Periodic Sync */
+    sm->timeout = g_ble_ll_sync_create_params.timeout;
+    sm->skip = g_ble_ll_sync_create_params.max_skip;
+    sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT;
+
     if (syncinfo[1] & 0x20) {
         offset *= 300;
         sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300;
@@ -1141,13 +1196,7 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
     /* sync end event */
     ble_npl_event_init(&sm->sync_ev_end, ble_ll_sync_event_end, sm);
 
-    /* Interval (2 bytes) */
-    sm->itvl = get_le16(&syncinfo[2]);
-
-    /* ignore if interval is invalid */
-    if (sm->itvl < 6) {
-        return;
-    }
+    sm->itvl = itvl;
 
     /* precalculate interval ticks and usecs */
     usecs = sm->itvl * BLE_LL_SYNC_ITVL_USECS;
@@ -1224,10 +1273,33 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
 
     sm->last_anchor_point = sm->anchor_point;
 
-    /* keep sm for which we want to establish new sync */
+#if MYNEWT_VAL(BLE_VERSION) >= 51
+    if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
+        sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
+    }
+#endif
+
+    sm->flags &= ~BLE_LL_SYNC_SM_FLAG_RESERVED;
     sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
     sm->flags |= BLE_LL_SYNC_SM_FLAG_SYNC_INFO;
-    g_ble_ll_sync_sm_establishing = sm;
+}
+
+static struct ble_ll_sync_sm *
+ble_ll_sync_reserve(void)
+{
+    struct ble_ll_sync_sm *sm;
+    int i;
+
+    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
+        sm = &g_ble_ll_sync_sm[i];
+
+        if (!sm->flags) {
+            sm->flags |= BLE_LL_SYNC_SM_FLAG_RESERVED;
+            return sm;
+        }
+    }
+
+    return NULL;
 }
 
 int
@@ -1237,10 +1309,8 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
     struct ble_ll_sync_sm *sm;
     uint16_t timeout;
     os_sr_t sr;
-    int cnt;
-    int i;
 
-    if (g_ble_ll_sync_pending) {
+    if (g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -1261,7 +1331,7 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
     }
 
     timeout = le16toh(cmd->sync_timeout);
-    if (timeout < 0x000a && timeout > 0x4000) {
+    if (timeout < 0x000a || timeout > 0x4000) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
@@ -1276,44 +1346,8 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
     }
 #endif
 
-    /* check if list is sane */
     if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) {
-        cnt = 0;
-
-        OS_ENTER_CRITICAL(sr);
-
-        for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-            sm = &g_ble_ll_sync_sm[i];
-
-            if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ON_LIST)) {
-                continue;
-            }
-
-            /* skip if already synchronized
-             * TODO should we return 0x0B if list is to be used?
-             */
-            if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
-                continue;
-            }
-
-            /* mark as pending */
-            sm->flags |= BLE_LL_SYNC_SM_FLAG_PENDING;
-#if MYNEWT_VAL(BLE_VERSION) >= 51
-            if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
-                sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
-            }
-#endif
-            sm->timeout = timeout * 10000; /* 10ms units, store in us */
-            sm->skip = cmd->skip;
-            cnt++;
-        }
-
-        OS_EXIT_CRITICAL(sr);
-
-        /* if nothing on list return error
-         * TODO is this valid behavior?
-         */
-        if (!cnt) {
+        if (ble_ll_sync_list_empty()) {
             return BLE_ERR_CMD_DISALLOWED;
         }
     } else {
@@ -1325,49 +1359,44 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len)
             return BLE_ERR_INV_HCI_CMD_PARMS;
         }
 
-        sm = ble_ll_sync_get(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
-        if (!sm) {
-            return BLE_ERR_MEM_CAPACITY;
-        }
-
         OS_ENTER_CRITICAL(sr);
+        sm = ble_ll_sync_find(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
+        OS_EXIT_CRITICAL(sr);
 
-        /* if we already have link established return error as per spec */
-        if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
-            OS_EXIT_CRITICAL(sr);
+        if (sm) {
             return BLE_ERR_ACL_CONN_EXISTS;
         }
-
-        /* mark as pending */
-        sm->flags |= BLE_LL_SYNC_SM_FLAG_PENDING;
-#if MYNEWT_VAL(BLE_VERSION) >= 51
-            if (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) {
-                sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
-            }
-#endif
-        sm->timeout = timeout * 10000; /* 10ms units, store in us */
-        sm->skip = cmd->skip;
-
-        OS_EXIT_CRITICAL(sr);
     }
 
-    g_ble_ll_sync_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
-    if (!g_ble_ll_sync_comp_ev) {
-        OS_ENTER_CRITICAL(sr);
+    /* reserve buffer for sync complete event */
+    g_ble_ll_sync_create_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+    if (!g_ble_ll_sync_create_comp_ev) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
 
-        for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-            g_ble_ll_sync_sm[i].flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
-            sm->timeout = 0;
-            sm->skip = 0;
-        }
+    OS_ENTER_CRITICAL(sr);
 
+    /* reserve 1 SM for created sync */
+    sm = ble_ll_sync_reserve();
+    if (!sm) {
+        ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
+        g_ble_ll_sync_create_comp_ev = NULL;
         OS_EXIT_CRITICAL(sr);
-
         return BLE_ERR_MEM_CAPACITY;
     }
 
-    g_ble_ll_sync_pending = BLE_LL_SYNC_ESTABLISH_CNT;
+    /* if we don't use list, store expected address in reserved SM */
+    if (!(cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER)) {
+        sm->adv_sid = cmd->sid;
+        sm->adv_addr_type = cmd->peer_addr_type;
+        memcpy(&sm->adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN);
+    }
+
+    g_ble_ll_sync_create_params.timeout = timeout * 10000; /* 10ms units, store in us */;
+    g_ble_ll_sync_create_params.max_skip = cmd->skip;
+    g_ble_ll_sync_create_params.options = cmd->options;
 
+    OS_EXIT_CRITICAL(sr);
     return BLE_ERR_SUCCESS;
 }
 
@@ -1384,7 +1413,7 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
     os_sr_t sr;
     int i;
 
-    if (!g_ble_ll_sync_pending) {
+    if (!g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -1393,20 +1422,22 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
     for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
         sm = &g_ble_ll_sync_sm[i];
 
-        sm->flags &= ~BLE_LL_SYNC_SM_FLAG_PENDING;
+        /* cancelled before fist sync info packet */
+        if (sm->flags & BLE_LL_SYNC_SM_FLAG_RESERVED) {
+            memset(sm, 0, sizeof(*sm));
+            break;
+        }
 
+        /* cancelled while pending sync */
         if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
-            sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
-            ble_ll_sched_rmv_elem(&sm->sch);
-            ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end);
+            ble_ll_sync_sm_clear(sm);
+            break;
         }
     }
 
     OS_EXIT_CRITICAL(sr);
 
-    g_ble_ll_sync_pending = 0;
-    g_ble_ll_sync_sm_establishing = NULL;
-
+    /* g_ble_ll_sync_create_comp_ev will be cleared by this callback */
     *post_cmd_cb = ble_ll_sync_cancel_complete_event;
 
     return BLE_ERR_SUCCESS;
@@ -1420,7 +1451,7 @@ ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len)
     uint16_t handle;
     os_sr_t sr;
 
-    if (g_ble_ll_sync_pending) {
+    if (g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -1457,10 +1488,9 @@ int
 ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len)
 {
     const struct ble_hci_le_add_dev_to_periodic_adv_list_cp *cmd = (const void *)cmdbuf;
-    struct ble_ll_sync_sm *sm;
-    os_sr_t sr;
+    int i;
 
-    if (g_ble_ll_sync_pending) {
+    if (g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -1475,17 +1505,19 @@ ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    OS_ENTER_CRITICAL(sr);
+    i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
+    if (i >= 0) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
 
-    sm = ble_ll_sync_get(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
-    if (!sm) {
-        OS_EXIT_CRITICAL(sr);
+    i = ble_ll_sync_list_get_free();
+    if (i < 0) {
         return BLE_ERR_MEM_CAPACITY;
     }
 
-    sm->flags |= BLE_LL_SYNC_SM_FLAG_ON_LIST;
-
-    OS_EXIT_CRITICAL(sr);
+    g_ble_ll_sync_adv_list[i].adv_sid = cmd->sid;
+    g_ble_ll_sync_adv_list[i].adv_addr_type = cmd->peer_addr_type;
+    memcpy(&g_ble_ll_sync_adv_list[i].adv_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN);
 
     return BLE_ERR_SUCCESS;
 }
@@ -1494,14 +1526,13 @@ int
 ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
 {
     const struct ble_hci_le_rem_dev_from_periodic_adv_list_cp *cmd = (const void *)cmdbuf;
-    struct ble_ll_sync_sm *sm;
-    os_sr_t sr;
+    int i;
 
     if (len != sizeof(*cmd)) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    if (g_ble_ll_sync_pending) {
+    if (g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -1513,22 +1544,13 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    OS_ENTER_CRITICAL(sr);
-
-    sm = ble_ll_sync_find(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
-    if (!sm) {
-        OS_EXIT_CRITICAL(sr);
+    i = ble_ll_sync_on_list(cmd->peer_addr, cmd->peer_addr_type, cmd->sid);
+    if (i < 0) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
-    /* if sync is established only mark entry as removed from list */
-    if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
-        sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ON_LIST;
-    } else {
-        ble_ll_sync_sm_clear(sm);
-    }
-
-    OS_EXIT_CRITICAL(sr);
+    memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
+    g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
 
     return BLE_ERR_SUCCESS;
 }
@@ -1536,30 +1558,17 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len)
 int
 ble_ll_sync_list_clear(void)
 {
-    struct ble_ll_sync_sm *sm;
-    os_sr_t sr;
     int i;
 
-    if (g_ble_ll_sync_pending) {
+    if (g_ble_ll_sync_create_comp_ev) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
-    OS_ENTER_CRITICAL(sr);
-
-    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-        sm = &g_ble_ll_sync_sm[i];
-
-        /* if sync is establish only mark entry as removed from list */
-        if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED) {
-            sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ON_LIST;
-            continue;
-        }
-
-        ble_ll_sync_sm_clear(sm);
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
+        g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
     }
 
-    OS_EXIT_CRITICAL(sr);
-
     return BLE_ERR_SUCCESS;
 }
 
@@ -1567,24 +1576,8 @@ int
 ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen)
 {
     struct ble_hci_le_rd_periodic_adv_list_size_rp *rsp = (void *) rspbuf;
-    os_sr_t sr;
-    int i;
-
-    rsp->list_size = 0;
-
-    OS_ENTER_CRITICAL(sr);
 
-    for (i = 0; i < BLE_LL_SYNC_CNT; i++) {
-        /* only established syncs 'consume' state machine entry */
-        if (g_ble_ll_sync_sm[i].flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING |
-                                         BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) {
-            continue;
-        }
-
-        rsp->list_size++;
-    }
-
-    OS_EXIT_CRITICAL(sr);
+    rsp->list_size = ARRAY_SIZE(g_ble_ll_sync_adv_list);
 
     *rsplen = sizeof(*rsp);
     return BLE_ERR_SUCCESS;
@@ -1632,7 +1625,6 @@ ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len)
     }
 
     OS_EXIT_CRITICAL(sr);
-
     return BLE_ERR_SUCCESS;
 }
 #endif
@@ -1650,9 +1642,14 @@ ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm)
 bool
 ble_ll_sync_enabled(void)
 {
-    return g_ble_ll_sync_pending > 0;
+    return g_ble_ll_sync_create_comp_ev != NULL;
 }
 
+/**
+ * Called to reset the sync module. When this function is called the
+ * scheduler has been stopped and the phy has been disabled. The LL should
+ * be in the standby state.
+ */
 void
 ble_ll_sync_reset(void)
 {
@@ -1662,14 +1659,30 @@ ble_ll_sync_reset(void)
         ble_ll_sync_sm_clear(&g_ble_ll_sync_sm[i]);
     }
 
-    g_ble_ll_sync_pending = 0;
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        memset(&g_ble_ll_sync_adv_list[i], 0, sizeof(g_ble_ll_sync_adv_list[i]));
+        g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
+    }
+
+    g_ble_ll_sync_create_params.timeout = 0;
+    g_ble_ll_sync_create_params.max_skip = 0;
+    g_ble_ll_sync_create_params.options = 0;
 
-    g_ble_ll_sync_sm_establishing = NULL;
     g_ble_ll_sync_sm_current = NULL;
 
-    if (g_ble_ll_sync_comp_ev) {
-        ble_hci_trans_buf_free(g_ble_ll_sync_comp_ev);
-        g_ble_ll_sync_comp_ev = NULL;
+    if (g_ble_ll_sync_create_comp_ev) {
+        ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev);
+        g_ble_ll_sync_create_comp_ev = NULL;
+    }
+}
+
+void
+ble_ll_sync_init(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) {
+        g_ble_ll_sync_adv_list[i].adv_sid = 0xff;
     }
 }
 #endif
diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml
index a12b4c9..be90a44 100644
--- a/nimble/controller/syscfg.yml
+++ b/nimble/controller/syscfg.yml
@@ -276,6 +276,11 @@ syscfg.defs:
             This option is used to configure number of supported periodic syncs.
         value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
 
+    BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT:
+        description: >
+            Size of Periodic Advertiser sync list.
+        value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
+
     BLE_LL_EXT_ADV_AUX_PTR_CNT:
          description: >
             This option configure a max number of scheduled outstanding auxiliary