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:18 UTC

[mynewt-nimble] branch master updated (3a2f0da -> 6e84712)

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

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


    from 3a2f0da  nimble/mesh: Add support for log modules
     new 914e044  nimble/ll: Refactor periodic sync synchronization
     new 1e0b094  nimble/ll: Add api for resolving peer RPA to any IRK on list
     new 8a4431b  nimble/ll: Add support for sync transfer reception
     new cd0afd3  nimble/ll: Add support for sync transfer transmission
     new 465b5c8  nimble/host: Add support for sync transfer
     new afc7260  nimble/btshell: Add support for periodic sync transfer
     new 734c26f  nimble/ll: Allow host to assign advertising instances
     new 6e84712  nimble/ll: Fix missing rfclk restart when not ending sync event

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 apps/btshell/src/cmd.c                             |  222 +++-
 apps/btshell/src/main.c                            |   29 +
 nimble/controller/include/controller/ble_ll.h      |   11 +
 nimble/controller/include/controller/ble_ll_adv.h  |    3 +
 nimble/controller/include/controller/ble_ll_conn.h |    9 +
 nimble/controller/include/controller/ble_ll_ctrl.h |   26 +-
 .../controller/include/controller/ble_ll_resolv.h  |    5 +-
 .../controller/include/controller/ble_ll_sched.h   |    2 +-
 nimble/controller/include/controller/ble_ll_sync.h |   12 +-
 nimble/controller/src/ble_ll.c                     |    6 +
 nimble/controller/src/ble_ll_adv.c                 |  346 ++++--
 nimble/controller/src/ble_ll_conn.c                |   47 +
 nimble/controller/src/ble_ll_conn_hci.c            |   98 ++
 nimble/controller/src/ble_ll_conn_priv.h           |   17 +
 nimble/controller/src/ble_ll_ctrl.c                |   40 +-
 nimble/controller/src/ble_ll_hci.c                 |   20 +
 nimble/controller/src/ble_ll_resolv.c              |   20 +-
 nimble/controller/src/ble_ll_scan.c                |    9 +-
 nimble/controller/src/ble_ll_sched.c               |    7 +-
 nimble/controller/src/ble_ll_supp_cmd.c            |   32 +-
 nimble/controller/src/ble_ll_sync.c                | 1166 +++++++++++++++-----
 nimble/controller/syscfg.yml                       |   15 +-
 nimble/host/include/host/ble_gap.h                 |  107 ++
 nimble/host/src/ble_gap.c                          |  303 +++++
 nimble/host/src/ble_gap_priv.h                     |    1 +
 nimble/host/src/ble_hs_conn_priv.h                 |    4 +
 nimble/host/src/ble_hs_hci_evt.c                   |   19 +
 nimble/host/src/ble_hs_startup.c                   |   10 +
 nimble/include/nimble/hci_common.h                 |   50 +
 nimble/syscfg.yml                                  |    9 +
 30 files changed, 2222 insertions(+), 423 deletions(-)


[mynewt-nimble] 02/08: nimble/ll: Add api for resolving peer RPA to any IRK on list

Posted by ja...@apache.org.
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 1e0b0948c3aa542adb925a663b0eec501bd0bf64
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Thu Nov 7 15:29:16 2019 +0100

    nimble/ll: Add api for resolving peer RPA to any IRK on list
    
    This is needed to properly report periodic sync transfers received
    since address in LL_SYNC_TRANSFER_IND is always RPA.
---
 nimble/controller/include/controller/ble_ll_resolv.h |  5 ++++-
 nimble/controller/src/ble_ll_resolv.c                | 20 +++++++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_resolv.h b/nimble/controller/include/controller/ble_ll_resolv.h
index 17228d6..f9dc397 100644
--- a/nimble/controller/include/controller/ble_ll_resolv.h
+++ b/nimble/controller/include/controller/ble_ll_resolv.h
@@ -98,7 +98,10 @@ int ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len);
 uint32_t ble_ll_resolv_get_rpa_tmo(void);
 
 /* Resolve a resolvable private address */
-int ble_ll_resolv_rpa(uint8_t *rpa, uint8_t *irk);
+int ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk);
+
+/* Try to resolve peer RPA and return index on RL if matched */
+int ble_ll_resolv_peer_rpa_any(const uint8_t *rpa);
 
 /* Initialize resolv*/
 void ble_ll_resolv_init(void);
diff --git a/nimble/controller/src/ble_ll_resolv.c b/nimble/controller/src/ble_ll_resolv.c
index abf3986..c35cc33 100644
--- a/nimble/controller/src/ble_ll_resolv.c
+++ b/nimble/controller/src/ble_ll_resolv.c
@@ -641,15 +641,15 @@ ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, int local)
  * @return int
  */
 int
-ble_ll_resolv_rpa(uint8_t *rpa, uint8_t *irk)
+ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk)
 {
     int rc;
-    uint32_t *irk32;
+    const uint32_t *irk32;
     uint32_t *key32;
     uint32_t *pt32;
     struct ble_encryption_block ecb;
 
-    irk32 = (uint32_t *)irk;
+    irk32 = (const uint32_t *)irk;
     key32 = (uint32_t *)&ecb.key[0];
 
     key32[0] = irk32[0];
@@ -678,6 +678,20 @@ ble_ll_resolv_rpa(uint8_t *rpa, uint8_t *irk)
     return rc;
 }
 
+int
+ble_ll_resolv_peer_rpa_any(const uint8_t *rpa)
+{
+    int i;
+
+    for (i = 0; i < g_ble_ll_resolv_data.rl_cnt_hw; i++) {
+        if (ble_ll_resolv_rpa(rpa, g_ble_ll_resolv_list[i].rl_peer_irk)) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
 /**
  * Returns whether or not address resolution is enabled.
  *


[mynewt-nimble] 05/08: nimble/host: Add support for sync transfer

Posted by ja...@apache.org.
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 465b5c808f316587cdc968e9544d35b1215ab0f5
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Mon Nov 4 12:57:46 2019 +0100

    nimble/host: Add support for sync transfer
    
    This allows to transmit and receive periodic sync transfer.
    New BLE_GAP_EVENT_PERIODIC_TRANSFER is generated when periodic
    sync transfer reception was attempted regardless of status.
    
    Since HCI spec is not requiring controller to disable transfer reception
    on first attemp, such behaviour is implemented in host. This is to
    mimic other GAP procedures as well as give application more control
    on controlling receptions.
---
 nimble/host/include/host/ble_gap.h | 107 +++++++++++++
 nimble/host/src/ble_gap.c          | 303 +++++++++++++++++++++++++++++++++++++
 nimble/host/src/ble_gap_priv.h     |   1 +
 nimble/host/src/ble_hs_conn_priv.h |   4 +
 nimble/host/src/ble_hs_hci_evt.c   |  19 +++
 nimble/host/src/ble_hs_startup.c   |  10 ++
 6 files changed, 444 insertions(+)

diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h
index 7523e23..6af7e9d 100644
--- a/nimble/host/include/host/ble_gap.h
+++ b/nimble/host/include/host/ble_gap.h
@@ -128,6 +128,7 @@ struct hci_conn_update;
 #define BLE_GAP_EVENT_PERIODIC_REPORT       21
 #define BLE_GAP_EVENT_PERIODIC_SYNC_LOST    22
 #define BLE_GAP_EVENT_SCAN_REQ_RCVD         23
+#define BLE_GAP_EVENT_PERIODIC_TRANSFER     24
 
 /*** Reason codes for the subscribe GAP event. */
 
@@ -925,6 +926,47 @@ struct ble_gap_event {
             ble_addr_t scan_addr;
         } scan_req_rcvd;
 #endif
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+        /**
+         * Represents a periodic advertising sync transfer received. Valid for
+         * the following event types:
+         *     o BLE_GAP_EVENT_PERIODIC_TRANSFER
+         */
+        struct {
+            /** BLE_ERR_SUCCESS on success or error code on failure. Sync handle
+             * is valid only for success.
+             */
+            uint8_t status;
+
+            /** Periodic sync handle */
+            uint16_t sync_handle;
+
+            /** Connection handle */
+            uint16_t conn_handle;
+
+            /** Service Data */
+            uint16_t service_data;
+
+            /** Advertising Set ID */
+            uint8_t sid;
+
+            /** Advertiser address */
+            ble_addr_t adv_addr;
+
+            /** Advertising PHY, can be one of following constants:
+             *  - BLE_HCI_LE_PHY_1M
+             *  - LE_HCI_LE_PHY_2M
+             *  - BLE_HCI_LE_PHY_CODED
+            */
+            uint8_t adv_phy;
+
+            /** Periodic advertising interval */
+            uint16_t per_adv_itvl;
+
+            /** Advertiser clock accuracy */
+            uint8_t adv_clk_accuracy;
+        } periodic_transfer;
+#endif
     };
 };
 
@@ -1297,6 +1339,9 @@ struct ble_gap_periodic_sync_params {
     /** Synchronization timeout for the periodic advertising train in 10ms units
      */
     uint16_t sync_timeout;
+
+    /** If reports should be initially disabled when sync is created */
+    unsigned int reports_disabled:1;
 };
 
 /**
@@ -1379,6 +1424,68 @@ int ble_gap_periodic_adv_sync_create_cancel(void);
  */
 int ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle);
 
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+/**
+ * Disable or enable periodic reports for specified sync.
+ *
+ * @param sync_handle        Handle identifying synchronization.
+ * @param enable             If reports should be enabled.
+ *
+ * @return                   0 on success; nonzero on failure.
+ */
+int ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable);
+
+/**
+ * Initialize sync transfer procedure for specified handles.
+ *
+ * This allows to transfer periodic sync to which host is synchronized.
+ *
+ * @param sync_handle        Handle identifying synchronization.
+ * @param conn_handle        Handle identifying connection.
+ * @param service_data       Sync transfer service data
+ *
+ * @return                   0 on success; nonzero on failure.
+ */
+int ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle,
+                                       uint16_t conn_handle,
+                                       uint16_t service_data);
+
+/**
+ * Initialize set info transfer procedure for specified handles.
+ *
+ * This allows to transfer periodic sync which is being advertised by host.
+ *
+ * @param instance           Advertising instance with periodic adv enabled.
+ * @param conn_handle        Handle identifying connection.
+ * @param service_data       Sync transfer service data
+ *
+ * @return                   0 on success; nonzero on failure.
+ */
+int ble_gap_periodic_adv_sync_set_info(uint8_t instance,
+                                       uint16_t conn_handle,
+                                       uint16_t service_data);
+
+/**
+ * Enables or disables sync transfer reception on specified connection.
+ * When BLE_GAP_EVENT_PERIODIC_TRANSFER is sent transfer reception is terminated
+ * on that connection.
+ *
+ * @param conn_handle        Handle identifying connection.
+ * @param params             Parameters for enabled sync transfer reception.
+ *                           Specify NULL to disable reception.
+ * @param cb                 The callback to associate with this synchronization
+ *                           procedure. BLE_GAP_EVENT_PERIODIC_REPORT events
+ *                           are reported only by this callback.
+ * @param cb_arg             The optional argument to pass to the callback
+ *                           function.
+ *
+ * @return                   0 on success; nonzero on failure.
+ */
+int ble_gap_periodic_adv_sync_receive(uint16_t conn_handle,
+                                      const struct ble_gap_periodic_sync_params *params,
+                                      ble_gap_event_fn *cb, void *cb_arg);
+#endif
+
 /**
  * Add peer device to periodic synchronization list.
  *
diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c
index 779b89c..d77d414 100644
--- a/nimble/host/src/ble_gap.c
+++ b/nimble/host/src/ble_gap.c
@@ -1499,6 +1499,110 @@ ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_
 }
 #endif
 
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+static int
+periodic_adv_transfer_disable(uint16_t conn_handle)
+{
+    struct ble_hci_le_periodic_adv_sync_transfer_params_cp cmd;
+    struct ble_hci_le_periodic_adv_sync_transfer_params_rp rsp;
+    uint16_t opcode;
+    int rc;
+
+    opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS);
+
+    cmd.conn_handle = htole16(conn_handle);
+    cmd.sync_cte_type = 0x00;
+    cmd.mode = 0x00;
+    cmd.skip = 0x0000;
+    cmd.sync_timeout = 0x000a;
+
+    rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
+    if (!rc) {
+        BLE_HS_DBG_ASSERT(le16toh(rsp.conn_handle) == conn_handle);
+    }
+
+    return rc;
+}
+
+void
+ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev)
+{
+    struct ble_hci_le_periodic_adv_term_sync_cp cmd_term;
+    struct ble_gap_event event;
+    struct ble_hs_conn *conn;
+    ble_gap_event_fn *cb;
+    uint16_t sync_handle;
+    uint16_t conn_handle;
+    uint16_t opcode;
+    void *cb_arg;
+
+    conn_handle = le16toh(ev->conn_handle);
+
+    ble_hs_lock();
+
+    /* Unfortunately spec sucks here as it doesn't explicitly stop
+     * transfer reception on first transfer... for now just disable it on
+     * every transfer event we get.
+     */
+    periodic_adv_transfer_disable(conn_handle);
+
+    conn = ble_hs_conn_find(le16toh(ev->conn_handle));
+    if (!conn || !conn->psync) {
+        /* terminate sync if we didn't expect it */
+        if (!ev->status) {
+            opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC);
+            cmd_term.sync_handle = ev->sync_handle;
+            ble_hs_hci_cmd_tx(opcode, &cmd_term, sizeof(cmd_term), NULL, 0);
+        }
+
+        ble_hs_unlock();
+        return;
+    }
+
+    cb = conn->psync->cb;
+    cb_arg = conn->psync->cb_arg;
+
+    memset(&event, 0, sizeof event);
+
+    event.type = BLE_GAP_EVENT_PERIODIC_TRANSFER;
+    event.periodic_transfer.status = ev->status;
+
+    /* only sync handle is not valid on error */
+    if (ev->status) {
+        sync_handle = 0;
+        ble_hs_periodic_sync_free(conn->psync);
+    } else {
+        sync_handle = le16toh(ev->sync_handle);
+
+        conn->psync->sync_handle = sync_handle;
+        conn->psync->adv_sid = ev->sid;
+        memcpy(conn->psync->advertiser_addr.val, ev->peer_addr, 6);
+        conn->psync->advertiser_addr.type = ev->peer_addr_type;
+        ble_hs_periodic_sync_insert(conn->psync);
+    }
+
+    conn->psync = NULL;
+
+    event.periodic_transfer.sync_handle = sync_handle;
+    event.periodic_transfer.conn_handle = conn_handle;
+    event.periodic_transfer.service_data = le16toh(ev->service_data);
+    event.periodic_transfer.sid = ev->sid;
+    memcpy(event.periodic_transfer.adv_addr.val, ev->peer_addr, 6);
+    event.periodic_transfer.adv_addr.type = ev->peer_addr_type;
+
+    event.periodic_transfer.adv_phy = ev->phy;
+    event.periodic_transfer.per_adv_itvl = le16toh(ev->interval);
+    event.periodic_transfer.adv_clk_accuracy = ev->aca;
+
+    ble_hs_unlock();
+
+    ble_gap_event_listener_call(&event);
+    if (cb) {
+        cb(&event, cb_arg);
+    }
+}
+#endif
+
 static int
 ble_gap_rd_rem_sup_feat_tx(uint16_t handle)
 {
@@ -3561,6 +3665,205 @@ ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle)
 
     return rc;
 }
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+int
+ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable)
+{
+    struct ble_hci_le_periodic_adv_receive_enable_cp cmd;
+    struct ble_hs_periodic_sync *psync;
+    uint16_t opcode;
+    int rc;
+
+    ble_hs_lock();
+
+    if (ble_gap_sync.op == BLE_GAP_OP_SYNC) {
+        ble_hs_unlock();
+        return BLE_HS_EBUSY;
+    }
+
+    psync = ble_hs_periodic_sync_find_by_handle(sync_handle);
+    if (!psync) {
+        ble_hs_unlock();
+        return BLE_HS_ENOTCONN;
+    }
+
+    opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE);
+
+    cmd.sync_handle = htole16(sync_handle);
+    cmd.enable = enable ? 0x01 : 0x00;
+
+    rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0);
+
+    ble_hs_unlock();
+
+    return rc;
+}
+
+int
+ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle, uint16_t conn_handle,
+                                   uint16_t service_data)
+{
+    struct ble_hci_le_periodic_adv_sync_transfer_cp cmd;
+    struct ble_hci_le_periodic_adv_sync_transfer_rp rsp;
+    struct ble_hs_periodic_sync *psync;
+    struct ble_hs_conn *conn;
+    uint16_t opcode;
+    int rc;
+
+    ble_hs_lock();
+
+    conn = ble_hs_conn_find(conn_handle);
+    if (!conn) {
+        ble_hs_unlock();
+        return BLE_HS_ENOTCONN;
+    }
+
+    psync = ble_hs_periodic_sync_find_by_handle(sync_handle);
+    if (!psync) {
+        ble_hs_unlock();
+        return BLE_HS_ENOTCONN;
+    }
+
+    opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER);
+
+    cmd.conn_handle = htole16(conn_handle);
+    cmd.sync_handle = htole16(sync_handle);
+    cmd.service_data = htole16(service_data);
+
+    rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
+    if (!rc) {
+        BLE_HS_DBG_ASSERT(le16toh(rsp.conn_handle) == conn_handle);
+    }
+
+    ble_hs_unlock();
+
+    return rc;
+}
+
+int
+ble_gap_periodic_adv_sync_set_info(uint8_t instance, uint16_t conn_handle,
+                                   uint16_t service_data)
+{
+    struct ble_hci_le_periodic_adv_set_info_transfer_cp cmd;
+    struct ble_hci_le_periodic_adv_set_info_transfer_rp rsp;
+    struct ble_hs_conn *conn;
+    uint16_t opcode;
+    int rc;
+
+    if (instance >= BLE_ADV_INSTANCES) {
+        return BLE_HS_EINVAL;
+    }
+
+    ble_hs_lock();
+    if (ble_gap_slave[instance].periodic_op != BLE_GAP_OP_S_PERIODIC_ADV) {
+        /* periodic adv not enabled */
+        ble_hs_unlock();
+        return BLE_HS_EINVAL;
+    }
+
+    conn = ble_hs_conn_find(conn_handle);
+    if (!conn) {
+        ble_hs_unlock();
+        return BLE_HS_ENOTCONN;
+    }
+
+    opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER);
+
+    cmd.conn_handle = htole16(conn_handle);
+    cmd.adv_handle = instance;
+    cmd.service_data = htole16(service_data);
+
+    rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
+    if (!rc) {
+        BLE_HS_DBG_ASSERT(le16toh(rsp.conn_handle) == conn_handle);
+    }
+
+    ble_hs_unlock();
+
+    return rc;
+}
+
+static int
+periodic_adv_transfer_enable(uint16_t conn_handle,
+                             const struct ble_gap_periodic_sync_params *params)
+{
+    struct ble_hci_le_periodic_adv_sync_transfer_params_cp cmd;
+    struct ble_hci_le_periodic_adv_sync_transfer_params_rp rsp;
+    uint16_t opcode;
+    int rc;
+
+    opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS);
+
+    cmd.conn_handle = htole16(conn_handle);
+    cmd.sync_cte_type = 0x00;
+    cmd.mode = params->reports_disabled ? 0x01 : 0x02;
+    cmd.skip = htole16(params->skip);
+    cmd.sync_timeout = htole16(params->sync_timeout);
+
+    rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp));
+    if (!rc) {
+        BLE_HS_DBG_ASSERT(le16toh(rsp.conn_handle) == conn_handle);
+    }
+
+    return rc;
+}
+
+int
+ble_gap_periodic_adv_sync_receive(uint16_t conn_handle,
+                                  const struct ble_gap_periodic_sync_params *params,
+                                  ble_gap_event_fn *cb, void *cb_arg)
+{
+    struct ble_hs_conn *conn;
+    int rc;
+
+    ble_hs_lock();
+
+    conn = ble_hs_conn_find(conn_handle);
+    if (!conn) {
+        ble_hs_unlock();
+        return BLE_HS_ENOTCONN;
+    }
+
+    if (params) {
+        if (conn->psync) {
+            ble_hs_unlock();
+            return BLE_HS_EALREADY;
+        }
+
+        conn->psync = ble_hs_periodic_sync_alloc();
+        if (!conn->psync) {
+            ble_hs_unlock();
+            return BLE_HS_ENOMEM;
+        }
+
+        rc = periodic_adv_transfer_enable(conn_handle, params);
+        if (rc) {
+            ble_hs_periodic_sync_free(conn->psync);
+            conn->psync = NULL;
+        } else {
+            conn->psync->cb = cb;
+            conn->psync->cb_arg = cb_arg;
+            ble_npl_event_init(&conn->psync->lost_ev, ble_gap_npl_sync_lost,
+                               conn->psync);
+        }
+    } else {
+        if (!conn->psync) {
+            ble_hs_unlock();
+            return BLE_HS_EALREADY;
+        }
+
+        rc = periodic_adv_transfer_disable(conn_handle);
+        if (!rc) {
+            ble_hs_periodic_sync_free(conn->psync);
+            conn->psync = NULL;
+        }
+    }
+
+    ble_hs_unlock();
+
+    return rc;
+}
+#endif
 
 int
 ble_gap_add_dev_to_periodic_adv_list(const ble_addr_t *peer_addr,
diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h
index 06ab765..ce44319 100644
--- a/nimble/host/src/ble_gap_priv.h
+++ b/nimble/host/src/ble_gap_priv.h
@@ -86,6 +86,7 @@ void ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_term
 void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev);
 void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_rpt *ev);
 void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev);
+void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev);
 #endif
 void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev);
 #endif
diff --git a/nimble/host/src/ble_hs_conn_priv.h b/nimble/host/src/ble_hs_conn_priv.h
index fa9f7a8..7578145 100644
--- a/nimble/host/src/ble_hs_conn_priv.h
+++ b/nimble/host/src/ble_hs_conn_priv.h
@@ -98,6 +98,10 @@ struct ble_hs_conn {
 
     ble_gap_event_fn *bhc_cb;
     void *bhc_cb_arg;
+
+#if MYNEWT_VAL(BLE_PERIODIC_ADV)
+    struct ble_hs_periodic_sync *psync;
+#endif
 };
 
 struct ble_hs_conn_addrs {
diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c
index 1ebd5a6..32ed401 100644
--- a/nimble/host/src/ble_hs_hci_evt.c
+++ b/nimble/host/src/ble_hs_hci_evt.c
@@ -57,6 +57,8 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_rpt;
 static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_lost;
 static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_scan_req_rcvd;
 static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_enh_conn_complete;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_transfer;
+
 /* Statistics */
 struct host_hci_stats
 {
@@ -103,6 +105,7 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = {
     [BLE_HCI_LE_SUBEV_SCAN_TIMEOUT] = ble_hs_hci_evt_le_scan_timeout,
     [BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED] = ble_hs_hci_evt_le_adv_set_terminated,
     [BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD] = ble_hs_hci_evt_le_scan_req_rcvd,
+    [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER] = ble_hs_hci_evt_le_periodic_adv_sync_transfer,
 };
 
 #define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \
@@ -623,6 +626,22 @@ ble_hs_hci_evt_le_periodic_adv_sync_lost(uint8_t subevent, const void *data,
     return 0;
 }
 
+static int
+ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data,
+                                             unsigned int len)
+{
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+    const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev = data;
+
+    if (len != sizeof(*ev)) {
+        return BLE_HS_EBADDATA;
+    }
+
+    ble_gap_rx_periodic_adv_sync_transfer(ev);
+
+#endif
+    return 0;
+}
 
 static int
 ble_hs_hci_evt_le_scan_timeout(uint8_t subevent, const void *data,
diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c
index 2ef8900..83026ac 100644
--- a/nimble/host/src/ble_hs_startup.c
+++ b/nimble/host/src/ble_hs_startup.c
@@ -228,6 +228,16 @@ ble_hs_startup_le_set_evmask_tx(void)
         mask |= 0x00000000000ff800;
     }
 
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+    if (version >= BLE_HCI_VER_BCS_5_1) {
+        /**
+         * Enable the following LE events:
+         * 0x0000000000800000 LE Periodic Advertising Sync Transfer Received event
+         */
+        mask |= 0x0000000000800000;
+    }
+#endif
+
     cmd.event_mask = htole64(mask);
 
     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,


[mynewt-nimble] 08/08: nimble/ll: Fix missing rfclk restart when not ending sync event

Posted by ja...@apache.org.
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 6e84712247df498e8544501856940ffc5815838f
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Tue Nov 26 11:24:02 2019 +0100

    nimble/ll: Fix missing rfclk restart when not ending sync event
---
 nimble/controller/src/ble_ll_sync.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c
index 436a2d9..f73d90e 100644
--- a/nimble/controller/src/ble_ll_sync.c
+++ b/nimble/controller/src/ble_ll_sync.c
@@ -999,6 +999,10 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
      */
     if (!sm->flags) {
         ble_ll_scan_chk_resume();
+
+#ifdef BLE_XCVR_RFCLK
+        ble_ll_sched_rfclk_chk_restart();
+#endif
         return;
     }
 
@@ -1044,6 +1048,10 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
         /* if chain was scheduled we don't end event yet */
         /* TODO should we check resume only if offset is high? */
         ble_ll_scan_chk_resume();
+
+#ifdef BLE_XCVR_RFCLK
+        ble_ll_sched_rfclk_chk_restart();
+#endif
         return;
     }
 


[mynewt-nimble] 03/08: nimble/ll: Add support for sync transfer reception

Posted by ja...@apache.org.
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 8a4431bca9693dfc7b97c64dddb5c7363095e584
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Tue Oct 22 14:19:32 2019 +0200

    nimble/ll: Add support for sync transfer reception
    
    Add support for required HCI commands/events and LL PDUs.
    Can be enabled only if version 5.1 or greater is enabled.
    Enabling sync transfer also enables DLE as LL_PERIODIC_SYNC_IND is
    35 bytes long.
---
 nimble/controller/include/controller/ble_ll.h      |  11 +
 nimble/controller/include/controller/ble_ll_adv.h  |   3 +
 nimble/controller/include/controller/ble_ll_conn.h |   9 +
 nimble/controller/include/controller/ble_ll_ctrl.h |  26 +-
 .../controller/include/controller/ble_ll_sched.h   |   2 +-
 nimble/controller/include/controller/ble_ll_sync.h |   9 +-
 nimble/controller/src/ble_ll.c                     |   4 +
 nimble/controller/src/ble_ll_conn.c                |  47 +++
 nimble/controller/src/ble_ll_conn_hci.c            |  98 +++++
 nimble/controller/src/ble_ll_conn_priv.h           |  17 +
 nimble/controller/src/ble_ll_ctrl.c                |  40 +-
 nimble/controller/src/ble_ll_hci.c                 |  12 +
 nimble/controller/src/ble_ll_scan.c                |   9 +-
 nimble/controller/src/ble_ll_sched.c               |   7 +-
 nimble/controller/src/ble_ll_supp_cmd.c            |  16 +-
 nimble/controller/src/ble_ll_sync.c                | 436 +++++++++++++++++++--
 nimble/controller/syscfg.yml                       |  10 +-
 nimble/include/nimble/hci_common.h                 |  50 +++
 nimble/syscfg.yml                                  |   9 +
 19 files changed, 757 insertions(+), 58 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h
index b0c44cc..4514815 100644
--- a/nimble/controller/include/controller/ble_ll.h
+++ b/nimble/controller/include/controller/ble_ll.h
@@ -246,6 +246,17 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats;
 #define BLE_LL_FEAT_CSA2             (0x00004000)
 #define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x00008000)
 #define BLE_LL_FEAT_MIN_USED_CHAN    (0x00010000)
+#define BLE_LL_FEAT_CTE_REQ          (0x00020000)
+#define BLE_LL_FEAT_CTE_RSP          (0x00040000)
+#define BLE_LL_FEAT_CTE_TX           (0x00080000)
+#define BLE_LL_FEAT_CTE_RX           (0x00100000)
+#define BLE_LL_FEAT_CTE_AOD          (0x00200000)
+#define BLE_LL_FEAT_CTE_AOA          (0x00400000)
+#define BLE_LL_FEAT_CTE_RECV         (0x00800000)
+#define BLE_LL_FEAT_SYNC_SEND        (0x01000000)
+#define BLE_LL_FEAT_SYNC_RECV        (0x02000000)
+#define BLE_LL_FEAT_SCA_UPDATE       (0x04000000)
+#define BLE_LL_FEAT_REM_PKEY         (0x08000000)
 
 /* This is initial mask, so if feature exchange will not happen,
  * but host will want to use this procedure, we will try. If not
diff --git a/nimble/controller/include/controller/ble_ll_adv.h b/nimble/controller/include/controller/ble_ll_adv.h
index ef64bc0..4afaadd 100644
--- a/nimble/controller/include/controller/ble_ll_adv.h
+++ b/nimble/controller/include/controller/ble_ll_adv.h
@@ -196,6 +196,9 @@ int ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len);
 int ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len);
 int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len);
 
+int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
+                                          uint8_t *rspbuf, uint8_t *rsplen);
+
 /* Called to notify adv code about RPA rotation */
 void ble_ll_adv_rpa_timeout(void);
 
diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h
index aa967cd..ebe69c8 100644
--- a/nimble/controller/include/controller/ble_ll_conn.h
+++ b/nimble/controller/include/controller/ble_ll_conn.h
@@ -372,6 +372,11 @@ struct ble_ll_conn_sm
     struct hci_ext_create_conn initial_params;
 #endif
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    uint8_t  sync_transfer_mode;
+    uint16_t sync_transfer_skip;
+    uint32_t sync_transfer_sync_timeout;
+#endif
 };
 
 /* Flags */
@@ -405,6 +410,10 @@ struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
 /* required for unit testing */
 uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency);
 
+/* used to get anchor point for connection event specified */
+void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
+                            uint32_t *anchor, uint8_t *anchor_usecs);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h
index 94a730a..76456b1 100644
--- a/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -80,14 +80,23 @@ extern "C" {
 #define BLE_LL_CTRL_PHY_RSP             (23)
 #define BLE_LL_CTRL_PHY_UPDATE_IND      (24)
 #define BLE_LL_CTRL_MIN_USED_CHAN_IND   (25)
+#define BLE_LL_CTRL_CTE_REQ             (26)
+#define BLE_LL_CTRL_CTE_RSP             (27)
+#define BLE_LL_CTRL_PERIODIC_SYNC_IND   (28)
+#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ  (29)
+#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP  (30)
 
 /* Maximum opcode value */
-#define BLE_LL_CTRL_OPCODES             (BLE_LL_CTRL_MIN_USED_CHAN_IND + 1)
+#define BLE_LL_CTRL_OPCODES             (BLE_LL_CTRL_CLOCK_ACCURACY_RSP + 1)
 
 extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
 
 /* Maximum LL control PDU size */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+#define BLE_LL_CTRL_MAX_PDU_LEN         (35)
+#else
 #define BLE_LL_CTRL_MAX_PDU_LEN         (27)
+#endif
 
 /* LL control connection update request */
 struct ble_ll_conn_upd_req
@@ -239,6 +248,19 @@ struct ble_ll_len_req
 /* Min used channels */
 #define BLE_LL_CTRL_MIN_USED_CHAN_LEN   (2)
 
+/* CTE REQ */
+#define BLE_LL_CTRL_CTE_REQ_LEN         (1)
+
+/* CTE RSP (contains no data) */
+#define BLE_LL_CTRL_CTE_RSP_LEN     (0)
+
+/* Periodic Sync Transfer IND */
+#define BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN   (34)
+
+/* Clock accuracy request/response */
+#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN  (1)
+#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN  (1)
+
 /* API */
 struct ble_ll_conn_sm;
 void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
@@ -281,6 +303,8 @@ void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm);
 void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm);
 void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line);
 
+uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/nimble/controller/include/controller/ble_ll_sched.h b/nimble/controller/include/controller/ble_ll_sched.h
index cbc66f4..9c638e5 100644
--- a/nimble/controller/include/controller/ble_ll_sched.h
+++ b/nimble/controller/include/controller/ble_ll_sched.h
@@ -172,7 +172,7 @@ int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
                                  uint8_t anchor_point_usecs,
                                  uint32_t window_widening, int8_t phy_mode);
 int ble_ll_sched_sync(struct ble_ll_sched_item *sch,
-                      struct ble_mbuf_hdr *ble_hdr, uint32_t offset,
+                      uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset,
                       int8_t phy_mode);
 
 /* Reschedule an advertising event */
diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h
index c217437..fea5b14 100644
--- a/nimble/controller/include/controller/ble_ll_sync.h
+++ b/nimble/controller/include/controller/ble_ll_sync.h
@@ -24,6 +24,7 @@
 
 #include "nimble/ble.h"
 #include "controller/ble_ll_hci.h"
+#include "controller/ble_ll_conn.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -40,8 +41,14 @@ int ble_ll_sync_list_clear(void);
 int ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen);
 int ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len);
 
+void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
+                              const uint8_t *sync_ind, bool reports_disabled,
+                              uint16_t max_skip, uint32_t sync_timeout);
+void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm);
+
 void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type,
-                            uint8_t sid, struct ble_mbuf_hdr *rxhdr,
+                            int rpa_index, uint8_t sid,
+                            struct ble_mbuf_hdr *rxhdr,
                             const uint8_t *syncinfo);
 
 int ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr);
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index c990ad0..f4f8ddb 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -1654,6 +1654,10 @@ ble_ll_init(void)
     ble_ll_sync_init();
 #endif
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    features |= BLE_LL_FEAT_SYNC_RECV;
+#endif
+
     /* Initialize random number generation */
     ble_ll_rand_init();
 
diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c
index 247cb65..297a13f 100644
--- a/nimble/controller/src/ble_ll_conn.c
+++ b/nimble/controller/src/ble_ll_conn.c
@@ -137,6 +137,11 @@ uint8_t *g_ble_ll_conn_comp_ev;
 /* Global LL connection parameters */
 struct ble_ll_conn_global_params g_ble_ll_conn_params;
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+/* Global default sync transfer params */
+struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params;
+#endif
+
 /* Pointer to connection state machine we are trying to create */
 struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
 
@@ -1681,6 +1686,12 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
     connsm->rpa_index = -1;
     connsm->inita_identity_used = 0;
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    connsm->sync_transfer_sync_timeout = g_ble_ll_conn_sync_transfer_params.sync_timeout_us;
+    connsm->sync_transfer_mode = g_ble_ll_conn_sync_transfer_params.mode;
+    connsm->sync_transfer_skip = g_ble_ll_conn_sync_transfer_params.max_skip;
+#endif
+
     /* XXX: TODO set these based on PHY that started connection */
 #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
     connsm->phy_data.cur_tx_phy = BLE_PHY_1M;
@@ -1925,6 +1936,35 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
                        connsm->event_cntr, (uint32_t)ble_err);
 }
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+void
+ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
+                       uint32_t *anchor, uint8_t *anchor_usecs)
+{
+    uint32_t ticks;
+    uint32_t itvl;
+
+    itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
+
+    if ((int16_t)(conn_event - connsm->event_cntr) < 0) {
+        itvl *= connsm->event_cntr - conn_event;
+        ticks = os_cputime_usecs_to_ticks(itvl);
+        *anchor = connsm->anchor_point - ticks;
+    } else {
+        itvl *= conn_event - connsm->event_cntr;
+        ticks = os_cputime_usecs_to_ticks(itvl);
+        *anchor = connsm->anchor_point + ticks;
+    }
+
+    *anchor_usecs = connsm->anchor_point_usecs;
+    *anchor_usecs += (itvl - os_cputime_ticks_to_usecs(ticks));
+    if (*anchor_usecs >= 31) {
+        (*anchor)++;
+        *anchor_usecs -= 31;
+    }
+}
+#endif
+
 /**
  * Called to move to the next connection event.
  *
@@ -4171,6 +4211,13 @@ ble_ll_conn_module_reset(void)
 
     /* Reset statistics */
     STATS_RESET(ble_ll_conn_stats);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    /* reset default sync transfer params */
+    g_ble_ll_conn_sync_transfer_params.max_skip = 0;
+    g_ble_ll_conn_sync_transfer_params.mode = 0;
+    g_ble_ll_conn_sync_transfer_params.sync_timeout_us = 0;
+#endif
 }
 
 /* Initialize the connection module */
diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c
index cdc7946..2ee81cf 100644
--- a/nimble/controller/src/ble_ll_conn_hci.c
+++ b/nimble/controller/src/ble_ll_conn_hci.c
@@ -1783,3 +1783,101 @@ phy_cmd_param_err:
     return rc;
 }
 #endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+int
+ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
+                                uint8_t *rspbuf, uint8_t *rsplen)
+{
+    const struct ble_hci_le_periodic_adv_sync_transfer_params_cp *cmd = (const void *)cmdbuf;
+    struct ble_hci_le_periodic_adv_sync_transfer_params_rp *rsp = (void *) rspbuf;
+    struct ble_ll_conn_sm *connsm;
+    uint16_t sync_timeout;
+    uint16_t skip;
+    int rc;
+
+    if (len != sizeof(*cmd)) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    if (cmd->mode > 0x02) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    skip = le16toh(cmd->skip);
+    if (skip > 0x01f3) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    sync_timeout = le16toh(cmd->sync_timeout);
+    if ((sync_timeout < 0x000a) || (sync_timeout > 0x4000)) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    /* we don't support any CTE yet */
+    if (cmd->sync_cte_type) {
+        rc = BLE_ERR_UNSUPPORTED;
+        goto done;
+    }
+
+    connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle));
+    if (!connsm) {
+        rc = BLE_ERR_UNK_CONN_ID;
+        goto done;
+    }
+
+    /* timeout in 10ms units */
+    connsm->sync_transfer_sync_timeout = sync_timeout * 10000;
+    connsm->sync_transfer_mode = cmd->mode;
+    connsm->sync_transfer_skip = skip;
+
+    rc = BLE_ERR_SUCCESS;
+
+done:
+    rsp->conn_handle = cmd->conn_handle;
+    *rsplen = sizeof(*rsp);
+    return rc;
+}
+
+int
+ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len)
+{
+    const struct ble_hci_le_set_default_periodic_sync_transfer_params_cp *cmd = (const void *)cmdbuf;
+    uint16_t sync_timeout;
+    uint16_t skip;
+
+    if (len != sizeof(*cmd)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    if (cmd->mode > 0x02) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    skip = le16toh(cmd->skip);
+    if (skip > 0x01f3) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    sync_timeout = le16toh(cmd->sync_timeout);
+    if ((sync_timeout < 0x000a) || (sync_timeout > 0x4000)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* we don't support any CTE yet */
+    if (cmd->sync_cte_type) {
+        return BLE_ERR_UNSUPPORTED;
+    }
+
+    /* timeout in 10ms units */
+    g_ble_ll_conn_sync_transfer_params.sync_timeout_us = sync_timeout * 10000;
+    g_ble_ll_conn_sync_transfer_params.mode = cmd->mode;
+    g_ble_ll_conn_sync_transfer_params.max_skip = skip;
+
+    return BLE_ERR_SUCCESS;
+}
+#endif
diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h
index c3e94ae..86c7b64 100644
--- a/nimble/controller/src/ble_ll_conn_priv.h
+++ b/nimble/controller/src/ble_ll_conn_priv.h
@@ -77,6 +77,16 @@ struct ble_ll_conn_global_params
 };
 extern struct ble_ll_conn_global_params g_ble_ll_conn_params;
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+struct ble_ll_conn_sync_transfer_params
+{
+    uint32_t sync_timeout_us;
+    uint16_t max_skip;
+    uint8_t  mode;
+};
+extern struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params;
+#endif
+
 /* Some data structures used by other LL routines */
 SLIST_HEAD(ble_ll_conn_active_list, ble_ll_conn_sm);
 STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm);
@@ -203,6 +213,13 @@ int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm);
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
 int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen);
 #endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
+                                    uint8_t *rspbuf, uint8_t *rsplen);
+int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c
index a8b873e..428f7d8 100644
--- a/nimble/controller/src/ble_ll_ctrl.c
+++ b/nimble/controller/src/ble_ll_ctrl.c
@@ -28,6 +28,7 @@
 #include "controller/ble_ll_ctrl.h"
 #include "controller/ble_ll_trace.h"
 #include "controller/ble_hw.h"
+#include "controller/ble_ll_sync.h"
 #include "ble_ll_conn_priv.h"
 
 /* To use spec sample data for testing */
@@ -105,7 +106,12 @@ const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
     BLE_LL_CTRL_PHY_REQ_LEN,
     BLE_LL_CTRL_PHY_RSP_LEN,
     BLE_LL_CTRL_PHY_UPD_IND_LEN,
-    BLE_LL_CTRL_MIN_USED_CHAN_LEN
+    BLE_LL_CTRL_MIN_USED_CHAN_LEN,
+    BLE_LL_CTRL_CTE_REQ_LEN,
+    BLE_LL_CTRL_CTE_RSP_LEN,
+    BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN,
+    BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN,
+    BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN,
 };
 
 /**
@@ -602,7 +608,7 @@ ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm)
  * BLE_HCI_LE_PHY_2M                    (2)
  * BLE_HCI_LE_PHY_CODED                 (3)
  */
-static uint8_t
+uint8_t
 ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask)
 {
     uint8_t phy;
@@ -989,6 +995,28 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
 }
 #endif
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+/**
+ * Called when a BLE_LL_CTRL_PERIODIC_SYNC_IND PDU is received
+ *
+ * @param connsm
+ * @param dptr
+ *
+ * @return uint8_t
+ */
+static uint8_t
+ble_ll_ctrl_rx_periodic_sync_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
+{
+    if (connsm->sync_transfer_mode) {
+        ble_ll_sync_periodic_ind(connsm, dptr, connsm->sync_transfer_mode == 1,
+                                 connsm->sync_transfer_skip,
+                                 connsm->sync_transfer_sync_timeout);
+    }
+
+    return BLE_ERR_MAX;
+}
+#endif
+
 /**
  * Create a link layer length request or length response PDU.
  *
@@ -2348,6 +2376,9 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
     case BLE_LL_CTRL_MIN_USED_CHAN_IND:
         feature = BLE_LL_FEAT_MIN_USED_CHAN;
         break;
+    case BLE_LL_CTRL_PERIODIC_SYNC_IND:
+        feature = BLE_LL_FEAT_SYNC_RECV;
+        break;
     default:
         feature = 0;
         break;
@@ -2489,6 +2520,11 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
         rsp_opcode = ble_ll_ctrl_rx_phy_update_ind(connsm, dptr);
         break;
 #endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_LL_CTRL_PERIODIC_SYNC_IND:
+        rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr);
+        break;
+#endif
     default:
         /* Nothing to do here */
         break;
diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c
index 5c3bfd8..05ee5c3 100644
--- a/nimble/controller/src/ble_ll_hci.c
+++ b/nimble/controller/src/ble_ll_hci.c
@@ -711,6 +711,10 @@ ble_ll_is_valid_adv_mode(uint8_t ocf)
 #if MYNEWT_VAL(BLE_VERSION) >= 51
     case BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE:
 #endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS:
+    case BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS:
+#endif
         if (hci_adv_mode == ADV_MODE_LEGACY) {
             return false;
         }
@@ -1124,6 +1128,14 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
         rc = ble_ll_resolve_set_priv_mode(cmdbuf, len);
         break;
 #endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS:
+        rc = ble_ll_set_sync_transfer_params(cmdbuf, len, rspbuf, rsplen);
+        break;
+    case BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS:
+        rc = ble_ll_set_default_sync_transfer_params(cmdbuf, len);
+        break;
+#endif
     default:
         rc = BLE_ERR_UNKNOWN_HCI_CMD;
         break;
diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c
index 7c5d53b..4baa70b 100644
--- a/nimble/controller/src/ble_ll_scan.c
+++ b/nimble/controller/src/ble_ll_scan.c
@@ -2842,7 +2842,7 @@ done:
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
 static void
 check_periodic_sync(const struct os_mbuf *om, struct ble_mbuf_hdr *rxhdr,
-                          uint8_t *adva, uint8_t adva_type)
+                          uint8_t *adva, uint8_t adva_type, int rpa_index)
 {
     uint8_t pdu_len;
     uint8_t ext_hdr_len;
@@ -2889,7 +2889,8 @@ check_periodic_sync(const struct os_mbuf *om, struct ble_mbuf_hdr *rxhdr,
         }
 
         if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) {
-            ble_ll_sync_info_event(adva, adva_type, sid, rxhdr, ext_hdr + i);
+            ble_ll_sync_info_event(adva, adva_type, rpa_index, sid, rxhdr,
+                                   ext_hdr + i);
         }
     }
 }
@@ -3165,8 +3166,8 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hd
      * policy if PDU and adv type match and advertiser address is present
      */
     if ((ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) &&
-            (ext_adv_mode == BLE_LL_EXT_ADV_MODE_NON_CONN) && ident_addr) {
-        check_periodic_sync(om, hdr, ident_addr, ident_addr_type);
+            (ext_adv_mode == BLE_LL_EXT_ADV_MODE_NON_CONN) && adv_addr) {
+        check_periodic_sync(om, hdr, adv_addr, txadd, index);
     }
 #endif
 
diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c
index 17e27ae..3ce22e9 100644
--- a/nimble/controller/src/ble_ll_sched.c
+++ b/nimble/controller/src/ble_ll_sched.c
@@ -963,7 +963,8 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
 }
 
 int
-ble_ll_sched_sync(struct ble_ll_sched_item *sch, struct ble_mbuf_hdr *ble_hdr,
+ble_ll_sched_sync(struct ble_ll_sched_item *sch,
+                  uint32_t beg_cputime, uint32_t rem_usecs,
                   uint32_t offset, int8_t phy_mode)
 {
     struct ble_ll_sched_item *entry;
@@ -979,8 +980,8 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, struct ble_mbuf_hdr *ble_hdr,
     off_ticks = os_cputime_usecs_to_ticks(offset);
     off_rem_usecs = offset - os_cputime_ticks_to_usecs(off_ticks);
 
-    start_time = ble_hdr->beg_cputime + off_ticks;
-    start_time_rem_usecs = ble_hdr->rem_usecs + off_rem_usecs;
+    start_time = beg_cputime + off_ticks;
+    start_time_rem_usecs = rem_usecs + off_rem_usecs;
     if (start_time_rem_usecs >= 31) {
         start_time++;
         start_time_rem_usecs -= 31;
diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c
index cb93dbe..c3c5950 100644
--- a/nimble/controller/src/ble_ll_supp_cmd.c
+++ b/nimble/controller/src/ble_ll_supp_cmd.c
@@ -386,6 +386,20 @@
     BLE_SUPP_CMD_LE_PADV_RECV_ENABLE        \
 )
 
+/* Octet 41 */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (1 << 0)
+#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (1 << 1)
+#else
+#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0)
+#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1)
+#endif
+#define BLE_LL_SUPP_CMD_OCTET_41                        \
+(                                                       \
+    BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS |         \
+    BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS   \
+)
+
 /* Defines the array of supported commands */
 const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
 {
@@ -430,5 +444,5 @@ const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
     BLE_LL_SUPP_CMD_OCTET_38,
     BLE_LL_SUPP_CMD_OCTET_39,
     BLE_LL_SUPP_CMD_OCTET_40,           /* Octet 40 */
-    0,
+    BLE_LL_SUPP_CMD_OCTET_41,
 };
diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c
index e5b4d01..41daf13 100644
--- a/nimble/controller/src/ble_ll_sync.c
+++ b/nimble/controller/src/ble_ll_sync.c
@@ -30,11 +30,14 @@
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_whitelist.h"
 #include "controller/ble_ll_scan.h"
+#include "controller/ble_ll_resolv.h"
 
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
 #include "nimble/ble_hci_trans.h"
 
+#include "ble_ll_conn_priv.h"
+
 #include "stats/stats.h"
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
@@ -54,6 +57,7 @@
 #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_SM_FLAG_ADDR_RESOLVED   0x80
 
 #define BLE_LL_SYNC_CHMAP_LEN               5
 #define BLE_LL_SYNC_ITVL_USECS              1250
@@ -98,6 +102,13 @@ struct ble_ll_sync_sm {
     struct ble_npl_event sync_ev_end;
 
     uint8_t *next_report;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    struct ble_ll_conn_sm *transfer_conn;
+    uint8_t *transfer_received_ev;
+    uint16_t transfer_id;
+    uint8_t adv_addr_rpa[6];
+#endif
 };
 
 static struct ble_ll_sync_sm g_ble_ll_sync_sm[BLE_LL_SYNC_CNT];
@@ -224,6 +235,84 @@ ble_ll_sync_phy_mode_to_hci(int8_t phy_mode)
 #endif
 }
 
+static struct ble_ll_sync_sm *
+ble_ll_sync_find(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
+{
+    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) {
+            continue;
+        }
+        if ((sm->adv_sid == sid) && (sm->adv_addr_type == addr_type) &&
+                !memcmp(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
+            return sm;
+        }
+    }
+
+    return NULL;
+}
+
+static uint16_t
+get_max_skip(uint32_t interval_us, uint32_t timeout_us)
+{
+    BLE_LL_ASSERT(interval_us);
+    BLE_LL_ASSERT(timeout_us);
+
+    if (timeout_us <= interval_us) {
+        return 0;
+    }
+
+    return (timeout_us / interval_us) - 1;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+static void
+ble_ll_sync_transfer_received(struct ble_ll_sync_sm *sm, uint8_t status)
+{
+    struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev;
+    struct ble_hci_ev *hci_ev;
+
+    BLE_LL_ASSERT(sm->transfer_received_ev);
+
+    if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER)) {
+        hci_ev = (void *) sm->transfer_received_ev;
+
+        hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
+        hci_ev->length = sizeof(*ev);
+
+        ev = (void *) hci_ev->data;
+        ev->subev_code = BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER;
+
+        ev->status = status;
+        ev->conn_handle = htole16(sm->transfer_conn->conn_handle);
+        ev->service_data = htole16(sm->transfer_id);
+
+        /* this is ignored by host on error */
+        ev->sync_handle = htole16(ble_ll_sync_get_handle(sm));
+        ev->sid = sm->adv_sid;
+        ev->peer_addr_type = sm->adv_addr_type;
+        if (sm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) {
+            ev->peer_addr_type += 2;
+        }
+        memcpy(ev->peer_addr, sm->adv_addr, BLE_DEV_ADDR_LEN);
+        ev->phy = ble_ll_sync_phy_mode_to_hci(sm->phy_mode);
+        ev->interval = htole16(sm->itvl);
+        ev->aca = sm->sca;
+
+        ble_ll_hci_event_send(hci_ev);
+    } else {
+        ble_hci_trans_buf_free(sm->transfer_received_ev);
+    }
+
+    sm->transfer_received_ev = NULL;
+    sm->transfer_conn = NULL;
+}
+#endif
+
 static void
 ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
 {
@@ -244,6 +333,9 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm)
         ev->sync_handle = htole16(ble_ll_sync_get_handle(sm));
         ev->sid = sm->adv_sid;
         ev->peer_addr_type = sm->adv_addr_type;
+        if (sm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) {
+            ev->peer_addr_type += 2;
+        }
         memcpy(ev->peer_addr, sm->adv_addr, BLE_DEV_ADDR_LEN);
         ev->phy = ble_ll_sync_phy_mode_to_hci(sm->phy_mode);
         ev->interval = htole16(sm->itvl);
@@ -306,27 +398,6 @@ ble_ll_sync_lost_event(struct ble_ll_sync_sm *sm)
     }
 }
 
-static struct ble_ll_sync_sm *
-ble_ll_sync_find(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
-{
-    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) {
-            continue;
-        }
-        if ((sm->adv_sid == sid) && (sm->adv_addr_type == addr_type) &&
-                !memcmp(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
-            return sm;
-        }
-    }
-
-    return NULL;
-}
-
 static void
 ble_ll_sync_current_sm_over(void)
 {
@@ -866,7 +937,8 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr,
     sm->sch.cb_arg = sm;
     sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC;
 
-    return ble_ll_sched_sync(&sm->sch, hdr, offset, sm->phy_mode);
+    return ble_ll_sched_sync(&sm->sch, hdr->beg_cputime, hdr->rem_usecs,
+                             offset, sm->phy_mode);
 }
 
 static void
@@ -875,11 +947,20 @@ ble_ll_sync_established(struct ble_ll_sync_sm *sm)
     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;
 
     sm->sync_pending_cnt = 0;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    if (sm->transfer_conn) {
+        ble_ll_sync_transfer_received(sm, BLE_ERR_SUCCESS);
+        return;
+    }
+#endif
+
+    ble_ll_sync_est_event_success(sm);
 }
 
 static void
@@ -892,9 +973,16 @@ ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm)
         return;
     }
 
-    ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
-
     sm->flags &= ~BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    if (sm->transfer_conn) {
+        ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT);
+        return;
+    }
+#endif
+
+    ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
 }
 
 void
@@ -958,7 +1046,7 @@ end_event:
 }
 
 static int
-ble_ll_sync_next_event(struct ble_ll_sync_sm *sm)
+ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
 {
     uint32_t cur_ww;
     uint32_t max_ww;
@@ -1003,6 +1091,8 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm)
                                                sm->last_anchor_point,
                                                sm->sca);
 
+    cur_ww += cur_ww_adjust;
+
     max_ww = (sm->itvl * (BLE_LL_SYNC_ITVL_USECS / 2)) - BLE_LL_IFS;
     if (cur_ww >= max_ww) {
         return -1;
@@ -1088,7 +1178,7 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
     sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC;
 
     do {
-        if (ble_ll_sync_next_event(sm) < 0) {
+        if (ble_ll_sync_next_event(sm, 0) < 0) {
             if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
                 /* don't allow any retry if this failed */
                 sm->sync_pending_cnt = 1;
@@ -1106,24 +1196,15 @@ ble_ll_sync_event_end(struct ble_npl_event *ev)
                                           sm->window_widening, sm->phy_mode));
 }
 
-static uint16_t
-get_max_skip(uint32_t interval_us, uint32_t timeout_us)
-{
-    BLE_LL_ASSERT(interval_us);
-    BLE_LL_ASSERT(timeout_us);
-
-    if (timeout_us <= interval_us) {
-        return 0;
-    }
-
-    return (timeout_us / interval_us) - 1;
-}
-
 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)
+ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index,
+                       uint8_t sid, struct ble_mbuf_hdr *rxhdr,
+                       const uint8_t *syncinfo)
 {
     struct ble_ll_sync_sm *sm = NULL;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    const uint8_t *rpa;
+#endif
     uint16_t max_skip;
     uint32_t offset;
     uint32_t usecs;
@@ -1148,6 +1229,15 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
         return;
     }
 
+    /* check if resolved */
+    if (rpa_index >= 0) {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+        rpa = addr;
+#endif
+        addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr;
+        addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type;
+    }
+
     /* 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) {
@@ -1180,6 +1270,13 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
         return;
     }
 
+    if (rpa_index >= 0) {
+        sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+        memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN);
+#endif
+    }
+
     /* 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;
@@ -1252,7 +1349,8 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, uint8_t sid,
     sm->sch.cb_arg = sm;
     sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC;
 
-    if (ble_ll_sched_sync(&sm->sch, rxhdr, offset, sm->phy_mode)) {
+    if (ble_ll_sched_sync(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs,
+                          offset, sm->phy_mode)) {
         return;
     }
 
@@ -1629,6 +1727,258 @@ ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len)
 }
 #endif
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+static struct ble_ll_sync_sm *
+ble_ll_sync_transfer_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid)
+{
+    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) {
+            /* allocate event for transfer received event */
+            sm->transfer_received_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+            if (!sm->transfer_received_ev) {
+                break;
+            }
+
+            sm->adv_sid = sid;
+            sm->adv_addr_type = addr_type;
+            memcpy(&sm->adv_addr, addr, BLE_DEV_ADDR_LEN);
+
+            sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING;
+            sm->flags |= BLE_LL_SYNC_SM_FLAG_SYNC_INFO;
+            return sm;
+        }
+    }
+
+    return NULL;
+}
+
+void
+ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
+                         const uint8_t *sync_ind, bool reports_disabled,
+                         uint16_t max_skip, uint32_t sync_timeout)
+{
+    const uint8_t *syncinfo = sync_ind + 2;
+    uint16_t sync_conn_event_count;
+    uint16_t last_pa_event_count;
+    struct ble_ll_sync_sm *sm;
+    uint16_t conn_event_count;
+    uint8_t sync_anchor_usecs;
+    const uint8_t *rpa = NULL;
+    uint16_t last_pa_diff;
+    uint32_t sync_anchor;
+    const uint8_t *addr;
+    uint16_t event_cntr;
+    uint32_t itvl_usecs;
+    uint32_t ww_adjust;
+    uint8_t addr_type;
+    uint8_t phy_mode;
+    uint32_t offset;
+    uint32_t future;
+    uint16_t itvl;
+    int rpa_index;
+    uint8_t sid;
+    uint8_t sca;
+    os_sr_t sr;
+
+    phy_mode = ble_ll_ctrl_phy_from_phy_mask(sync_ind[25]);
+    itvl = get_le16(syncinfo + 2);
+    /* ignore if sync params are not valid */
+    if ((phy_mode == 0) || (itvl < 6)) {
+        return;
+    }
+
+    last_pa_event_count = get_le16(sync_ind + 22);
+    event_cntr = get_le16(syncinfo + 16);
+    itvl_usecs = itvl * BLE_LL_SYNC_ITVL_USECS;
+
+    last_pa_diff = event_cntr - last_pa_event_count;
+    /* check if not 5 seconds apart, if so ignore sync transfer */
+    if ((last_pa_diff * itvl_usecs) > 5000000) {
+        return;
+    }
+
+    sid = (sync_ind[24] & 0x0f);
+    addr_type = (sync_ind[24] & 0x10) ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC;
+    addr = sync_ind + 26;
+
+    rpa_index = -1;
+
+    /* check if need to resolve */
+    if (ble_ll_is_rpa(addr, addr_type)) {
+        rpa_index = ble_ll_resolv_peer_rpa_any(addr);
+        if (rpa_index >= 0) {
+            rpa = addr;
+            addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr;
+            addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type;
+        }
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    /* check if already synchronized with this peer */
+    sm = ble_ll_sync_find(addr, addr_type, sid);
+    if (sm) {
+        OS_EXIT_CRITICAL(sr);
+        return;
+    }
+
+    /* ignore if no memory for new sync */
+    sm = ble_ll_sync_transfer_get(addr, addr_type, sid);
+    if (!sm) {
+        OS_EXIT_CRITICAL(sr);
+        return;
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    if (rpa_index >= 0) {
+        sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED;
+        memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN);
+    }
+
+    /* set params from transfer */
+    sm->timeout = os_cputime_usecs_to_ticks(sync_timeout);
+    sm->skip = max_skip;
+    sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT;
+    sm->transfer_id = get_le16(sync_ind); /* first two bytes */
+    sm->transfer_conn = connsm;
+
+    /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit),
+     * RFU (1 bit)
+     */
+    offset = syncinfo[0];
+    offset |= (uint16_t)(syncinfo[1] & 0x1f) << 8;
+
+    if (syncinfo[1] & 0x20) {
+        if (syncinfo[1] & 0x40) {
+            offset += 0x2000;
+        }
+
+        offset *= 300;
+        sm->flags |= BLE_LL_SYNC_SM_FLAG_OFFSET_300;
+    } else {
+        offset *= 30;
+        sm->flags &= ~BLE_LL_SYNC_SM_FLAG_OFFSET_300;
+    }
+
+    /* sync end event */
+    ble_npl_event_init(&sm->sync_ev_end, ble_ll_sync_event_end, sm);
+
+    sm->itvl = itvl;
+
+    /* precalculate interval ticks and usecs */
+    sm->itvl_ticks = os_cputime_usecs_to_ticks(itvl_usecs);
+    sm->itvl_usecs = (uint8_t)(itvl_usecs -
+                               os_cputime_ticks_to_usecs(sm->itvl_ticks));
+    if (sm->itvl_usecs == 31) {
+        sm->itvl_usecs = 0;
+        sm->itvl_ticks++;
+    }
+
+    /* Channels Mask (37 bits) */
+    sm->chanmap[0] = syncinfo[4];
+    sm->chanmap[1] = syncinfo[5];
+    sm->chanmap[2] = syncinfo[6];
+    sm->chanmap[3] = syncinfo[7];
+    sm->chanmap[4] = syncinfo[8] & 0x1f;
+    sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap);
+
+    /* SCA (3 bits) */
+    sm->sca = syncinfo[8] >> 5;
+
+    /* AA (4 bytes) */
+    sm->access_addr = get_le32(syncinfo + 9);
+    sm->channel_id = ((sm->access_addr & 0xffff0000) >> 16) ^
+                      (sm->access_addr & 0x0000ffff);
+
+    /* CRCInit (3 bytes) */
+    sm->crcinit = syncinfo[13];
+    sm->crcinit |= syncinfo[14] << 8;
+    sm->crcinit |= syncinfo[15] << 16;
+
+    /* Event Counter (2 bytes) */
+    sm->event_cntr = event_cntr;
+
+    /* adjust skip if pass timeout */
+    max_skip = get_max_skip(sm->itvl * BLE_LL_SYNC_ITVL_USECS, sync_timeout);
+    if (sm->skip > max_skip) {
+        sm->skip = max_skip;
+    }
+
+    sm->phy_mode = phy_mode;
+
+    sm->window_widening = BLE_LL_JITTER_USECS;
+
+    /* Calculate channel index of first event */
+    sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id,
+                                                sm->num_used_chans, sm->chanmap);
+
+    sm->sch.sched_cb = ble_ll_sync_event_start_cb;
+    sm->sch.cb_arg = sm;
+    sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC;
+
+    /* get anchor for specified conn event */
+    conn_event_count = get_le16(sync_ind + 20);
+    ble_ll_conn_get_anchor(connsm, conn_event_count, &sm->anchor_point,
+                           &sm->anchor_point_usecs);
+
+    /* Set last anchor point */
+    last_pa_diff = sm->event_cntr - last_pa_event_count;
+    sm->last_anchor_point = sm->anchor_point - (last_pa_diff * sm->itvl_ticks);
+
+    /* calculate extra window widening */
+    sync_conn_event_count = get_le16(sync_ind + 32);
+    sca = sync_ind[24] >> 5;
+    ble_ll_conn_get_anchor(connsm, sync_conn_event_count, &sync_anchor,
+                           &sync_anchor_usecs);
+    ww_adjust = ble_ll_utils_calc_window_widening(connsm->anchor_point,
+                                                  sync_anchor, sca);
+
+    /* spin until we get anchor in future */
+    future = os_cputime_get32() + g_ble_ll_sched_offset_ticks;
+    while (CPUTIME_LT(sm->anchor_point, future)) {
+        if (ble_ll_sync_next_event(sm, ww_adjust) < 0) {
+            /* release SM if this failed */
+            ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT);
+            memset(sm, 0, sizeof(*sm));
+            return;
+        }
+    }
+
+    if (ble_ll_sched_sync(&sm->sch, sm->anchor_point, sm->anchor_point_usecs,
+                          offset, sm->phy_mode)) {
+        /* release SM if this failed */
+        ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT);
+        memset(sm, 0, sizeof(*sm));
+        return;
+    }
+
+    /* Set new anchor point */
+    sm->anchor_point = sm->sch.start_time + g_ble_ll_sched_offset_ticks;
+    sm->anchor_point_usecs = sm->sch.remainder;
+
+    /* set anchor point in middle of offset window */
+    if (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) {
+        sm->anchor_point_usecs += 150;
+    } else {
+        sm->anchor_point_usecs += 15;
+    }
+
+    while (sm->anchor_point_usecs >= 31) {
+        sm->anchor_point++;
+        sm->anchor_point_usecs -= 31;
+    }
+
+    if (reports_disabled) {
+        sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
+    }
+}
+#endif
+
 /*
  * Called when a sync scan event has been removed from the scheduler
  * without being run.
diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml
index be90a44..06f08b6 100644
--- a/nimble/controller/syscfg.yml
+++ b/nimble/controller/syscfg.yml
@@ -110,10 +110,10 @@ syscfg.defs:
         value: '251'
     BLE_LL_SUPP_MAX_RX_BYTES:
         description: 'The maximum supported received PDU size'
-        value: 'MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE'
+        value: MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
     BLE_LL_SUPP_MAX_TX_BYTES:
         description: 'The maximum supported transmit PDU size'
-        value: 'MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE'
+        value: MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
     BLE_LL_CONN_INIT_MAX_TX_BYTES:
         description: >
             Used to set the initial maximum transmit PDU size in a
@@ -281,6 +281,12 @@ syscfg.defs:
             Size of Periodic Advertiser sync list.
         value: MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)
 
+    BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER:
+        description: >
+            This option is use to enable/disable support for Periodic
+            Advertising Sync Transfer Feature.
+        value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+
     BLE_LL_EXT_ADV_AUX_PTR_CNT:
          description: >
             This option configure a max number of scheduled outstanding auxiliary
diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h
index 75cae50..068e85c 100644
--- a/nimble/include/nimble/hci_common.h
+++ b/nimble/include/nimble/hci_common.h
@@ -783,9 +783,45 @@ struct ble_hci_le_periodic_adv_receive_enable_cp {
 } __attribute__((packed));
 
 #define BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER        (0x005A)
+struct ble_hci_le_periodic_adv_sync_transfer_cp {
+    uint16_t conn_handle;
+    uint16_t service_data;
+    uint16_t sync_handle;
+} __attribute__((packed));
+struct ble_hci_le_periodic_adv_sync_transfer_rp {
+    uint16_t conn_handle;
+} __attribute__((packed));
+
 #define BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER    (0x005B)
+struct ble_hci_le_periodic_adv_set_info_transfer_cp {
+    uint16_t conn_handle;
+    uint16_t service_data;
+    uint8_t adv_handle;
+} __attribute__((packed));
+struct ble_hci_le_periodic_adv_set_info_transfer_rp {
+    uint16_t conn_handle;
+} __attribute__((packed));
+
 #define BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS (0x005C)
+struct ble_hci_le_periodic_adv_sync_transfer_params_cp {
+    uint16_t conn_handle;
+    uint8_t  mode;
+    uint16_t skip;
+    uint16_t sync_timeout;
+    uint8_t  sync_cte_type;
+} __attribute__((packed));
+struct ble_hci_le_periodic_adv_sync_transfer_params_rp {
+    uint16_t conn_handle;
+} __attribute__((packed));
+
 #define BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS  (0x005D)
+struct ble_hci_le_set_default_periodic_sync_transfer_params_cp {
+    uint8_t  mode;
+    uint16_t skip;
+    uint16_t sync_timeout;
+    uint8_t  sync_cte_type;
+} __attribute__((packed));
+
 #define BLE_HCI_OCF_LE_GENERATE_DHKEY_V2                 (0x005E)
 #define BLE_HCI_OCF_LE_MODIFY_SCA                        (0x005F)
 
@@ -1386,7 +1422,21 @@ struct ble_hci_ev_le_subev_chan_sel_alg {
 #define BLE_HCI_LE_SUBEV_CONNLESS_IQ_RPT        (0x15)
 #define BLE_HCI_LE_SUBEV_CONN_IQ_RPT            (0x16)
 #define BLE_HCI_LE_SUBEV_CTE_REQ_FAILED         (0x17)
+
 #define BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER   (0x18)
+struct ble_hci_ev_le_subev_periodic_adv_sync_transfer {
+    uint8_t  subev_code;
+    uint8_t  status;
+    uint16_t conn_handle;
+    uint16_t service_data;
+    uint16_t sync_handle;
+    uint8_t  sid;
+    uint8_t  peer_addr_type;
+    uint8_t  peer_addr[6];
+    uint8_t  phy;
+    uint16_t interval;
+    uint8_t  aca;
+} __attribute__((packed));
 
 /* Data buffer overflow event */
 #define BLE_HCI_EVENT_ACL_BUF_OVERFLOW      (0x01)
diff --git a/nimble/syscfg.yml b/nimble/syscfg.yml
index b1e3182..c07f9bc 100644
--- a/nimble/syscfg.yml
+++ b/nimble/syscfg.yml
@@ -59,6 +59,11 @@ syscfg.defs:
         description: >
             This enables periodic advertising feature.
         value: 0
+    BLE_PERIODIC_ADV_SYNC_TRANSFER:
+        description: >
+            This enables Periodic Advertising Sync Transfer Feature.
+        value: 0
+
     BLE_EXT_ADV_MAX_SIZE:
         description: >
             This allows to configure maximum size of advertising data and
@@ -72,3 +77,7 @@ syscfg.defs:
             integer for easy comparison.
         range: 50, 51
         value: 50
+
+# Allow periodic sync transfer only if 5.1 or higher
+syscfg.restrictions:
+    - "'BLE_PERIODIC_ADV_SYNC_TRANSFER == 0' || 'BLE_VERSION >= 51'"


[mynewt-nimble] 07/08: nimble/ll: Allow host to assign advertising instances

Posted by ja...@apache.org.
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 734c26fdd0597e2e1f8f62f3396ed7eef8da57e6
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Nov 20 15:11:21 2019 +0100

    nimble/ll: Allow host to assign advertising instances
    
    This allows host to assign own instances when configuring extended
    advertising. Before this change host could use only 0-max_adv_instances
    values as instance number.
---
 nimble/controller/src/ble_ll_adv.c | 168 +++++++++++++++++--------------------
 1 file changed, 79 insertions(+), 89 deletions(-)

diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c
index db83ba4..79e250f 100644
--- a/nimble/controller/src/ble_ll_adv.c
+++ b/nimble/controller/src/ble_ll_adv.c
@@ -202,6 +202,34 @@ struct ble_ll_adv_sm
 #define SYNC_DATA_LEN(_advsm) \
                 (_advsm->periodic_adv_data ? OS_MBUF_PKTLEN(advsm->periodic_adv_data) : 0)
 
+/* The advertising state machine global object */
+struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES];
+struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm;
+
+static struct ble_ll_adv_sm *
+ble_ll_adv_sm_find_configured(uint8_t instance)
+{
+    struct ble_ll_adv_sm *advsm;
+    int i;
+
+    /* in legacy mode we only allow instance 0 */
+    if (!ble_ll_hci_adv_mode_ext()) {
+        BLE_LL_ASSERT(instance == 0);
+        return &g_ble_ll_adv_sm[0];
+    }
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_adv_sm); i++) {
+        advsm = &g_ble_ll_adv_sm[i];
+
+        if ((advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED) &&
+                (advsm->adv_instance == instance)) {
+            return advsm;
+        }
+    }
+
+    return NULL;
+}
+
 static int
 ble_ll_adv_active_chanset_is_pri(struct ble_ll_adv_sm *advsm)
 {
@@ -272,10 +300,6 @@ ble_ll_adv_flags_clear(struct ble_ll_adv_sm *advsm, uint16_t flags)
     OS_EXIT_CRITICAL(sr);
 }
 
-/* The advertising state machine global object */
-struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES];
-struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm;
-
 static void ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr);
 static void ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm);
 static void ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm);
@@ -2717,12 +2741,11 @@ ble_ll_adv_set_enable(uint8_t instance, uint8_t enable, int duration,
     int rc;
     struct ble_ll_adv_sm *advsm;
 
-    if (instance >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
+    advsm = ble_ll_adv_sm_find_configured(instance);
+    if (!advsm) {
+        return BLE_ERR_UNK_ADV_INDENT;
     }
 
-    advsm = &g_ble_ll_adv_sm[instance];
-
     rc = BLE_ERR_SUCCESS;
     if (enable == 1) {
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
@@ -2814,19 +2837,6 @@ done:
     *omp = om;
 }
 
-static bool
-instance_configured(struct ble_ll_adv_sm *advsm)
-{
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
-    if (ble_ll_hci_adv_mode_ext()) {
-        return advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED;
-    }
-#endif
-
-    /* legacy HCI instance is always configured */
-    return true;
-}
-
 /**
  * Set the scan response data that the controller will send.
  *
@@ -2842,13 +2852,8 @@ ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen,
     struct ble_ll_adv_sm *advsm;
     bool new_data;
 
-    if (instance >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[instance];
-
-    if (!instance_configured(advsm)) {
+    advsm = ble_ll_adv_sm_find_configured(instance);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -2968,13 +2973,8 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance,
     struct ble_ll_adv_sm *advsm;
     bool new_data;
 
-    if (instance >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[instance];
-
-    if (!instance_configured(advsm)) {
+    advsm = ble_ll_adv_sm_find_configured(instance);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -3132,6 +3132,32 @@ sec_phy_valid(uint8_t phy)
     }
 }
 
+static struct ble_ll_adv_sm *
+ble_ll_adv_sm_get(uint8_t instance)
+{
+    struct ble_ll_adv_sm *advsm;
+    int i;
+
+    advsm = ble_ll_adv_sm_find_configured(instance);
+    if (advsm) {
+        return advsm;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(g_ble_ll_adv_sm); i++) {
+        advsm = &g_ble_ll_adv_sm[i];
+
+        if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+            ble_ll_adv_sm_init(advsm);
+
+           /* configured flag is set by caller on success config */
+           advsm->adv_instance = instance;
+           return advsm;
+        }
+    }
+
+    return NULL;
+}
+
 int
 ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
                          uint8_t *rspbuf, uint8_t *rsplen)
@@ -3149,12 +3175,12 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
         goto done;
     }
 
-    if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+    advsm = ble_ll_adv_sm_get(cmd->adv_handle);
+    if (!advsm) {
+        rc = BLE_ERR_MEM_CAPACITY;
         goto done;
     }
 
-    advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
     if (advsm->adv_enabled) {
         rc = BLE_ERR_CMD_DISALLOWED;
         goto done;
@@ -3453,10 +3479,6 @@ ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len)
 
     /* validate instances */
     for (i = 0; i < cmd->num_sets; i++) {
-        if (cmd->sets[i].adv_handle >= BLE_ADV_INSTANCES) {
-            return BLE_ERR_INV_HCI_CMD_PARMS;
-        }
-
         /* validate duplicated sets */
         for (j = i + 1; j < cmd->num_sets; j++) {
             if (cmd->sets[i].adv_handle == cmd->sets[j].adv_handle) {
@@ -3464,9 +3486,8 @@ ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len)
             }
         }
 
-        advsm = &g_ble_ll_adv_sm[cmd->sets[i].adv_handle];
-
-        if (!instance_configured(advsm)) {
+        advsm = ble_ll_adv_sm_find_configured(cmd->sets[i].adv_handle);
+        if (!advsm) {
             return BLE_ERR_UNK_ADV_INDENT;
         }
 
@@ -3497,12 +3518,11 @@ ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance)
 {
     struct ble_ll_adv_sm *advsm;
 
-    if (instance >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
+    advsm = ble_ll_adv_sm_find_configured(instance);
+    if (!advsm) {
+        return BLE_ERR_UNK_ADV_INDENT;
     }
 
-    advsm = &g_ble_ll_adv_sm[instance];
-
     /*
      * Reject if connectable advertising is on
      * Core Spec Vol. 2 Part E 7.8.52
@@ -3543,17 +3563,8 @@ ble_ll_adv_remove(const uint8_t *cmdbuf, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    /* TODO
-     * Should we allow any value for instance ID?
-     */
-
-    if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
-
-    if (!instance_configured(advsm)) {
+    advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -3627,12 +3638,8 @@ ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len)
     adv_itvl_max = le16toh(cmd->max_itvl);
     props = le16toh(cmd->props);
 
-    if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
-    if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+    advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -3694,12 +3701,8 @@ ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
-    if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+    advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -3787,12 +3790,8 @@ ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
-    if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+    advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle);
+    if (!advsm) {
         return BLE_ERR_UNK_ADV_INDENT;
     }
 
@@ -3886,13 +3885,8 @@ ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
          goto done;
      }
 
-     if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
-         rc = BLE_ERR_INV_HCI_CMD_PARMS;
-         goto done;
-     }
-
-     advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
-     if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+     advsm = ble_ll_adv_sm_find_configured(cmd->adv_handle);
+     if (!advsm) {
          rc = BLE_ERR_UNK_ADV_INDENT;
          goto done;
      }
@@ -4915,11 +4909,8 @@ ble_ll_adv_enabled(void)
 static void
 ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm)
 {
-    uint8_t i = advsm->adv_instance;
-
     memset(advsm, 0, sizeof(struct ble_ll_adv_sm));
 
-    advsm->adv_instance = i;
     advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF;
     advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF;
     advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF;
@@ -4972,7 +4963,6 @@ ble_ll_adv_init(void)
 
     /* Set default advertising parameters */
     for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
-        g_ble_ll_adv_sm[i].adv_instance = i;
         ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]);
     }
 }


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

Posted by ja...@apache.org.
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


[mynewt-nimble] 06/08: nimble/btshell: Add support for periodic sync transfer

Posted by ja...@apache.org.
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 afc726098b13b5da4220512db877afc02dda8937
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Mon Nov 4 14:50:16 2019 +0100

    nimble/btshell: Add support for periodic sync transfer
    
    Allows to transmit and enable reception of sync transfer.
---
 apps/btshell/src/cmd.c  | 222 +++++++++++++++++++++++++++++++++++++++++++++++-
 apps/btshell/src/main.c |  29 +++++++
 2 files changed, 250 insertions(+), 1 deletion(-)

diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c
index 152a3cc..1bb174f 100644
--- a/apps/btshell/src/cmd.c
+++ b/apps/btshell/src/cmd.c
@@ -3680,7 +3680,7 @@ static const struct shell_cmd_help periodic_stop_help = {
 static int
 cmd_sync_create(int argc, char **argv)
 {
-    struct ble_gap_periodic_sync_params params;
+    struct ble_gap_periodic_sync_params params = { 0 };
     ble_addr_t addr;
     ble_addr_t *addr_param = &addr;
     uint8_t sid;
@@ -3728,6 +3728,12 @@ cmd_sync_create(int argc, char **argv)
         return rc;
     }
 
+    params.reports_disabled = parse_arg_bool_dflt("reports_disabled", false, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'reports_disabled' parameter\n");
+        return rc;
+    }
+
     rc = ble_gap_periodic_adv_sync_create(addr_param, sid, &params,
                                           btshell_gap_event, NULL);
     if (rc) {
@@ -3745,6 +3751,7 @@ static const struct shell_param sync_create_params[] = {
     {"sid", "usage: =[UINT8], default: 0"},
     {"skip", "usage: =[0-0x01F3], default: 0x0000"},
     {"sync_timeout", "usage: =[0x000A-0x4000], default: 0x000A"},
+    {"reports_disabled", "disable reports, usage: =[0-1], default: 0"},
     {NULL, NULL}
 };
 
@@ -3755,6 +3762,196 @@ static const struct shell_cmd_help sync_create_help = {
 };
 #endif
 
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+static int
+cmd_sync_transfer(int argc, char **argv)
+{
+    uint16_t service_data;
+    uint16_t conn_handle;
+    uint16_t sync_handle;
+    int rc;
+
+    rc = parse_arg_all(argc - 1, argv + 1);
+    if (rc != 0) {
+        return rc;
+    }
+
+    conn_handle = parse_arg_uint16("conn", &rc);
+    if (rc != 0) {
+        console_printf("invalid 'conn' parameter\n");
+        return rc;
+    }
+
+    sync_handle = parse_arg_uint16_dflt("sync_handle", 0, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'sync_handle' parameter\n");
+        return rc;
+    }
+
+    service_data = parse_arg_uint16_dflt("service_data", 0, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'service_data' parameter\n");
+        return rc;
+    }
+
+    rc = ble_gap_periodic_adv_sync_transfer(sync_handle, conn_handle,
+                                            service_data);
+    if (rc) {
+        console_printf("Failed to transfer sync (%d)\n", rc);
+    }
+
+    return rc;
+}
+
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+static const struct shell_param sync_transfer_params[] = {
+    {"conn", "connection handle, usage: =<UINT16>"},
+    {"sync_handle", "sync handle, usage: =[UINT16], default: 0"},
+    {"service_data", "service data, usage: =[UINT16], default: 0"},
+    {NULL, NULL}
+};
+
+static const struct shell_cmd_help sync_transfer_help = {
+    .summary = "start periodic sync transfer procedure with specific parameters",
+    .usage = NULL,
+    .params = sync_transfer_params,
+};
+#endif
+
+static int
+cmd_sync_transfer_set_info(int argc, char **argv)
+{
+    uint16_t service_data;
+    uint16_t conn_handle;
+    uint8_t instance;
+    int rc;
+
+    rc = parse_arg_all(argc - 1, argv + 1);
+    if (rc != 0) {
+        return rc;
+    }
+
+    conn_handle = parse_arg_uint16("conn", &rc);
+    if (rc != 0) {
+        console_printf("invalid 'conn' parameter\n");
+        return rc;
+    }
+
+    instance = parse_arg_uint8_dflt("instance", 0, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'instance' parameter\n");
+        return rc;
+    }
+
+    service_data = parse_arg_uint16_dflt("service_data", 0, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'service_data' parameter\n");
+        return rc;
+    }
+
+    rc = ble_gap_periodic_adv_sync_set_info(instance, conn_handle,
+                                                service_data);
+    if (rc) {
+        console_printf("Failed to transfer sync (%d)\n", rc);
+    }
+
+    return rc;
+}
+
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+static const struct shell_param sync_transfer_set_info_params[] = {
+    {"conn", "connection handle, usage: =<UINT16>"},
+    {"instance", "advertising instance, usage: =[UINT8], default: 0"},
+    {"service_data", "service data, usage: =[UINT16], default: 0"},
+    {NULL, NULL}
+};
+
+static const struct shell_cmd_help sync_transfer_set_info_help = {
+    .summary = "start periodic sync transfer procedure with specific parameters",
+    .usage = NULL,
+    .params = sync_transfer_set_info_params,
+};
+#endif
+
+static int
+cmd_sync_transfer_receive(int argc, char **argv)
+{
+    struct ble_gap_periodic_sync_params params = { 0 };
+    uint16_t conn_handle;
+    bool disable;
+    int rc;
+
+    rc = parse_arg_all(argc - 1, argv + 1);
+    if (rc != 0) {
+        return rc;
+    }
+
+    conn_handle = parse_arg_uint16("conn", &rc);
+    if (rc != 0) {
+        console_printf("invalid 'conn' parameter\n");
+        return rc;
+    }
+
+    disable = parse_arg_bool_dflt("disable", false, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'disable' parameter\n");
+        return rc;
+    }
+
+    if (disable) {
+        rc = ble_gap_periodic_adv_sync_receive(conn_handle, NULL, NULL, NULL);
+        if (rc) {
+            console_printf("Failed to disable sync transfer reception (%d)\n", rc);
+        }
+
+        return rc;
+    }
+
+    params.skip = parse_arg_uint16_dflt("skip", 0, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'skip' parameter\n");
+        return rc;
+    }
+
+    params.sync_timeout = parse_arg_time_dflt("sync_timeout", 10000, 10, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'sync_timeout' parameter\n");
+        return rc;
+    }
+
+    params.reports_disabled = parse_arg_bool_dflt("reports_disabled", false, &rc);
+    if (rc != 0) {
+        console_printf("invalid 'reports_disabled' parameter\n");
+        return rc;
+    }
+
+    rc = ble_gap_periodic_adv_sync_receive(conn_handle, &params, btshell_gap_event,
+                                       NULL);
+    if (rc) {
+        console_printf("Failed to enable sync transfer reception (%d)\n", rc);
+    }
+
+    return rc;
+}
+
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+static const struct shell_param sync_transfer_receive_params[] = {
+    {"conn", "connection handle, usage: =<UINT16>"},
+    {"disable", "disable transfer reception, usage: =[0-1], default: 0"},
+    {"skip", "usage: =[0-0x01F3], default: 0x0000"},
+    {"sync_timeout", "usage: =[0x000A-0x4000], default: 0x000A"},
+    {"reports_disabled", "disable reports, usage: =[0-1], default: 0"},
+    {NULL, NULL}
+};
+#endif
+
+static const struct shell_cmd_help sync_transfer_receive_help = {
+    .summary = "start/stop periodic sync reception with specific parameters",
+    .usage = NULL,
+    .params = sync_transfer_receive_params,
+};
+#endif
+
 static int
 cmd_sync_terminate(int argc, char **argv)
 {
@@ -4281,6 +4478,29 @@ static const struct shell_cmd btshell_commands[] = {
         .help = &sync_stats_help,
 #endif
     },
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+    {
+        .sc_cmd = "sync-transfer",
+        .sc_cmd_func = cmd_sync_transfer,
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+        .help = &sync_transfer_help,
+#endif
+    },
+    {
+        .sc_cmd = "sync-transfer-set-info",
+        .sc_cmd_func = cmd_sync_transfer_set_info,
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+        .help = &sync_transfer_set_info_help,
+#endif
+    },
+    {
+        .sc_cmd = "sync-transfer-receive",
+        .sc_cmd_func = cmd_sync_transfer_receive,
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+        .help = &sync_transfer_receive_help,
+#endif
+    },
+#endif
 #endif
     { 0 },
 };
diff --git a/apps/btshell/src/main.c b/apps/btshell/src/main.c
index 923416d..8abe190 100644
--- a/apps/btshell/src/main.c
+++ b/apps/btshell/src/main.c
@@ -1393,6 +1393,35 @@ btshell_gap_event(struct ble_gap_event *event, void *arg)
     case BLE_GAP_EVENT_PERIODIC_REPORT:
         handle_periodic_report(event);
         return 0;
+#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_GAP_EVENT_PERIODIC_TRANSFER:
+        console_printf("Periodic Sync Transfer Received on conn=%u; status=%u,"
+                        " sync_handle=%u sid=%u phy=%u adv_interval=%u ca=%u "
+                        "addr_type=%u addr=",
+                       event->periodic_transfer.conn_handle,
+                       event->periodic_transfer.status,
+                       event->periodic_transfer.sync_handle,
+                       event->periodic_transfer.sid,
+                       event->periodic_transfer.adv_phy,
+                       event->periodic_transfer.per_adv_itvl,
+                       event->periodic_transfer.adv_clk_accuracy,
+                       event->periodic_transfer.adv_addr.type);
+        print_addr(event->periodic_transfer.adv_addr.val);
+        console_printf("\n");
+
+        if (!event->periodic_transfer.status) {
+            /* TODO non-NimBLE controllers may not start handles from 0 */
+            if (event->periodic_transfer.sync_handle >= MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS)) {
+                console_printf("Unable to prepare cache for sync data\n");
+            } else {
+                psync = &g_periodic_data[event->periodic_transfer.sync_handle];
+                memset(psync, 0, sizeof(*psync));
+                psync->changed = true;
+                psync->established = true;
+            }
+        }
+        return 0;
+#endif
 #endif
     default:
         return 0;


[mynewt-nimble] 04/08: nimble/ll: Add support for sync transfer transmission

Posted by ja...@apache.org.
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 cd0afd37a837a6dbf06553236a1c225a4778039c
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Mon Oct 28 09:32:30 2019 +0100

    nimble/ll: Add support for sync transfer transmission
    
    Add support for required HCI commands/events and LL PDUs.
---
 nimble/controller/include/controller/ble_ll_sync.h |   2 +
 nimble/controller/src/ble_ll.c                     |   1 +
 nimble/controller/src/ble_ll_adv.c                 | 192 ++++++++++++++++++--
 nimble/controller/src/ble_ll_hci.c                 |   8 +
 nimble/controller/src/ble_ll_supp_cmd.c            |  16 +-
 nimble/controller/src/ble_ll_sync.c                | 201 ++++++++++++++++++++-
 6 files changed, 396 insertions(+), 24 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h
index fea5b14..712af6d 100644
--- a/nimble/controller/include/controller/ble_ll_sync.h
+++ b/nimble/controller/include/controller/ble_ll_sync.h
@@ -40,6 +40,8 @@ int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len);
 int ble_ll_sync_list_clear(void);
 int ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen);
 int ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len);
+int ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len,
+                         uint8_t *rspbuf, uint8_t *rsplen);
 
 void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
                               const uint8_t *sync_ind, bool reports_disabled,
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index f4f8ddb..2d39b14 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -1656,6 +1656,7 @@ ble_ll_init(void)
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
     features |= BLE_LL_FEAT_SYNC_RECV;
+    features |= BLE_LL_FEAT_SYNC_SEND;
 #endif
 
     /* Initialize random number generation */
diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c
index 3c6ef62..db83ba4 100644
--- a/nimble/controller/src/ble_ll_adv.c
+++ b/nimble/controller/src/ble_ll_adv.c
@@ -165,6 +165,9 @@ struct ble_ll_adv_sm
     uint32_t periodic_adv_event_start_time;
     struct ble_ll_adv_sync periodic_sync[2];
     struct ble_npl_event adv_periodic_txdone_ev;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    uint16_t periodic_event_cntr_last_sent;
+#endif
 #endif
 #endif
 };
@@ -571,19 +574,45 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
 static void
-ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm, uint8_t *dptr)
+ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm,
+                        struct ble_ll_conn_sm *connsm, uint8_t *dptr)
 {
     uint32_t offset;
     uint8_t units;
 
-    offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time -
-                                       AUX_CURRENT(advsm)->start_time);
-    offset += advsm->periodic_adv_event_start_time_remainder;
+    if (connsm) {
+        if (CPUTIME_LT(connsm->anchor_point, advsm->periodic_adv_event_start_time)) {
+            offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time -
+                                               connsm->anchor_point);
+        } else {
+            offset = os_cputime_ticks_to_usecs(connsm->anchor_point -
+                                               advsm->periodic_adv_event_start_time);
+        }
 
-    /* Sync Packet Offset (13 bits), Offset Units (1 bit), RFU (2 bits) */
+        offset -= connsm->anchor_point_usecs;
+        offset += advsm->periodic_adv_event_start_time_remainder;
+    } else {
+        offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time -
+                                           AUX_CURRENT(advsm)->start_time);
+        offset += advsm->periodic_adv_event_start_time_remainder;
+    }
+
+    /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit),
+     * RFU (1 bit)
+     */
     if (offset > 245700) {
         units = 0x20;
         offset = offset / 300;
+
+        if (offset >= 0x2000) {
+            if (connsm) {
+                offset -= 0x2000;
+                units |= 0x40;
+            } else {
+                offset = 0;
+            }
+        }
+
     } else {
         units = 0x00;
         offset = offset / 30;
@@ -703,7 +732,7 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
     if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) {
-        ble_ll_adv_put_syncinfo(advsm, dptr);
+        ble_ll_adv_put_syncinfo(advsm, NULL, dptr);
         dptr += BLE_LL_EXT_ADV_SYNC_INFO_SIZE;
     }
 #endif
@@ -1996,24 +2025,13 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
     return sync->payload_len;
 }
 
-/**
- * Called to indicate the advertising sync event is over.
- *
- * Context: Interrupt
- *
- * @param advsm
- *
- */
+
 static void
-ble_ll_adv_sync_tx_done(void *arg)
+ble_ll_adv_sync_tx_done(struct ble_ll_adv_sm *advsm)
 {
-    struct ble_ll_adv_sm *advsm;
-
     /* reset power to max after advertising */
     ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
 
-    advsm = (struct ble_ll_adv_sm *)arg;
-
     /* for sync we trace a no pri nor sec set */
     ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, 0);
 
@@ -2030,6 +2048,27 @@ ble_ll_adv_sync_tx_done(void *arg)
     g_ble_ll_cur_adv_sm = NULL;
 }
 
+/**
+ * Called to indicate the advertising sync event is over.
+ *
+ * Context: Interrupt
+ *
+ * @param advsm
+ *
+ */
+static void
+ble_ll_adv_sync_tx_end(void *arg)
+{
+    struct ble_ll_adv_sm *advsm = arg;
+
+    ble_ll_adv_sync_tx_done(advsm);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    /* store last sent periodic counter */
+    advsm->periodic_event_cntr_last_sent = advsm->periodic_event_cntr;
+#endif
+}
+
 static int
 ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch)
 {
@@ -2079,7 +2118,7 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch)
 #endif
 
     /* Transmit advertisement */
-    ble_phy_set_txend_cb(ble_ll_adv_sync_tx_done, advsm);
+    ble_phy_set_txend_cb(ble_ll_adv_sync_tx_end, advsm);
     rc = ble_phy_tx(ble_ll_adv_sync_pdu_make, advsm, BLE_PHY_TRANSITION_NONE);
     if (rc) {
         goto adv_tx_done;
@@ -3779,6 +3818,119 @@ ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len)
 
     return BLE_ERR_SUCCESS;
 }
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+static int
+ble_ll_adv_periodic_send_sync_ind(struct ble_ll_adv_sm *advsm,
+                                  struct ble_ll_conn_sm *connsm,
+                                  uint16_t service_data)
+{
+    struct os_mbuf *om;
+    uint8_t *sync_ind;
+
+    om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN,
+                            sizeof(struct ble_mbuf_hdr));
+    if (!om) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    om->om_data[0] = BLE_LL_CTRL_PERIODIC_SYNC_IND;
+
+    sync_ind = om->om_data + 1;
+
+    /* ID (service_data), already in LE order */
+    memcpy(sync_ind, &service_data, sizeof(service_data));
+
+    /* fill in syncinfo */
+    ble_ll_adv_put_syncinfo(advsm, connsm, sync_ind + 2);
+
+    /* connEventCount */
+    put_le16(sync_ind + 20, connsm->event_cntr);
+
+    /* lastPaEventCounter */
+    put_le16(sync_ind + 22, advsm->periodic_event_cntr_last_sent);
+
+    /* SID, AType, SCA */
+    sync_ind[24] = (advsm->adi >> 12);
+    sync_ind[24] |= !!(advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) << 4 ;
+    sync_ind[24] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
+
+    /* PHY */
+    sync_ind[25] = (0x01 << (advsm->sec_phy - 1));
+
+    /* AdvA */
+    memcpy(sync_ind + 26, advsm->adva, BLE_DEV_ADDR_LEN);
+
+    /* syncConnEventCount */
+    put_le16(sync_ind + 32, connsm->event_cntr);
+
+    ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL,
+                            BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN + 1);
+
+    return BLE_ERR_SUCCESS;
+}
+
+int
+ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
+                                      uint8_t *rspbuf, uint8_t *rsplen)
+{
+    const struct ble_hci_le_periodic_adv_set_info_transfer_cp *cmd = (const void *)cmdbuf;
+     struct ble_hci_le_periodic_adv_set_info_transfer_rp *rsp = (void *) rspbuf;
+     struct ble_ll_conn_sm *connsm;
+     struct ble_ll_adv_sm *advsm;
+     uint16_t handle;
+     int rc;
+
+     if (len != sizeof(*cmd)) {
+         rc = BLE_ERR_INV_HCI_CMD_PARMS;
+         goto done;
+     }
+
+     if (cmd->adv_handle >= BLE_ADV_INSTANCES) {
+         rc = BLE_ERR_INV_HCI_CMD_PARMS;
+         goto done;
+     }
+
+     advsm = &g_ble_ll_adv_sm[cmd->adv_handle];
+     if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED)) {
+         rc = BLE_ERR_UNK_ADV_INDENT;
+         goto done;
+     }
+
+     if (!advsm->periodic_adv_active) {
+         rc = BLE_ERR_CMD_DISALLOWED;
+         goto done;
+     }
+
+     handle = le16toh(cmd->conn_handle);
+     if (handle > 0xeff) {
+         rc = BLE_ERR_INV_HCI_CMD_PARMS;
+         goto done;
+     }
+
+     connsm = ble_ll_conn_find_active_conn(handle);
+     if (!connsm) {
+         rc = BLE_ERR_UNK_CONN_ID;
+         goto done;
+     }
+
+     /* TODO should not need to shift
+      * byte 3 (0 byte is conn_feature) , bit 1
+      *
+      * Allow initiate LL procedure only if remote supports it.
+      */
+     if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_RECV >> (8 * 3)))) {
+         rc = BLE_ERR_UNSUPP_REM_FEATURE;
+         goto done;
+     }
+
+     rc = ble_ll_adv_periodic_send_sync_ind(advsm, connsm, cmd->service_data);
+ done:
+     rsp->conn_handle = cmd->conn_handle;
+     *rsplen = sizeof(*rsp);
+     return rc;
+}
+#endif
 #endif
 #endif
 
diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c
index 05ee5c3..50027ac 100644
--- a/nimble/controller/src/ble_ll_hci.c
+++ b/nimble/controller/src/ble_ll_hci.c
@@ -712,6 +712,8 @@ ble_ll_is_valid_adv_mode(uint8_t ocf)
     case BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE:
 #endif
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER:
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER:
     case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS:
     case BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS:
 #endif
@@ -1129,6 +1131,12 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
         break;
 #endif
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER:
+        rc = ble_ll_sync_transfer(cmdbuf, len, rspbuf, rsplen);
+        break;
+    case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER:
+        rc = ble_ll_adv_periodic_set_info_transfer(cmdbuf, len, rspbuf, rsplen);
+        break;
     case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS:
         rc = ble_ll_set_sync_transfer_params(cmdbuf, len, rspbuf, rsplen);
         break;
diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c
index c3c5950..834e009 100644
--- a/nimble/controller/src/ble_ll_supp_cmd.c
+++ b/nimble/controller/src/ble_ll_supp_cmd.c
@@ -381,9 +381,19 @@
 #else
 #define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5)
 #endif
-#define BLE_LL_SUPP_CMD_OCTET_40            \
-(                                           \
-    BLE_SUPP_CMD_LE_PADV_RECV_ENABLE        \
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (1 << 6)
+#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (1 << 7)
+#else
+#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (0 << 6)
+#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (0 << 7)
+#endif
+
+#define BLE_LL_SUPP_CMD_OCTET_40             \
+(                                            \
+    BLE_SUPP_CMD_LE_PADV_RECV_ENABLE       | \
+    BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER     | \
+    BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER   \
 )
 
 /* Octet 41 */
diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c
index 41daf13..436a2d9 100644
--- a/nimble/controller/src/ble_ll_sync.c
+++ b/nimble/controller/src/ble_ll_sync.c
@@ -107,6 +107,7 @@ struct ble_ll_sync_sm {
     struct ble_ll_conn_sm *transfer_conn;
     uint8_t *transfer_received_ev;
     uint16_t transfer_id;
+    uint16_t event_cntr_last_received;
     uint8_t adv_addr_rpa[6];
 #endif
 };
@@ -1019,6 +1020,11 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
         goto end_event;
     }
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
+    /* save last pa counter */
+    sm->event_cntr_last_received = sm->event_cntr;
+#endif
+
     /* if packet is good we send sync established here */
     if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
         ble_ll_sync_established(sm);
@@ -1203,7 +1209,7 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index,
 {
     struct ble_ll_sync_sm *sm = NULL;
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
-    const uint8_t *rpa;
+    const uint8_t *rpa = NULL;
 #endif
     uint16_t max_skip;
     uint32_t offset;
@@ -1977,6 +1983,199 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
         sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED;
     }
 }
+
+static void
+ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm,
+                         struct ble_ll_conn_sm *connsm, uint8_t *dptr)
+{
+    uint32_t offset;
+    uint8_t units;
+
+     if (CPUTIME_LT(connsm->anchor_point, syncsm->anchor_point)) {
+         offset = os_cputime_ticks_to_usecs(syncsm->anchor_point -
+                                            connsm->anchor_point);
+     } else {
+         offset = os_cputime_ticks_to_usecs(connsm->anchor_point -
+                                            syncsm->anchor_point);
+     }
+
+     offset -= connsm->anchor_point_usecs;
+     offset += syncsm->anchor_point_usecs;
+
+    /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit),
+     * RFU (1 bit)
+     */
+    if (offset > 245700) {
+        units = 0x20;
+
+        if (offset >= 0x2000) {
+            offset -= 0x2000;
+            units |= 0x40;
+        }
+
+        offset = offset / 300;
+    } else {
+        units = 0x00;
+        offset = offset / 30;
+    }
+
+    dptr[0] = (offset & 0x000000ff);
+    dptr[1] = ((offset >> 8) & 0x0000001f) | units;
+
+    /* Interval (2 bytes) */
+    put_le16(&dptr[2], syncsm->itvl);
+
+    /* Channels Mask (37 bits) */
+    dptr[4] = syncsm->chanmap[0];
+    dptr[5] = syncsm->chanmap[1];
+    dptr[6] = syncsm->chanmap[2];
+    dptr[7] = syncsm->chanmap[3];
+    dptr[8] = syncsm->chanmap[4] & 0x1f;
+
+    /* SCA (3 bits) */
+    dptr[8] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
+
+    /* AA (4 bytes) */
+    put_le32(&dptr[9], syncsm->access_addr);
+
+    /* CRCInit (3 bytes) */
+    dptr[13] = (uint8_t)syncsm->crcinit;
+    dptr[14] = (uint8_t)(syncsm->crcinit >> 8);
+    dptr[15] = (uint8_t)(syncsm->crcinit >> 16);
+
+    /* Event Counter (2 bytes) */
+    put_le16(&dptr[16], syncsm->event_cntr);
+}
+
+static int
+ble_ll_sync_send_sync_ind(struct ble_ll_sync_sm *syncsm,
+                          struct ble_ll_conn_sm *connsm, uint16_t service_data)
+{
+    struct os_mbuf *om;
+    uint8_t *sync_ind;
+
+    om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN,
+                            sizeof(struct ble_mbuf_hdr));
+    if (!om) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    om->om_data[0] = BLE_LL_CTRL_PERIODIC_SYNC_IND;
+
+    sync_ind = om->om_data + 1;
+
+    /* ID (service_data), already in LE order */
+    memcpy(sync_ind, &service_data, sizeof(service_data));
+
+    /* fill in syncinfo */
+    ble_ll_sync_put_syncinfo(syncsm, connsm, sync_ind + 2);
+
+    /* connEventCount */
+    put_le16(sync_ind + 20, connsm->event_cntr);
+
+    /* lastPaEventCounter */
+    put_le16(sync_ind + 22, syncsm->event_cntr_last_received);
+
+    /* SID, AType, SCA */
+    sync_ind[24] = syncsm->adv_sid;
+
+    if (syncsm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) {
+        sync_ind[24] |= 1 << 4;
+    } else {
+        sync_ind[24] |= (syncsm->adv_addr_type == BLE_ADDR_RANDOM) << 4 ;
+    }
+
+    sync_ind[24] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
+
+    /* PHY */
+    sync_ind[25] = (0x01 << (ble_ll_sync_phy_mode_to_hci(syncsm->phy_mode) - 1));
+
+    /* AdvA */
+    if (syncsm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) {
+        memcpy(sync_ind + 26, syncsm->adv_addr_rpa, BLE_DEV_ADDR_LEN);
+    } else {
+        memcpy(sync_ind + 26, syncsm->adv_addr, BLE_DEV_ADDR_LEN);
+    }
+
+    /* syncConnEventCount */
+    put_le16(sync_ind + 32, connsm->event_cntr);
+
+    ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL,
+                            BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN + 1);
+
+    return BLE_ERR_SUCCESS;
+}
+
+int
+ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len,
+                     uint8_t *rspbuf, uint8_t *rsplen)
+{
+    const struct ble_hci_le_periodic_adv_sync_transfer_cp *cmd = (const void *)cmdbuf;
+    struct ble_hci_le_periodic_adv_sync_transfer_rp *rsp = (void *) rspbuf;
+    struct ble_ll_conn_sm *connsm;
+    struct ble_ll_sync_sm *sm;
+    uint16_t handle;
+    os_sr_t sr;
+    int rc;
+
+    if (len != sizeof(*cmd)) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    handle = le16toh(cmd->sync_handle);
+    if (handle > 0xeff) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        goto done;
+    }
+
+    if (handle >= BLE_LL_SYNC_CNT) {
+        rc = BLE_ERR_UNK_ADV_INDENT;
+        goto done;
+    }
+
+    sm = &g_ble_ll_sync_sm[handle];
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) {
+        rc = BLE_ERR_UNK_ADV_INDENT;
+        OS_EXIT_CRITICAL(sr);
+        goto done;
+    }
+
+    handle = le16toh(cmd->conn_handle);
+    if (handle > 0xeff) {
+        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+        OS_EXIT_CRITICAL(sr);
+        goto done;
+    }
+
+    connsm = ble_ll_conn_find_active_conn(handle);
+    if (!connsm) {
+        rc = BLE_ERR_UNK_CONN_ID;
+        OS_EXIT_CRITICAL(sr);
+        goto done;
+    }
+
+    /* TODO should not need to shift
+     * byte 3 (0 byte is conn_feature) , bit 1
+     *
+     * Allow initiate LL procedure only if remote supports it.
+     */
+    if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_RECV >> (8 * 3)))) {
+        rc = BLE_ERR_UNSUPP_REM_FEATURE;
+        goto done;
+    }
+
+    rc = ble_ll_sync_send_sync_ind(sm, connsm, cmd->service_data);
+
+    OS_EXIT_CRITICAL(sr);
+done:
+    rsp->conn_handle = cmd->conn_handle;
+    *rsplen = sizeof(*rsp);
+    return rc;
+}
 #endif
 
 /*