You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by st...@apache.org on 2016/12/18 21:56:34 UTC

[06/50] incubator-mynewt-core git commit: MYNEWT-508: Add multiple advertising instances

MYNEWT-508: Add multiple advertising instances

This commit adds the ability for the nimble controller to have
multiple advertising instances. There were many changes to the code
to support this feature. More on how to enable it is in the jira
ticket.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/8c876d8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/8c876d8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/8c876d8c

Branch: refs/heads/sensors_branch
Commit: 8c876d8c350e71026827f35868356a1af6826b46
Parents: d64f500
Author: William San Filippo <wi...@runtime.io>
Authored: Tue Dec 13 11:41:57 2016 -0800
Committer: Sterling Hughes <st...@apache.org>
Committed: Sun Dec 18 13:56:16 2016 -0800

----------------------------------------------------------------------
 apps/bletest/src/bletest_hci.c                  | 173 ++++++-
 apps/bletest/src/bletest_priv.h                 |  20 +-
 apps/bletest/src/main.c                         | 266 +++++++++-
 hw/drivers/nimble/nrf52/src/ble_phy.c           |   2 +-
 .../controller/include/controller/ble_ll_adv.h  |  46 +-
 .../include/controller/ble_ll_sched.h           |  25 +-
 net/nimble/controller/src/ble_ll_adv.c          | 479 ++++++++++++++-----
 net/nimble/controller/src/ble_ll_conn.c         |  24 +-
 net/nimble/controller/src/ble_ll_conn_hci.c     |   7 +-
 net/nimble/controller/src/ble_ll_conn_priv.h    |   7 +-
 net/nimble/controller/src/ble_ll_hci.c          | 103 +++-
 net/nimble/controller/src/ble_ll_sched.c        | 185 +++++--
 net/nimble/controller/syscfg.yml                |  11 +-
 net/nimble/include/nimble/ble.h                 |   4 +
 net/nimble/include/nimble/hci_common.h          |   1 +
 net/nimble/include/nimble/hci_vendor.h          | 112 +++++
 net/nimble/syscfg.yml                           |  10 +
 17 files changed, 1268 insertions(+), 207 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/apps/bletest/src/bletest_hci.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/bletest_hci.c b/apps/bletest/src/bletest_hci.c
index fd3985f..528e888 100755
--- a/apps/bletest/src/bletest_hci.c
+++ b/apps/bletest/src/bletest_hci.c
@@ -21,11 +21,13 @@
 #include <string.h>
 #include "os/os.h"
 #include "bsp/bsp.h"
+#include "syscfg/syscfg.h"
 
 /* BLE */
 #include "nimble/ble.h"
 #include "nimble/ble_hci_trans.h"
 #include "nimble/hci_common.h"
+#include "nimble/hci_vendor.h"
 #include "host/ble_hs.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
@@ -361,6 +363,35 @@ bletest_hci_le_rd_max_datalen(void)
     return rc;
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+bletest_hci_le_set_multi_adv_data(uint8_t *data, uint8_t len, uint8_t instance)
+{
+    uint8_t *dst;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_DATA_LEN];
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return -1;
+    }
+
+    dst = buf;
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
+                             BLE_HCI_MULTI_ADV_DATA_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    if (((data == NULL) && (len != 0)) || (len > BLE_HCI_MAX_ADV_DATA_LEN)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    memset(dst, 0, BLE_HCI_MULTI_ADV_DATA_LEN);
+    dst[0] = BLE_HCI_MULTI_ADV_DATA;
+    dst[1] = len;
+    memcpy(dst + 2, data, len);
+    dst[33] = instance;
+
+    return ble_hs_hci_cmd_tx_empty_ack(buf);
+}
+#else
 int
 bletest_hci_le_set_adv_data(uint8_t *data, uint8_t len)
 {
@@ -371,6 +402,7 @@ bletest_hci_le_set_adv_data(uint8_t *data, uint8_t len)
     assert(rc == 0);
     return ble_hs_hci_cmd_tx_empty_ack(buf);
 }
+#endif
 
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
 int
@@ -398,6 +430,68 @@ bletest_hci_le_read_rem_used_feat(uint16_t handle)
     return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+bletest_hci_le_set_multi_adv_params(struct hci_multi_adv_params *adv,
+                                    uint8_t instance)
+{
+    uint8_t *dst;
+    uint16_t itvl;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_PARAMS_LEN];
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return -1;
+    }
+
+    dst = buf;
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
+                             BLE_HCI_MULTI_ADV_PARAMS_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    /* Make sure parameters are valid */
+    if ((adv->adv_itvl_min > adv->adv_itvl_max) ||
+        (adv->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) ||
+        (adv->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) ||
+        (adv->adv_filter_policy > BLE_HCI_ADV_FILT_MAX) ||
+        (adv->adv_type > BLE_HCI_ADV_TYPE_MAX) ||
+        (adv->adv_channel_map == 0) ||
+        ((adv->adv_channel_map & 0xF8) != 0)) {
+        /* These parameters are not valid */
+        return -1;
+    }
+
+    /* Make sure interval is valid for advertising type. */
+    if ((adv->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) ||
+        (adv->adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) {
+        itvl = BLE_HCI_ADV_ITVL_NONCONN_MIN;
+    } else {
+        itvl = BLE_HCI_ADV_ITVL_MIN;
+    }
+
+    /* Do not check if high duty-cycle directed */
+    if (adv->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
+        if ((adv->adv_itvl_min < itvl) ||
+            (adv->adv_itvl_min > BLE_HCI_ADV_ITVL_MAX)) {
+            return -1;
+        }
+    }
+
+    dst[0] = BLE_HCI_MULTI_ADV_PARAMS;
+    htole16(dst + 1, adv->adv_itvl_min);
+    htole16(dst + 3, adv->adv_itvl_max);
+    dst[5] = adv->adv_type;
+    dst[6] = adv->own_addr_type;
+    memcpy(dst + 7, adv->own_addr, BLE_DEV_ADDR_LEN);
+    dst[13] = adv->peer_addr_type;
+    memcpy(dst + 14, adv->peer_addr, BLE_DEV_ADDR_LEN);
+    dst[20] = adv->adv_channel_map;
+    dst[21] = adv->adv_filter_policy;
+    dst[22] = instance;
+    dst[23] = adv->adv_tx_pwr;
+
+    return ble_hs_hci_cmd_tx_empty_ack(buf);
+}
+#else
 int
 bletest_hci_le_set_adv_params(struct hci_adv_params *adv)
 {
@@ -410,12 +504,13 @@ bletest_hci_le_set_adv_params(struct hci_adv_params *adv)
     }
     return rc;
 }
+#endif
 
 int
 bletest_hci_le_set_rand_addr(uint8_t *addr)
 {
     uint8_t *dst;
-    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN];
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN];
 
     dst = buf;
     ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RAND_ADDR,
@@ -426,6 +521,29 @@ bletest_hci_le_set_rand_addr(uint8_t *addr)
     return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+bletest_hci_le_set_multi_rand_addr(uint8_t *addr, uint8_t instance)
+{
+    uint8_t *dst;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN];
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return -1;
+    }
+
+    dst = buf;
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
+                       BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    dst[0] = BLE_HCI_MULTI_ADV_SET_RAND_ADDR;
+    memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
+    dst[7] = instance;
+    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
+}
+#endif
+
 int
 bletest_hci_rd_rem_version(uint16_t handle)
 {
@@ -483,6 +601,28 @@ bletest_hci_le_rd_chanmap(uint16_t handle)
     return rc;
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+bletest_hci_le_set_multi_adv_enable(uint8_t enable, uint8_t instance)
+{
+    uint8_t *dst;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_ENABLE_LEN];
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return -1;
+    }
+
+    dst = buf;
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
+                             BLE_HCI_MULTI_ADV_ENABLE_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    dst[0] = BLE_HCI_MULTI_ADV_ENABLE;
+    dst[1] = enable;
+    dst[2] = instance;
+    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
+}
+#else
 int
 bletest_hci_le_set_adv_enable(uint8_t enable)
 {
@@ -497,6 +637,7 @@ bletest_hci_le_set_adv_enable(uint8_t enable)
     dst[0] = enable;
     return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
 }
+#endif
 
 int
 bletest_hci_le_set_event_mask(uint64_t event_mask)
@@ -516,6 +657,35 @@ bletest_hci_set_event_mask(uint64_t event_mask)
     return ble_hs_hci_cmd_tx_empty_ack(buf);
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+bletest_hci_le_set_multi_scan_rsp_data(uint8_t *data, uint8_t len,
+                                       uint8_t instance)
+{
+    uint8_t *dst;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN];
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return -1;
+    }
+
+    dst = buf;
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
+                             BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    if (((data == NULL) && (len != 0)) || (len>BLE_HCI_MAX_SCAN_RSP_DATA_LEN)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    memset(dst, 0, BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN);
+    dst[0] = BLE_HCI_MULTI_ADV_SCAN_RSP_DATA;
+    dst[1] = len;
+    memcpy(dst + 2, data, len);
+    dst[33] = instance;
+    return ble_hs_hci_cmd_tx_empty_ack(buf);
+}
+#else
 int
 bletest_hci_le_set_scan_rsp_data(uint8_t *data, uint8_t len)
 {
@@ -526,6 +696,7 @@ bletest_hci_le_set_scan_rsp_data(uint8_t *data, uint8_t len)
     assert(rc == 0);
     return ble_hs_hci_cmd_tx_empty_ack(buf);
 }
+#endif
 
 int
 bletest_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/apps/bletest/src/bletest_priv.h
----------------------------------------------------------------------
diff --git a/apps/bletest/src/bletest_priv.h b/apps/bletest/src/bletest_priv.h
index cbb207e..7ecc8df 100644
--- a/apps/bletest/src/bletest_priv.h
+++ b/apps/bletest/src/bletest_priv.h
@@ -45,17 +45,13 @@ int bletest_hci_rd_local_feat(void);
 int bletest_hci_rd_local_supp_cmd(void);
 int bletest_hci_le_read_supp_states(void);
 int bletest_hci_le_rd_max_datalen(void);
-int bletest_hci_le_set_adv_data(uint8_t *data, uint8_t len);
-int bletest_hci_le_set_adv_params(struct hci_adv_params *adv);
 int bletest_hci_le_read_rem_used_feat(uint16_t handle);
 int bletest_hci_le_set_rand_addr(uint8_t *addr);
 int bletest_hci_rd_rem_version(uint16_t handle);
 int bletest_hci_le_set_host_chan_class(uint8_t *chanmap);
 int bletest_hci_le_rd_chanmap(uint16_t handle);
-int bletest_hci_le_set_adv_enable(uint8_t enable);
 int bletest_hci_le_set_event_mask(uint64_t event_mask);
 int bletest_hci_set_event_mask(uint64_t event_mask);
-int bletest_hci_le_set_scan_rsp_data(uint8_t *data, uint8_t len);
 int bletest_hci_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type);
 int bletest_hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dups);
 int bletest_hci_le_create_connection(struct hci_create_conn *hcc);
@@ -66,6 +62,22 @@ int bletest_hci_le_add_resolv_list(uint8_t *local_irk, uint8_t *peer_irk,
                                    uint8_t *peer_ident_addr, uint8_t addr_type);
 int bletest_hci_le_enable_resolv_list(uint8_t enable);
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int bletest_hci_le_set_multi_rand_addr(uint8_t *addr, uint8_t instance);
+int bletest_hci_le_set_multi_adv_data(uint8_t *data, uint8_t len,
+                                      uint8_t instance);
+int bletest_hci_le_set_multi_adv_params(struct hci_multi_adv_params *adv,
+                                        uint8_t instance);
+int bletest_hci_le_set_multi_adv_enable(uint8_t enable, uint8_t instance);
+int bletest_hci_le_set_multi_scan_rsp_data(uint8_t *data, uint8_t len,
+                                           uint8_t instance);
+#else
+int bletest_hci_le_set_adv_data(uint8_t *data, uint8_t len);
+int bletest_hci_le_set_adv_params(struct hci_adv_params *adv);
+int bletest_hci_le_set_adv_enable(uint8_t enable);
+int bletest_hci_le_set_scan_rsp_data(uint8_t *data, uint8_t len);
+#endif
+
 
 #ifdef __cplusplus
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/apps/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c
index dddfcce..6c6cd88 100755
--- a/apps/bletest/src/main.c
+++ b/apps/bletest/src/main.c
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <string.h>
 #include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
 #include "os/os.h"
 #include "bsp/bsp.h"
 #include "hal/hal_bsp.h"
@@ -34,6 +35,7 @@
 #include "nimble/ble.h"
 #include "nimble/ble_hci_trans.h"
 #include "nimble/hci_common.h"
+#include "nimble/hci_vendor.h"
 #include "host/ble_hs.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
@@ -83,6 +85,72 @@ uint8_t g_host_adv_len;
 #define BLETEST_CFG_ADV_FILT_POLICY     (BLE_HCI_ADV_FILT_NONE)
 #define BLETEST_CFG_ADV_ADDR_RES_EN     (0)
 
+/* Multi-adv config */
+/*
+ * Number of advertising instances to start up, not including the default
+ * instance. The default instance is used to connect. If this number is greater
+ * than the number of available advertising instances, we only use the number
+ * of available advertising instances (defined by the configuration setting:
+ * BLE_MULTI_ADV_INSTANCES.
+ */
+#define BLETEST_CFG_ADV_TEST_INSTANCES     (8)
+
+struct bletest_multi_adv_interval
+{
+    uint8_t adv_type;
+    /*
+     * Note: if own addr type greater than 1, we use own addr field; otherwise
+     * we use the set multi random address call to set the random address
+     */
+    uint8_t adv_own_addr_type;
+    uint16_t adv_itvl;
+};
+
+/*
+ * NOTE: currently, these are all NONCONN_IND. Thus, must be 100 msecs or
+ * greater
+ */
+const struct bletest_multi_adv_interval
+bletest_multi_adv_instances[BLETEST_CFG_ADV_TEST_INSTANCES] = {
+    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
+     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
+     (100000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
+     BLE_HCI_ADV_OWN_ADDR_RANDOM,
+     (110000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
+     BLE_HCI_ADV_OWN_ADDR_RANDOM,
+     (120000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
+     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
+     (130000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
+     BLE_HCI_ADV_OWN_ADDR_MAX + 1,
+     (140000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
+     BLE_HCI_ADV_OWN_ADDR_MAX + 1,
+     (150000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
+     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
+     (160000 / BLE_HCI_ADV_ITVL)},
+
+    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
+     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
+     (170000 / BLE_HCI_ADV_ITVL)}
+};
+
+/*
+ * Determines if own address contains random address or set through the
+ * multi-adv set random address command
+ */
+#define BLETEST_CFG_MULTI_ADV_RANDOM_OWN    (0)
+
 /* Scan config */
 #define BLETEST_CFG_SCAN_ITVL           (700000 / BLE_HCI_SCAN_ITVL)
 #define BLETEST_CFG_SCAN_WINDOW         (700000 / BLE_HCI_SCAN_ITVL)
@@ -95,7 +163,7 @@ uint8_t g_host_adv_len;
 #define BLETEST_CFG_CONN_ITVL           (128)  /* in 1.25 msec increments */
 #define BLETEST_CFG_SLAVE_LATENCY       (0)
 #define BLETEST_CFG_INIT_FILTER_POLICY  (BLE_HCI_CONN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_SPVN_TMO       (1000)  /* 20 seconds */
+#define BLETEST_CFG_CONN_SPVN_TMO       (1000)  /* 10 msec increments */
 #define BLETEST_CFG_MIN_CE_LEN          (6)
 #define BLETEST_CFG_MAX_CE_LEN          (BLETEST_CFG_CONN_ITVL)
 #define BLETEST_CFG_CONN_PEER_ADDR_TYPE (BLE_HCI_CONN_PEER_ADDR_PUBLIC)
@@ -294,6 +362,175 @@ bletest_set_adv_data(uint8_t *dptr, uint8_t *addr)
 }
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+void
+bletest_init_adv_instances(void)
+{
+    uint8_t i;
+    int rc;
+    uint8_t *addr;
+    uint8_t adv_len;
+    uint8_t inst_allowed;
+    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
+    struct hci_multi_adv_params adv;
+
+    inst_allowed = MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES);
+    if (inst_allowed > BLETEST_CFG_ADV_TEST_INSTANCES) {
+        inst_allowed = BLETEST_CFG_ADV_TEST_INSTANCES;
+    }
+
+    /* Start up all the instances */
+    for (i = 1; i <= inst_allowed; ++i) {
+        memset(&adv, 0, sizeof(struct hci_multi_adv_params));
+
+        adv.own_addr_type = bletest_multi_adv_instances[i-1].adv_own_addr_type;
+        if (adv.own_addr_type == BLE_HCI_ADV_OWN_ADDR_PUBLIC) {
+            addr = g_dev_addr;
+        } else {
+            memcpy(rand_addr, g_dev_addr, BLE_DEV_ADDR_LEN);
+            rand_addr[5] |= 0xc0;
+            rand_addr[0] = i;
+            /*
+             * NOTE: we overload own address type with a special case
+             * to denote if we use own address or call to set multi random
+             * address.
+             */
+            if (adv.own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+                rc = bletest_hci_le_set_multi_rand_addr(rand_addr, i);
+                assert(rc == 0);
+                addr = rand_addr;
+            } else {
+                adv.own_addr_type = BLE_HCI_ADV_OWN_ADDR_RANDOM;
+                addr = rand_addr;
+                memcpy(adv.own_addr, addr, BLE_DEV_ADDR_LEN);
+            }
+        }
+
+        adv.adv_type = bletest_multi_adv_instances[i - 1].adv_type;
+        adv.adv_channel_map = 0x07;
+        adv.adv_filter_policy = BLE_HCI_ADV_FILT_NONE;
+        adv.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC;
+        adv_len = bletest_set_adv_data(&g_host_adv_data[0], addr);
+
+        adv.adv_itvl_min = bletest_multi_adv_instances[i - 1].adv_itvl;
+        adv.adv_itvl_max = bletest_multi_adv_instances[i - 1].adv_itvl;
+        adv.adv_tx_pwr = -1 * i;
+
+        /* Set the advertising parameters */
+        rc = bletest_hci_le_set_multi_adv_params(&adv, i);
+        assert(rc == 0);
+
+        /* Set advertising data */
+        if (adv_len != 0) {
+            rc = bletest_hci_le_set_multi_adv_data(&g_host_adv_data[0], adv_len,
+                                                   i);
+            assert(rc == 0);
+
+            /* Set scan response data */
+            rc = bletest_hci_le_set_multi_scan_rsp_data(&g_host_adv_data[0],
+                                                        adv_len, i);
+            assert(rc == 0);
+        }
+
+        /* Set the advertising parameters */
+        rc = bletest_hci_le_set_multi_adv_enable(1, i);
+        assert(rc == 0);
+    }
+}
+
+void
+bletest_init_advertising(uint8_t instance, int8_t txpwr)
+{
+    int rc;
+    int set_peer_addr;
+    uint8_t adv_len;
+    uint8_t *addr;
+    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
+    struct hci_multi_adv_params adv;
+
+    /* Make sure it is a valid instance */
+    assert(instance < BLE_LL_ADV_INSTANCES);
+
+    /* Just zero out advertising */
+    set_peer_addr = 0;
+    memset(&adv, 0, sizeof(struct hci_multi_adv_params));
+
+    /* If we are using a random address, we need to set it */
+    adv.own_addr_type = BLETEST_CFG_ADV_OWN_ADDR_TYPE;
+    if (adv.own_addr_type & 1) {
+        memcpy(rand_addr, g_dev_addr, BLE_DEV_ADDR_LEN);
+        rand_addr[5] |= 0xc0;
+        if (BLETEST_CFG_MULTI_ADV_RANDOM_OWN == 1) {
+            addr = rand_addr;
+            memcpy(adv.own_addr, addr, BLE_DEV_ADDR_LEN);
+        } else {
+            rc = bletest_hci_le_set_multi_rand_addr(rand_addr, instance);
+            assert(rc == 0);
+            addr = rand_addr;
+        }
+    } else {
+        addr = g_dev_addr;
+    }
+
+    /* Set advertising parameters */
+    adv.adv_type = BLETEST_CFG_ADV_TYPE;
+    adv.adv_channel_map = 0x07;
+    adv.adv_filter_policy = BLETEST_CFG_ADV_FILT_POLICY;
+    if ((adv.adv_filter_policy & 1) || (BLETEST_CFG_ADV_ADDR_RES_EN == 1)) {
+        set_peer_addr = 1;
+    }
+    adv.peer_addr_type = BLETEST_CFG_ADV_PEER_ADDR_TYPE;
+    if ((adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
+        (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
+        set_peer_addr = 1;
+        adv_len = 0;
+    } else {
+        adv_len = bletest_set_adv_data(&g_host_adv_data[0], addr);
+    }
+
+    /* Not allowed for multi-adv command */
+    if (adv.own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+        assert(0);
+    }
+
+    if (set_peer_addr) {
+        memcpy(adv.peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
+        if (adv.peer_addr_type == BLE_HCI_ADV_PEER_ADDR_RANDOM) {
+            adv.peer_addr[5] |= 0xc0;
+        }
+    }
+
+    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
+                   adv.peer_addr[0], adv.peer_addr[1], adv.peer_addr[2],
+                   adv.peer_addr[3], adv.peer_addr[4], adv.peer_addr[5]);
+
+    if (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
+        adv.adv_itvl_min = 0;
+        adv.adv_itvl_max = 0;
+    } else {
+        adv.adv_itvl_min = BLETEST_CFG_ADV_ITVL;
+        adv.adv_itvl_max = BLETEST_CFG_ADV_ITVL; /* Advertising interval */
+    }
+
+    adv.adv_tx_pwr = txpwr;
+
+    /* Set the advertising parameters */
+    rc = bletest_hci_le_set_multi_adv_params(&adv, instance);
+    assert(rc == 0);
+
+    /* Set advertising data */
+    if (adv_len != 0) {
+        rc = bletest_hci_le_set_multi_adv_data(&g_host_adv_data[0], adv_len,
+                                               instance);
+        assert(rc == 0);
+
+        /* Set scan response data */
+        rc = bletest_hci_le_set_multi_scan_rsp_data(&g_host_adv_data[0],adv_len,
+                                                    instance);
+        assert(rc == 0);
+    }
+}
+#else
 void
 bletest_init_advertising(void)
 {
@@ -387,7 +624,8 @@ bletest_init_advertising(void)
         assert(rc == 0);
     }
 }
-#endif
+#endif  /* MULTI_ADV SUPPORT */
+#endif  /* BLETEST_ROLE_ADVERTISER */
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
 void
@@ -733,13 +971,22 @@ bletest_execute_advertiser(void)
                 /* restart initiating */
                 g_bletest_cur_peer_addr[5] += 1;
                 g_dev_addr[5] += 1;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+                bletest_init_advertising(0,0);
+                bletest_hci_le_set_multi_adv_enable(1, 0);
+#else
                 bletest_init_advertising();
                 bletest_hci_le_set_adv_enable(1);
+#endif
             }
         } else {
             /* If we failed to start advertising we should keep trying */
             if (ble_ll_adv_enabled() == 0) {
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+                bletest_hci_le_set_multi_adv_enable(1, 0);
+#else
                 bletest_hci_le_set_adv_enable(1);
+#endif
             }
         }
     }
@@ -817,7 +1064,7 @@ bletest_execute_advertiser(void)
     }
 #endif /* XXX: throughput test */
 }
-#endif
+#endif /* XXX: BLETEST_ROLE_ADVERTISER */
 
 /**
  * Main bletest function. Called by the task timer every 50 msecs.
@@ -888,8 +1135,16 @@ bletest_task_handler(void *arg)
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
     /* Initialize the advertiser */
     console_printf("Starting BLE test task as advertiser\n");
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    /* Start up all advertising instances except default one */
+    bletest_init_adv_instances();
+
+    /* Start advertising on instance 0 at 0 dbm */
+    bletest_init_advertising(0, 0);
+#else
     bletest_init_advertising();
 #endif
+#endif
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
     /* Initialize the scanner */
@@ -985,9 +1240,14 @@ bletest_task_handler(void *arg)
 
     /* Begin advertising if we are an advertiser */
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    rc = bletest_hci_le_set_multi_adv_enable(1, 0);
+    assert(rc == 0);
+#else
     rc = bletest_hci_le_set_adv_enable(1);
     assert(rc == 0);
 #endif
+#endif
 
     bletest_timer_cb(NULL);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/hw/drivers/nimble/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/hw/drivers/nimble/nrf52/src/ble_phy.c b/hw/drivers/nimble/nrf52/src/ble_phy.c
index 5d41322..92941f2 100644
--- a/hw/drivers/nimble/nrf52/src/ble_phy.c
+++ b/hw/drivers/nimble/nrf52/src/ble_phy.c
@@ -376,7 +376,7 @@ ble_phy_tx_end_isr(void)
     assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
 
     /* Log the event */
-    ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_tx_buf[0] >> 8) & 0xFF,
+    ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len,
                was_encrypted, txstart);
 
     /* Clear events and clear interrupt on disabled event */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/include/controller/ble_ll_adv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_adv.h b/net/nimble/controller/include/controller/ble_ll_adv.h
index 74eabdf..298f4bf 100644
--- a/net/nimble/controller/include/controller/ble_ll_adv.h
+++ b/net/nimble/controller/include/controller/ble_ll_adv.h
@@ -20,10 +20,15 @@
 #ifndef H_BLE_LL_ADV_
 #define H_BLE_LL_ADV_
 
+#include "syscfg/syscfg.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* The number of advertising instances */
+#define BLE_LL_ADV_INSTANCES    (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES + 1)
+
 /*
  * ADV event timing
  *      T_advEvent = advInterval + advDelay
@@ -101,34 +106,43 @@ extern "C" {
 #define BLE_ADV_SCAN_IND_MAX_LEN        (37)
 
 /*---- HCI ----*/
+struct ble_ll_adv_sm;
+struct ble_ll_conn_sm;
+
 /* Start an advertiser */
 int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type,
                          uint8_t *init_addr, uint16_t adv_itvl, void *handle);
 
 /* Start or stop advertising */
-int ble_ll_adv_set_enable(uint8_t *cmd);
+int ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance);
 
 /* Set advertising data */
-int ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t len);
+int ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance);
 
 /* Set scan response data */
-int ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len);
+int ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance);
 
 /* Set advertising parameters */
-int ble_ll_adv_set_adv_params(uint8_t *cmd);
+int ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi);
 
 /* Read advertising channel power */
 int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen);
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int ble_ll_adv_multi_adv_cmd(uint8_t *cmd, uint8_t cmdlen, uint8_t *rspbuf,
+                             uint8_t *rsplen);
+#endif
+
 /*---- API used by BLE LL ----*/
-/* Returns the event allocated to send the connection complete event */
-uint8_t *ble_ll_adv_get_conn_comp_ev(void);
+/* Send the connection complete event */
+void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
+                                  struct ble_mbuf_hdr *rxhdr);
 
 /* Returns local resolvable private address */
-uint8_t *ble_ll_adv_get_local_rpa(void);
+uint8_t *ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm);
 
 /* Returns peer resolvable private address */
-uint8_t *ble_ll_adv_get_peer_rpa(void);
+uint8_t *ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm);
 
 /* Called to initialize advertising functionality. */
 void ble_ll_adv_init(void);
@@ -136,9 +150,6 @@ void ble_ll_adv_init(void);
 /* Called when LL wait for response timer expires in advertising state */
 void ble_ll_adv_wfr_timer_exp(void);
 
-/* Called to initialize advertising functionality. */
-void ble_ll_adv_init(void);
-
 /* Called to reset the advertiser. */
 void ble_ll_adv_reset(void);
 
@@ -155,14 +166,17 @@ void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
 /* Boolean function denoting whether or not the whitelist can be changed */
 int ble_ll_adv_can_chg_whitelist(void);
 
-/* Called when a connection request has been received at the link layer */
-int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr);
-
 /* Called when an advertising event has been scheduled */
-void ble_ll_adv_scheduled(uint32_t sch_start);
+void ble_ll_adv_scheduled(struct ble_ll_adv_sm *, uint32_t sch_start);
+
+/*
+ * Called when an advertising event has been removed from the scheduler
+ * without being run.
+ */
+void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
 
 /* Called to halt currently running advertising event */
-void ble_ll_adv_halt(void);
+void ble_ll_adv_halt(struct ble_ll_adv_sm *advsm);
 
 /* Called to determine if advertising is enabled */
 uint8_t ble_ll_adv_enabled(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/include/controller/ble_ll_sched.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_sched.h b/net/nimble/controller/include/controller/ble_ll_sched.h
index cda4f40..3a05cfe 100644
--- a/net/nimble/controller/include/controller/ble_ll_sched.h
+++ b/net/nimble/controller/include/controller/ble_ll_sched.h
@@ -28,6 +28,25 @@ extern "C" {
 #define BLE_LL_SCHED_USECS_PER_SLOT (1250)
 
 /*
+ * Worst case time needed for scheduled advertising item. This is the longest
+ * possible time to receive a scan request and send a scan response (with the
+ * appropriate IFS time between them). This number is calculated using the
+ * following formula: IFS + SCAN_REQ + IFS + SCAN_RSP = 150 + 176 + 150 + 376.
+ * Note: worst case time to tx adv, rx scan req and send scan rsp is 1228 usecs.
+ * This assumes maximum sized advertising PDU and scan response PDU.
+ *
+ * For connectable advertising events no scan request is allowed. In this case
+ * we just need to receive a connect request PDU: IFS + CONNECT_REQ = 150 + 352.
+ * Note: worst-case is 376 + 150 + 352 = 878 usecs
+ *
+ * NOTE: The advertising PDU transmit time is NOT included here since we know
+ * how long that will take (worst-case is 376 usecs).
+ */
+#define BLE_LL_SCHED_ADV_MAX_USECS          (852)
+#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS   (502)
+#define BLE_LL_SCHED_MAX_ADV_PDU_USECS      (376)
+
+/*
  * This is the number of slots needed to transmit and receive a maximum
  * size PDU, including an IFS time before each. The actual time is
  * 2120 usecs for tx/rx and 150 for IFS = 4540 usecs.
@@ -85,7 +104,11 @@ int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
 int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch);
 
 /* Reschedule an advertising event */
-int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch);
+int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
+                                uint32_t max_delay_ticks);
+
+/* Reschedule and advertising pdu */
+int ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch);
 
 /* Reschedule a connection that had previously been scheduled or that is over */
 int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_adv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c
index 61a2291..0b7b470 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -27,10 +27,12 @@
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
+#include "nimble/hci_vendor.h"
 #include "nimble/ble_hci_trans.h"
 #include "controller/ble_phy.h"
 #include "controller/ble_hw.h"
 #include "controller/ble_ll.h"
+#include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_adv.h"
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_scan.h"
@@ -69,7 +71,8 @@
  */
 struct ble_ll_adv_sm
 {
-    uint8_t enabled;
+    uint8_t adv_enabled;
+    uint8_t adv_instance;
     uint8_t adv_type;
     uint8_t adv_len;
     uint8_t adv_chanmask;
@@ -83,6 +86,7 @@ struct ble_ll_adv_sm
     uint8_t adv_directed;           /* note: can be 1 bit */
     uint8_t adv_txadd;              /* note: can be 1 bit */
     uint8_t adv_rxadd;              /* note: can be 1 bit */
+    int8_t adv_txpwr;
     uint16_t adv_itvl_min;
     uint16_t adv_itvl_max;
     uint32_t adv_itvl_usecs;
@@ -99,31 +103,17 @@ struct ble_ll_adv_sm
     uint8_t *conn_comp_ev;
     struct os_event adv_txdone_ev;
     struct ble_ll_sched_item adv_sch;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    uint8_t adv_random_addr[BLE_DEV_ADDR_LEN];
+#endif
 };
 
 /* The advertising state machine global object */
-struct ble_ll_adv_sm g_ble_ll_adv_sm;
+struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_LL_ADV_INSTANCES];
+struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm;
 
 static void ble_ll_adv_done(struct ble_ll_adv_sm *advsm);
 
-/*
- * Worst case time needed for scheduled advertising item. This is the longest
- * possible time to receive a scan request and send a scan response (with the
- * appropriate IFS time between them). This number is calculated using the
- * following formula: IFS + SCAN_REQ + IFS + SCAN_RSP = 150 + 176 + 150 + 376.
- * Note: worst case time to tx adv, rx scan req and send scan rsp is 1228 usecs.
- * This assumes maximum sized advertising PDU and scan response PDU.
- *
- * For connectable advertising events no scan request is allowed. In this case
- * we just need to receive a connect request PDU: IFS + CONNECT_REQ = 150 + 352.
- * Note: worst-case is 376 + 150 + 352 = 878 usecs
- *
- * NOTE: The advertising PDU transmit time is NOT included here since we know
- * how long that will take (worst-case is 376 usecs).
- */
-#define BLE_LL_ADV_SCHED_MAX_USECS          (852)
-#define BLE_LL_ADV_DIRECT_SCHED_MAX_USECS   (502)
-
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
 /**
  * Called to change advertisers ADVA and INITA (for directed advertisements)
@@ -209,6 +199,30 @@ ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm)
 }
 
 /**
+ * Calculate the final channel that we should advertise upon when we start
+ * an advertising event.
+ *
+ * @param advsm
+ *
+ * @return uint8_t The number of the final channel usable for advertising.
+ */
+static uint8_t
+ble_ll_adv_final_chan(struct ble_ll_adv_sm *advsm)
+{
+    uint8_t adv_chan;
+
+    if (advsm->adv_chanmask & 0x04) {
+        adv_chan = BLE_PHY_ADV_CHAN_START + 2;
+    } else if (advsm->adv_chanmask & 0x02) {
+        adv_chan = BLE_PHY_ADV_CHAN_START + 1;
+    } else {
+        adv_chan = BLE_PHY_ADV_CHAN_START;
+    }
+
+    return adv_chan;
+}
+
+/**
  * Create the advertising PDU
  *
  * @param advsm Pointer to advertisement state machine
@@ -353,12 +367,34 @@ ble_ll_adv_tx_done(void *arg)
 {
     struct ble_ll_adv_sm *advsm;
 
+    /* XXX: for now, reset power to max after advertising */
+    ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
+
     advsm = (struct ble_ll_adv_sm *)arg;
     os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
 
-    ble_ll_log(BLE_LL_LOG_ID_ADV_TXDONE, ble_ll_state_get(), 0, 0);
+    ble_ll_log(BLE_LL_LOG_ID_ADV_TXDONE, ble_ll_state_get(),
+               advsm->adv_instance, 0);
 
     ble_ll_state_set(BLE_LL_STATE_STANDBY);
+
+    /* We no longer have a current state machine */
+    g_ble_ll_cur_adv_sm = NULL;
+}
+
+/*
+ * Called when an advertising event has been removed from the scheduler
+ * without being run.
+ */
+void
+ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm)
+{
+    /*
+     * Need to set advertising channel to final chan so new event gets
+     * scheduled.
+     */
+    advsm->adv_chan = ble_ll_adv_final_chan(advsm);
+    os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
 }
 
 /**
@@ -383,6 +419,12 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
     /* Get the state machine for the event */
     advsm = (struct ble_ll_adv_sm *)sch->cb_arg;
 
+    /* Set the current advertiser */
+    g_ble_ll_cur_adv_sm = advsm;
+
+    /* Set the power */
+    ble_phy_txpwr_set(advsm->adv_txpwr);
+
     /* Set channel */
     rc = ble_phy_setchan(advsm->adv_chan, 0, 0);
     assert(rc == 0);
@@ -471,11 +513,11 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
     switch (advsm->adv_type) {
     case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
     case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
-        max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS;
+        max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS;
         break;
     case BLE_HCI_ADV_TYPE_ADV_IND:
     case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
-        max_usecs += BLE_LL_ADV_SCHED_MAX_USECS;
+        max_usecs += BLE_LL_SCHED_ADV_MAX_USECS;
         break;
     default:
         break;
@@ -508,11 +550,12 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
  * and is only called when a scheduled item executes but advertising is still
  * running.
  *
+ * Context: Interrupt
  */
 void
-ble_ll_adv_halt(void)
+ble_ll_adv_halt(struct ble_ll_adv_sm *advsm)
 {
-    ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
+    ble_ll_adv_tx_done(advsm);
 }
 
 /**
@@ -526,24 +569,36 @@ ble_ll_adv_halt(void)
  * @return int
  */
 int
-ble_ll_adv_set_adv_params(uint8_t *cmd)
+ble_ll_adv_set_adv_params(uint8_t *cmd, uint8_t instance, int is_multi)
 {
     uint8_t adv_type;
     uint8_t adv_filter_policy;
     uint8_t adv_chanmask;
     uint8_t own_addr_type;
     uint8_t peer_addr_type;
+    uint8_t offset;
     uint16_t adv_itvl_min;
     uint16_t adv_itvl_max;
     uint16_t min_itvl;
     struct ble_ll_adv_sm *advsm;
 
     /* If already enabled, we return an error */
-    advsm = &g_ble_ll_adv_sm;
-    if (advsm->enabled) {
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    advsm = &g_ble_ll_adv_sm[instance];
+    if (advsm->adv_enabled) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
+    /* Add offset if this is a multi-advertising command */
+    if (is_multi) {
+        offset = 6;
+    } else {
+        offset = 0;
+    }
+
     /* Make sure intervals are OK (along with advertising type */
     adv_itvl_min = le16toh(cmd);
     adv_itvl_max = le16toh(cmd + 2);
@@ -553,7 +608,7 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
      * Get the filter policy now since we will ignore it if we are doing
      * directed advertising
      */
-    adv_filter_policy = cmd[14];
+    adv_filter_policy = cmd[14 + offset];
 
     /* Assume min interval based on low duty cycle/indirect advertising */
     min_itvl = BLE_LL_ADV_ITVL_MIN;
@@ -580,6 +635,7 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
         min_itvl = BLE_LL_ADV_ITVL_NONCONN_MIN;
         break;
     default:
+        /* This will cause an invalid parameter error */
         min_itvl = 0xFFFF;
         break;
     }
@@ -593,17 +649,44 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
 
     /* Check own and peer address type */
     own_addr_type =  cmd[5];
-    peer_addr_type = cmd[6];
+    peer_addr_type = cmd[6 + offset];
 
     if ((own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) ||
         (peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
+    /* Deal with multi-advertising command specific*/
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    if (is_multi) {
+        /* Get and check advertising power */
+        advsm->adv_txpwr = cmd[22];
+        if (advsm->adv_txpwr > 20) {
+            return BLE_ERR_INV_HCI_CMD_PARMS;
+        }
+
+        /* Get own address if it is there. */
+        if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+            return BLE_ERR_INV_HCI_CMD_PARMS;
+        } else {
+            if (own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+                /* Use this random address if set in own address */
+                if (ble_ll_is_valid_random_addr(cmd + 6)) {
+                    memcpy(advsm->adv_random_addr, cmd + 6, BLE_DEV_ADDR_LEN);
+                }
+            }
+        }
+    } else {
+        advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
+    }
+#else
+    advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
+#endif
+
 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
         /* Copy peer address */
-        memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN);
+        memcpy(advsm->peer_addr, cmd + 7 + offset, BLE_DEV_ADDR_LEN);
 
         /* Reset RPA timer so we generate a new RPA */
         advsm->adv_rpa_timer = os_time_get();
@@ -616,7 +699,7 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
 #endif
 
     /* There are only three adv channels, so check for any outside the range */
-    adv_chanmask = cmd[13];
+    adv_chanmask = cmd[13 + offset];
     if (((adv_chanmask & 0xF8) != 0) || (adv_chanmask == 0)) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
@@ -650,7 +733,7 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
 {
     os_sr_t sr;
 
-    if (advsm->enabled) {
+    if (advsm->adv_enabled) {
         /* Remove any scheduled advertising items */
         ble_ll_sched_rmv_elem(&advsm->adv_sch);
 
@@ -672,7 +755,7 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
         }
 
         /* Disable advertising */
-        advsm->enabled = 0;
+        advsm->adv_enabled = 0;
     }
 }
 
@@ -702,9 +785,15 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
      * is why I chose command disallowed.
      */
     if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+        if (!ble_ll_is_valid_random_addr(advsm->adv_random_addr)) {
+            return BLE_ERR_CMD_DISALLOWED;
+        }
+#else
         if (!ble_ll_is_valid_random_addr(g_random_addr)) {
             return BLE_ERR_CMD_DISALLOWED;
         }
+#endif
     }
 
     /*
@@ -733,7 +822,11 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
         addr = g_dev_addr;
         advsm->adv_txadd = 0;
     } else {
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+        addr = advsm->adv_random_addr;
+#else
         addr = g_random_addr;
+#endif
         advsm->adv_txadd = 1;
     }
     memcpy(advsm->adva, addr, BLE_DEV_ADDR_LEN);
@@ -753,7 +846,7 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
 #endif
 
     /* Set flag telling us that advertising is enabled */
-    advsm->enabled = 1;
+    advsm->adv_enabled = 1;
 
     /* Determine the advertising interval we will use */
     if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
@@ -779,12 +872,8 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
 }
 
 void
-ble_ll_adv_scheduled(uint32_t sch_start)
+ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start)
 {
-    struct ble_ll_adv_sm *advsm;
-
-    advsm = &g_ble_ll_adv_sm;
-
     /* The event start time is when we start transmission of the adv PDU */
     advsm->adv_event_start_time = sch_start +
         os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
@@ -826,19 +915,23 @@ ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen)
  * @return int
  */
 int
-ble_ll_adv_set_enable(uint8_t *cmd)
+ble_ll_adv_set_enable(uint8_t *cmd, uint8_t instance)
 {
     int rc;
     uint8_t enable;
     struct ble_ll_adv_sm *advsm;
 
-    advsm = &g_ble_ll_adv_sm;
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    advsm = &g_ble_ll_adv_sm[instance];
 
-    rc = 0;
+    rc = BLE_ERR_SUCCESS;
     enable = cmd[0];
     if (enable == 1) {
         /* If already enabled, do nothing */
-        if (!advsm->enabled) {
+        if (!advsm->adv_enabled) {
             /* Start the advertising state machine */
             rc = ble_ll_adv_sm_start(advsm);
         }
@@ -860,7 +953,7 @@ ble_ll_adv_set_enable(uint8_t *cmd)
  * @return int
  */
 int
-ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
+ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t instance)
 {
     uint8_t datalen;
     struct ble_ll_adv_sm *advsm;
@@ -871,12 +964,16 @@ ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
     /* Copy the new data into the advertising structure. */
-    advsm = &g_ble_ll_adv_sm;
+    advsm = &g_ble_ll_adv_sm[instance];
     advsm->scan_rsp_len = datalen;
     memcpy(advsm->scan_rsp_data, cmd + 1, datalen);
 
-    return 0;
+    return BLE_ERR_SUCCESS;
 }
 
 /**
@@ -889,7 +986,7 @@ ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
  * @return int 0: success; BLE_ERR_INV_HCI_CMD_PARMS otherwise.
  */
 int
-ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t len)
+ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t instance)
 {
     uint8_t datalen;
     struct ble_ll_adv_sm *advsm;
@@ -900,14 +997,93 @@ ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t len)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
     /* Copy the new data into the advertising structure. */
-    advsm = &g_ble_ll_adv_sm;
+    advsm = &g_ble_ll_adv_sm[instance];
     advsm->adv_len = datalen;
     memcpy(advsm->adv_data, cmd + 1, datalen);
 
-    return 0;
+    return BLE_ERR_SUCCESS;
 }
 
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+int
+ble_ll_adv_set_random_addr(uint8_t *addr, uint8_t instance)
+{
+    struct ble_ll_adv_sm *advsm;
+
+    if (instance >= BLE_LL_ADV_INSTANCES) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+    advsm = &g_ble_ll_adv_sm[instance];
+    memcpy(advsm->adv_random_addr, addr, BLE_DEV_ADDR_LEN);
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Process the multi-advertising command
+ *
+ * NOTE: the command length was already checked to make sure it is non-zero.
+ *
+ * @param cmdbuf    Pointer to command buffer
+ * @param cmdlen    The length of the command data
+ * @param rspbuf    Pointer to response buffer
+ * @param rsplen    Pointer to response length
+ *
+ * @return int
+ */
+int
+ble_ll_adv_multi_adv_cmd(uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf,
+                         uint8_t *rsplen)
+{
+    int rc;
+    uint8_t subcmd;
+
+    /* NOTE: the command length includes the sub command byte */
+    rc = BLE_ERR_INV_HCI_CMD_PARMS;
+    subcmd = cmdbuf[0];
+    ++cmdbuf;
+    switch (subcmd) {
+    case BLE_HCI_MULTI_ADV_PARAMS:
+        if (cmdlen == BLE_HCI_MULTI_ADV_PARAMS_LEN) {
+            rc = ble_ll_adv_set_adv_params(cmdbuf, cmdbuf[21], 1);
+        }
+        break;
+    case BLE_HCI_MULTI_ADV_DATA:
+        if (cmdlen == BLE_HCI_MULTI_ADV_DATA_LEN) {
+            rc = ble_ll_adv_set_adv_data(cmdbuf, cmdbuf[32]);
+        }
+        break;
+    case BLE_HCI_MULTI_ADV_SCAN_RSP_DATA:
+        if (cmdlen == BLE_HCI_MULTI_ADV_SCAN_RSP_DATA_LEN) {
+            rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, cmdbuf[32]);
+        }
+        break;
+    case BLE_HCI_MULTI_ADV_SET_RAND_ADDR:
+        if (cmdlen == BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN) {
+            rc = ble_ll_adv_set_random_addr(cmdbuf, cmdbuf[6]);
+        }
+        break;
+    case BLE_HCI_MULTI_ADV_ENABLE:
+        if (cmdlen == BLE_HCI_MULTI_ADV_ENABLE_LEN) {
+            rc = ble_ll_adv_set_enable(cmdbuf, cmdbuf[1]);
+        }
+        break;
+    default:
+        rc = BLE_ERR_UNKNOWN_HCI_CMD;
+        break;
+    }
+
+    rspbuf[0] = subcmd;
+    *rsplen = 1;
+
+    return rc;
+}
+#endif
+
 /**
  * Called when the LL receives a scan request or connection request
  *
@@ -935,7 +1111,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
     struct os_mbuf *scan_rsp;
 
     /* See if adva in the request (scan or connect) matches what we sent */
-    advsm = &g_ble_ll_adv_sm;
+    advsm = g_ble_ll_cur_adv_sm;
     rxbuf = rxpdu->om_data;
     adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
     if (memcmp(advsm->adva, adva, BLE_DEV_ADDR_LEN)) {
@@ -995,7 +1171,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
         scan_rsp = ble_ll_adv_scan_rsp_pdu_make(advsm);
         if (scan_rsp) {
-            ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
+            ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
             rc = ble_phy_tx(scan_rsp, BLE_PHY_TRANSITION_NONE);
             if (!rc) {
                 ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
@@ -1018,8 +1194,9 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
  *
  * @return 0: no connection started. 1: connection started
  */
-int
-ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
+static int
+ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr,
+                        struct ble_ll_adv_sm *advsm)
 {
     int valid;
     uint8_t pyld_len;
@@ -1030,14 +1207,12 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
     uint8_t *inita;
     uint8_t *ident_addr;
     uint32_t endtime;
-    struct ble_ll_adv_sm *advsm;
 
     /* Check filter policy. */
     valid = 0;
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
     resolved = BLE_MBUF_HDR_RESOLVED(hdr);
 #endif
-    advsm = &g_ble_ll_adv_sm;
     inita = rxbuf + BLE_LL_PDU_HDR_LEN;
     if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) {
 
@@ -1092,7 +1267,7 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
         /* Try to start slave connection. If successful, stop advertising */
         pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
         endtime = hdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len);
-        valid = ble_ll_conn_slave_start(rxbuf, endtime, addr_type);
+        valid = ble_ll_conn_slave_start(rxbuf, endtime, addr_type, hdr);
         if (valid) {
             ble_ll_adv_sm_stop(advsm);
         }
@@ -1126,11 +1301,18 @@ int
 ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok)
 {
     int rc;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    struct ble_mbuf_hdr *rxhdr;
+#endif
 
     rc = -1;
     if (rxpdu == NULL) {
-        ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
+        ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm);
     } else {
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+        rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
+        rxhdr->rxinfo.advsm = g_ble_ll_cur_adv_sm;
+#endif
         if (crcok) {
             if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
                 (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
@@ -1138,6 +1320,11 @@ ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok)
                 rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
             }
         }
+
+        if (rc) {
+            /* We no longer have a current state machine */
+            g_ble_ll_cur_adv_sm = NULL;
+        }
     }
 
     if (rc) {
@@ -1164,13 +1351,20 @@ void
 ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
 {
     int adv_event_over;
+    struct ble_ll_adv_sm *advsm;
+
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    advsm = (struct ble_ll_adv_sm *)hdr->rxinfo.advsm;
+#else
+    advsm = &g_ble_ll_adv_sm[0];
+#endif
 
     /*
      * It is possible that advertising was stopped and a packet plcaed on the
      * LL receive packet queue. In this case, just ignore the received packet
      * as the advertising state machine is no longer "valid"
      */
-    if (!g_ble_ll_adv_sm.enabled) {
+    if (!advsm->adv_enabled) {
         return;
     }
 
@@ -1184,7 +1378,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
     adv_event_over = 1;
     if (BLE_MBUF_HDR_CRC_OK(hdr)) {
         if (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
-            if (ble_ll_adv_conn_req_rxd(rxbuf, hdr)) {
+            if (ble_ll_adv_conn_req_rxd(rxbuf, hdr, advsm)) {
                 adv_event_over = 0;
             }
         } else {
@@ -1196,7 +1390,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
     }
 
     if (adv_event_over) {
-        ble_ll_adv_done(&g_ble_ll_adv_sm);
+        ble_ll_adv_done(advsm);
     }
 }
 
@@ -1223,7 +1417,7 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type)
     rc = -1;
 
     /* If we get a scan request we must tell the phy to go from rx to tx */
-    advsm = &g_ble_ll_adv_sm;
+    advsm = g_ble_ll_cur_adv_sm;
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
         /* Only accept scan requests if we are indirect adv or scan adv */
         if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND) ||
@@ -1262,13 +1456,17 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type)
 static void
 ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
 {
+    int rc;
+    int resched_pdu;
     uint8_t mask;
     uint8_t final_adv_chan;
     int32_t delta_t;
     uint32_t itvl;
+    uint32_t tick_itvl;
     uint32_t start_time;
+    uint32_t max_delay_ticks;
 
-    assert(advsm->enabled);
+    assert(advsm->adv_enabled);
 
     /* Remove the element from the schedule if it is still there. */
     ble_ll_sched_rmv_elem(&advsm->adv_sch);
@@ -1279,13 +1477,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
      * packet was sent on the last channel, it means we are done with this
      * event.
      */
-    if (advsm->adv_chanmask & 0x04) {
-        final_adv_chan = BLE_PHY_ADV_CHAN_START + 2;
-    } else if (advsm->adv_chanmask & 0x02) {
-        final_adv_chan = BLE_PHY_ADV_CHAN_START + 1;
-    } else {
-        final_adv_chan = BLE_PHY_ADV_CHAN_START;
-    }
+    final_adv_chan = ble_ll_adv_final_chan(advsm);
 
     if (advsm->adv_chan == final_adv_chan) {
         /* Check if we need to resume scanning */
@@ -1294,12 +1486,19 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
         /* This event is over. Set adv channel to first one */
         advsm->adv_chan = ble_ll_adv_first_chan(advsm);
 
-        /* Calculate start time of next advertising event */
+        /*
+         * Calculate start time of next advertising event. NOTE: we do not
+         * add the random advDelay as the scheduling code will do that.
+         */
         itvl = advsm->adv_itvl_usecs;
         if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
-            itvl += rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000);
+            max_delay_ticks =
+                os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000);
+        } else {
+            max_delay_ticks = 0;
         }
-        advsm->adv_event_start_time += os_cputime_usecs_to_ticks(itvl);
+        tick_itvl = os_cputime_usecs_to_ticks(itvl);
+        advsm->adv_event_start_time += tick_itvl;
         advsm->adv_pdu_start_time = advsm->adv_event_start_time;
 
         /*
@@ -1311,18 +1510,17 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
 
         delta_t = (int32_t)(start_time - os_cputime_get32());
         if (delta_t < 0) {
-            /* Calculate start time of next advertising event */
+            /*
+             * NOTE: we just the same interval that we calculated earlier.
+             * No real need to keep recalculating a new interval.
+             */
             while (delta_t < 0) {
-                itvl = advsm->adv_itvl_usecs;
-                if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
-                    itvl += rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000);
-                }
-                itvl = os_cputime_usecs_to_ticks(itvl);
-                advsm->adv_event_start_time += itvl;
+                advsm->adv_event_start_time += tick_itvl;
                 advsm->adv_pdu_start_time = advsm->adv_event_start_time;
-                delta_t += (int32_t)itvl;
+                delta_t += (int32_t)tick_itvl;
             }
         }
+        resched_pdu = 0;
     } else {
         /*
          * Move to next advertising channel. If not in the mask, just
@@ -1341,6 +1539,8 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
          */
         advsm->adv_pdu_start_time = os_cputime_get32() +
             os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+
+        resched_pdu = 1;
     }
 
     /*
@@ -1350,9 +1550,9 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
     if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
         if (advsm->adv_pdu_start_time >= advsm->adv_dir_hd_end_time) {
             /* Disable advertising */
-            advsm->enabled = 0;
+            advsm->adv_enabled = 0;
             ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO,
-                                        advsm->conn_comp_ev);
+                                        advsm->conn_comp_ev, advsm);
             advsm->conn_comp_ev = NULL;
             ble_ll_scan_chk_resume();
             return;
@@ -1371,7 +1571,19 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
      * In the unlikely event we cant reschedule this, just post a done
      * event and we will reschedule the next advertising event
      */
-    if (ble_ll_sched_adv_reschedule(&advsm->adv_sch)) {
+    if (resched_pdu) {
+        rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch);
+    } else {
+        rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time,
+                                         max_delay_ticks);
+        if (!rc) {
+            advsm->adv_event_start_time = start_time;
+            advsm->adv_pdu_start_time = start_time;
+        }
+    }
+
+    if (rc) {
+        advsm->adv_chan = final_adv_chan;
         os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
     }
 }
@@ -1395,31 +1607,64 @@ ble_ll_adv_can_chg_whitelist(void)
     int rc;
     struct ble_ll_adv_sm *advsm;
 
-    advsm = &g_ble_ll_adv_sm;
-    if (advsm->enabled && (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) {
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    int i;
+
+    rc = 1;
+    for (i = 0; i < BLE_LL_ADV_INSTANCES; ++i) {
+        advsm = &g_ble_ll_adv_sm[i];
+        if (advsm->adv_enabled &&
+            (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) {
+            rc = 0;
+            break;
+        }
+    }
+#else
+    advsm = &g_ble_ll_adv_sm[0];
+    if (advsm->adv_enabled &&
+        (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) {
         rc = 0;
     } else {
         rc = 1;
     }
+#endif
 
     return rc;
 }
 
 /**
- * Returns the event allocated to send the connection complete event
+ * Sends the connection complete event when advertising a connection starts.
  *
  * @return uint8_t* Pointer to event buffer
  */
-uint8_t *
-ble_ll_adv_get_conn_comp_ev(void)
+void
+ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
+                             struct ble_mbuf_hdr *rxhdr)
 {
     uint8_t *evbuf;
+    struct ble_ll_adv_sm *advsm;
 
-    evbuf = g_ble_ll_adv_sm.conn_comp_ev;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    advsm = (struct ble_ll_adv_sm *)rxhdr->rxinfo.advsm;
+    evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+    if (evbuf) {
+        evbuf[0] = BLE_HCI_EVCODE_LE_META;
+        evbuf[1] = 5;   /* Length of event, including sub-event code */
+        evbuf[2] = BLE_HCI_LE_SUBEV_ADV_STATE_CHG;
+        evbuf[3] = advsm->adv_instance;
+        evbuf[4] = 0x00;    /* status code */
+        htole16(evbuf + 5, connsm->conn_handle);
+        ble_ll_hci_event_send(evbuf);
+    }
+#else
+    advsm = &g_ble_ll_adv_sm[0];
+#endif
+
+    evbuf = advsm->conn_comp_ev;
     assert(evbuf != NULL);
-    g_ble_ll_adv_sm.conn_comp_ev = NULL;
+    advsm->conn_comp_ev = NULL;
 
-    return evbuf;
+    ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm);
 }
 
 /**
@@ -1429,12 +1674,9 @@ ble_ll_adv_get_conn_comp_ev(void)
  * @return uint8_t*
  */
 uint8_t *
-ble_ll_adv_get_local_rpa(void)
+ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm)
 {
     uint8_t *rpa;
-    struct ble_ll_adv_sm *advsm;
-
-    advsm = &g_ble_ll_adv_sm;
 
     rpa = NULL;
     if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
@@ -1450,12 +1692,8 @@ ble_ll_adv_get_local_rpa(void)
  * @return uint8_t*
  */
 uint8_t *
-ble_ll_adv_get_peer_rpa(void)
+ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm)
 {
-    struct ble_ll_adv_sm *advsm;
-
-    advsm = &g_ble_ll_adv_sm;
-
     /* XXX: should this go into IRK list or connection? */
     return advsm->adv_rpa;
 }
@@ -1469,7 +1707,7 @@ void
 ble_ll_adv_wfr_timer_exp(void)
 {
     ble_phy_disable();
-    ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
+    ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm);
 }
 
 /**
@@ -1481,21 +1719,27 @@ ble_ll_adv_wfr_timer_exp(void)
 void
 ble_ll_adv_reset(void)
 {
+    int i;
     struct ble_ll_adv_sm *advsm;
-    advsm = &g_ble_ll_adv_sm;
 
-    /* Stop advertising state machine */
-    ble_ll_adv_sm_stop(advsm);
+    for (i = 0; i < BLE_LL_ADV_INSTANCES; ++i) {
+        /* Stop advertising state machine */
+        advsm = &g_ble_ll_adv_sm[i];
+        ble_ll_adv_sm_stop(advsm);
+    }
 
     /* re-initialize the advertiser state machine */
     ble_ll_adv_init();
 }
 
-/* Called to determine if advertising is enabled */
+/* Called to determine if advertising is enabled.
+ *
+ * NOTE: this currently only applies to the default advertising index.
+ */
 uint8_t
 ble_ll_adv_enabled(void)
 {
-    return g_ble_ll_adv_sm.enabled;
+    return g_ble_ll_adv_sm[0].adv_enabled;
 }
 
 /**
@@ -1505,18 +1749,23 @@ ble_ll_adv_enabled(void)
 void
 ble_ll_adv_init(void)
 {
+    int i;
     struct ble_ll_adv_sm *advsm;
 
     /* Set default advertising parameters */
-    advsm = &g_ble_ll_adv_sm;
-    memset(advsm, 0, sizeof(struct ble_ll_adv_sm));
+    for (i = 0; i < BLE_LL_ADV_INSTANCES; ++i) {
+        advsm = &g_ble_ll_adv_sm[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;
+        memset(advsm, 0, sizeof(struct ble_ll_adv_sm));
 
-    /* Initialize advertising tx done event */
-    advsm->adv_txdone_ev.ev_cb = ble_ll_adv_event_done;
-    advsm->adv_txdone_ev.ev_arg = advsm;
+        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;
+
+        /* Initialize advertising tx done event */
+        advsm->adv_txdone_ev.ev_cb = ble_ll_adv_event_done;
+        advsm->adv_txdone_ev.ev_arg = advsm;
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index e67408d..c72b0b4 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -1630,7 +1630,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     if (ble_err) {
         if (ble_err == BLE_ERR_UNK_CONN_ID) {
             evbuf = ble_ll_init_get_conn_comp_ev();
-            ble_ll_conn_comp_event_send(connsm, ble_err, evbuf);
+            ble_ll_conn_comp_event_send(connsm, ble_err, evbuf, NULL);
         } else {
             ble_ll_disconn_comp_event_send(connsm, ble_err);
         }
@@ -1804,7 +1804,8 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
  * @ return 0: connection NOT created. 1: connection created
  */
 static int
-ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
+ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime,
+                    struct ble_mbuf_hdr *rxhdr)
 {
     int rc;
     uint8_t *evbuf;
@@ -1867,11 +1868,11 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
             }
         }
         if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
-            evbuf = ble_ll_adv_get_conn_comp_ev();
+            ble_ll_adv_send_conn_comp_ev(connsm, rxhdr);
         } else {
             evbuf = ble_ll_init_get_conn_comp_ev();
+            ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL);
         }
-        ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf);
     }
 
     return rc;
@@ -1898,10 +1899,6 @@ ble_ll_conn_event_end(struct os_event *ev)
     /* Check if we need to resume scanning */
     ble_ll_scan_chk_resume();
 
-    /* Log event end */
-    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, connsm->event_cntr,
-               connsm->ce_end_time);
-
     /* If we have transmitted the terminate IND successfully, we are done */
     if ((connsm->csmflags.cfbit.terminate_ind_txd) ||
         (connsm->csmflags.cfbit.terminate_ind_rxd)) {
@@ -1970,6 +1967,10 @@ ble_ll_conn_event_end(struct os_event *ev)
         }
     }
 
+    /* Log event end */
+    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, connsm->conn_handle,
+               connsm->event_cntr, connsm->conn_sch.start_time);
+
     /* If we have completed packets, send an event */
     ble_ll_conn_num_comp_pkts_event_send(connsm);
 }
@@ -2222,7 +2223,7 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
         ble_ll_scan_sm_stop(0);
         payload_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
         endtime = ble_hdr->beg_cputime + BLE_TX_DUR_USECS_M(payload_len);
-        ble_ll_conn_created(connsm, endtime);
+        ble_ll_conn_created(connsm, endtime, NULL);
     } else {
         ble_ll_scan_chk_resume();
     }
@@ -3054,7 +3055,8 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, uint8_t *chanmap)
  * @return 0: connection not started; 1 connecton started
  */
 int
-ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t pat)
+ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t pat,
+                        struct ble_mbuf_hdr *rxhdr)
 {
     int rc;
     uint32_t temp;
@@ -3148,7 +3150,7 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t pat)
     /* Set initial schedule callback */
     connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
 
-    rc = ble_ll_conn_created(connsm, conn_req_end);
+    rc = ble_ll_conn_created(connsm, conn_req_end, rxhdr);
     if (!rc) {
         SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
         STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index 0ce49f8..99b8665 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -156,7 +156,7 @@ ble_ll_conn_req_pdu_make(struct ble_ll_conn_sm *connsm)
  */
 void
 ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
-                            uint8_t *evbuf)
+                            uint8_t *evbuf, struct ble_ll_adv_sm *advsm)
 {
     uint8_t peer_addr_type;
     uint8_t enabled;
@@ -181,6 +181,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
 
         if (connsm) {
             htole16(evbuf + 4, connsm->conn_handle);
+
             evbuf[6] = connsm->conn_role - 1;
             peer_addr_type = connsm->peer_addr_type;
 
@@ -194,7 +195,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
                         rpa = NULL;
                     }
                 } else {
-                    rpa = ble_ll_adv_get_local_rpa();
+                    rpa = ble_ll_adv_get_local_rpa(advsm);
                 }
                 if (rpa) {
                     memcpy(evdata, rpa, BLE_DEV_ADDR_LEN);
@@ -204,7 +205,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
                     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
                         rpa = ble_ll_scan_get_peer_rpa();
                     } else {
-                        rpa = ble_ll_adv_get_peer_rpa();
+                        rpa = ble_ll_adv_get_peer_rpa(advsm);
                     }
                     memcpy(evdata + 6, rpa, BLE_DEV_ADDR_LEN);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h
index f1abbdc..eea5439 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -92,6 +92,8 @@ extern struct os_mempool g_ble_ll_hci_ev_pool;
 struct ble_ll_len_req;
 struct hci_create_conn;
 struct ble_mbuf_hdr;
+struct ble_ll_adv_sm;
+
 void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm);
 void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
 void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
@@ -104,7 +106,8 @@ void ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm,
                                 struct ble_ll_len_req *req);
 
 /* Advertising interface */
-int ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t pat);
+int ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t pat,
+                            struct ble_mbuf_hdr *rxhdr);
 
 /* Link Layer interface */
 void ble_ll_conn_module_init(void);
@@ -136,7 +139,7 @@ int ble_ll_conn_hci_param_reply(uint8_t *cmdbuf, int negative_reply);
 int ble_ll_conn_create_cancel(void);
 void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm);
 void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
-                                 uint8_t *evbuf);
+                                 uint8_t *evbuf, struct ble_ll_adv_sm *advsm);
 void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
 int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
                                     uint16_t latency, uint16_t spvn_tmo);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci.c b/net/nimble/controller/src/ble_ll_hci.c
index 7b549ad..7f3bb09 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -24,6 +24,7 @@
 #include "nimble/ble.h"
 #include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
+#include "nimble/hci_vendor.h"
 #include "nimble/ble_hci_trans.h"
 #include "controller/ble_hw.h"
 #include "controller/ble_ll_adv.h"
@@ -505,6 +506,87 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf)
 }
 
 /**
+ * Returns the vendor specific capabilities
+ *
+ * @param rspbuf Pointer to response buffer
+ * @param rsplen Length of response buffer
+ *
+ * @return int BLE error code
+ */
+static int
+ble_ll_hci_vendor_caps(uint8_t *rspbuf, uint8_t *rsplen)
+{
+    /* Clear all bytes */
+    memset(rspbuf, 0, 14);
+
+    /* Fill out the ones we support */
+    rspbuf[0] = BLE_LL_ADV_INSTANCES;
+    rspbuf[9] = 0x60;
+    *rsplen = 14;
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Process a vendor command sent from the host to the controller. The HCI
+ * command has a 3 byte command header followed by data. The header is:
+ *  -> opcode (2 bytes)
+ *  -> Length of parameters (1 byte; does include command header bytes).
+ *
+ * @param cmdbuf Pointer to command buffer. Points to start of command header.
+ * @param ocf    Opcode command field.
+ * @param *rsplen Pointer to length of response
+ *
+ * @return int  This function returns a BLE error code. If a command status
+ *              event should be returned as opposed to command complete,
+ *              256 gets added to the return value.
+ */
+static int
+ble_ll_hci_vendor_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
+{
+    int rc;
+    uint8_t cmdlen;
+    uint8_t *rspbuf;
+
+    /* Assume error; if all pass rc gets set to 0 */
+    rc = BLE_ERR_INV_HCI_CMD_PARMS;
+
+    /* Get length from command */
+    cmdlen = cmdbuf[sizeof(uint16_t)];
+
+    /*
+     * The command response pointer points into the same buffer as the
+     * command data itself. That is fine, as each command reads all the data
+     * before crafting a response.
+     */
+    rspbuf = cmdbuf + BLE_HCI_EVENT_CMD_COMPLETE_MIN_LEN;
+
+    /* Move past HCI command header */
+    cmdbuf += BLE_HCI_CMD_HDR_LEN;
+
+    switch (ocf) {
+    case BLE_HCI_OCF_VENDOR_CAPS:
+        if (cmdlen == 0) {
+            ble_ll_hci_vendor_caps(rspbuf, rsplen);
+            rc = BLE_ERR_SUCCESS;
+        }
+        break;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    case BLE_HCI_OCF_MULTI_ADV:
+        if (cmdlen > 0) {
+            rc = ble_ll_adv_multi_adv_cmd(cmdbuf, cmdlen, rspbuf, rsplen);
+        }
+        break;
+#endif
+    default:
+        rc = BLE_ERR_UNKNOWN_HCI_CMD;
+        break;
+    }
+
+    /* XXX: for now, all vendor commands return a command complete */
+    return rc;
+}
+
+/**
  * Process a LE command sent from the host to the controller. The HCI command
  * has a 3 byte command header followed by data. The header is:
  *  -> opcode (2 bytes)
@@ -534,7 +616,7 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
 
     /* Check the length to make sure it is valid */
     cmdlen = g_ble_hci_le_cmd_len[ocf];
-    if ((cmdlen != 0xFF) && (len != cmdlen)) {
+    if (len != cmdlen) {
         goto ll_hci_le_cmd_exit;
     }
 
@@ -562,27 +644,19 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
         rc = ble_ll_set_random_addr(cmdbuf);
         break;
     case BLE_HCI_OCF_LE_SET_ADV_PARAMS:
-        /* Length should be one byte */
-        rc = ble_ll_adv_set_adv_params(cmdbuf);
+        rc = ble_ll_adv_set_adv_params(cmdbuf, 0, 0);
         break;
     case BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR:
         rc = ble_ll_adv_read_txpwr(rspbuf, rsplen);
         break;
     case BLE_HCI_OCF_LE_SET_ADV_DATA:
-        if (len > 0) {
-            --len;
-            rc = ble_ll_adv_set_adv_data(cmdbuf, len);
-        }
+        rc = ble_ll_adv_set_adv_data(cmdbuf, 0);
         break;
     case BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA:
-        if (len > 0) {
-            --len;
-            rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, len);
-        }
+        rc = ble_ll_adv_set_scan_rsp_data(cmdbuf, 0);
         break;
     case BLE_HCI_OCF_LE_SET_ADV_ENABLE:
-        /* Length should be one byte */
-        rc = ble_ll_adv_set_enable(cmdbuf);
+        rc = ble_ll_adv_set_enable(cmdbuf, 0);
         break;
     case BLE_HCI_OCF_LE_SET_SCAN_ENABLE:
         rc = ble_ll_scan_set_enable(cmdbuf);
@@ -951,6 +1025,9 @@ ble_ll_hci_cmd_proc(struct os_event *ev)
     case BLE_HCI_OGF_LE:
         rc = ble_ll_hci_le_cmd_proc(cmdbuf, ocf, &rsplen);
         break;
+    case BLE_HCI_OGF_VENDOR:
+        rc = ble_ll_hci_vendor_cmd_proc(cmdbuf, ocf, &rsplen);
+        break;
     default:
         /* XXX: Need to support other OGF. For now, return unsupported */
         rc = BLE_ERR_UNKNOWN_HCI_CMD;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/src/ble_ll_sched.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_sched.c b/net/nimble/controller/src/ble_ll_sched.c
index b3cc52d..99b387c 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -32,6 +32,11 @@
 /* XXX: this is temporary. Not sure what I want to do here */
 struct hal_timer g_ble_ll_sched_timer;
 
+#define BLE_LL_SCHED_ADV_WORST_CASE_USECS       \
+    (BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \
+     + XCVR_TX_SCHED_DELAY_USECS)
+
+
 #if (BLE_LL_SCHED_DEBUG == 1)
 int32_t g_ble_ll_sched_max_late;
 #endif
@@ -182,8 +187,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
     TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
         if (ble_ll_sched_is_overlap(sch, entry)) {
             /* Only insert if this element is older than all that we overlap */
-            if ((entry->sched_type == BLE_LL_SCHED_TYPE_ADV) ||
-                !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg,
+            if (!ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg,
                                     (struct ble_ll_conn_sm *)entry->cb_arg)) {
                 start_overlap = NULL;
                 rc = -1;
@@ -196,7 +200,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
                 end_overlap = entry;
             }
         } else {
-            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+            if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
                 rc = 0;
                 TAILQ_INSERT_BEFORE(entry, sch, link);
                 break;
@@ -218,6 +222,9 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
         if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) {
             tmp = (struct ble_ll_conn_sm *)entry->cb_arg;
             ble_ll_event_send(&tmp->conn_ev_end);
+        } else {
+            assert(entry->sched_type == BLE_LL_SCHED_TYPE_ADV);
+            ble_ll_adv_event_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg);
         }
 
         TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
@@ -315,7 +322,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend,
             sch->end_time = earliest_end;
 
             /* We can insert if before entry in list */
-            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+            if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
                 if ((earliest_start - initial_start) <= itvl_t) {
                     rc = 0;
                     TAILQ_INSERT_BEFORE(entry, sch, link);
@@ -401,7 +408,7 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
         while (1) {
             next_sch = entry->link.tqe_next;
             /* Insert if event ends before next starts */
-            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+            if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
                 rc = 0;
                 TAILQ_INSERT_BEFORE(entry, sch, link);
                 break;
@@ -443,14 +450,17 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
 {
     int rc;
     os_sr_t sr;
+    uint8_t ll_state;
     int32_t ticks;
     uint32_t ce_end_time;
     uint32_t adv_start;
     uint32_t duration;
     struct ble_ll_sched_item *entry;
+    struct ble_ll_sched_item *orig;
 
     /* Get length of schedule item */
     duration = sch->end_time - sch->start_time;
+    orig = sch;
 
     OS_ENTER_CRITICAL(sr);
 
@@ -458,7 +468,8 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
      * If we are currently in a connection, we add one slot time to the
      * earliest start so we can end the connection reasonably.
      */
-    if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+    ll_state = ble_ll_state_get();
+    if (ll_state == BLE_LL_STATE_CONNECTION) {
         ticks = (int32_t)os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT);
         ce_end_time = ble_ll_conn_get_ce_end_time();
         if ((int32_t)(ce_end_time - sch->start_time) < ticks) {
@@ -467,6 +478,18 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
         sch->start_time = ce_end_time;
         sch->end_time = ce_end_time + duration;
     }
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    else if ((ll_state == BLE_LL_STATE_ADV) && (BLE_LL_ADV_INSTANCES > 1)) {
+        /*
+         * Since we currently dont know how long this item might be scheduled
+         * for we add what we think the worst-case time for the advertising
+         * scheduled item to be over. We add in a IFS for good measure.
+         */
+        sch->start_time += BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS +
+            BLE_LL_SCHED_ADV_MAX_USECS + XCVR_TX_SCHED_DELAY_USECS;
+        sch->end_time = sch->start_time + duration;
+    }
+#endif
 
     entry = ble_ll_sched_insert_if_empty(sch);
     if (!entry) {
@@ -476,7 +499,7 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
         os_cputime_timer_stop(&g_ble_ll_sched_timer);
         TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
             /* We can insert if before entry in list */
-            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+            if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
                 rc = 0;
                 TAILQ_INSERT_BEFORE(entry, sch, link);
                 break;
@@ -504,7 +527,7 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
         sch = TAILQ_FIRST(&g_ble_ll_sched_q);
     }
 
-    ble_ll_adv_scheduled(adv_start);
+    ble_ll_adv_scheduled((struct ble_ll_adv_sm *)orig->cb_arg, adv_start);
 
     OS_EXIT_CRITICAL(sr);
 
@@ -520,65 +543,158 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
 }
 
 int
-ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch)
+ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
+                            uint32_t max_delay_ticks)
 {
     int rc;
     os_sr_t sr;
+    uint32_t orig_start;
+    uint32_t duration;
+    uint32_t rand_ticks;
     struct ble_ll_sched_item *entry;
     struct ble_ll_sched_item *next_sch;
+    struct ble_ll_sched_item *before;
+    struct ble_ll_sched_item *start_overlap;
+    struct ble_ll_sched_item *end_overlap;
+
+    /* Get length of schedule item */
+    duration = sch->end_time - sch->start_time;
+
+    /* Add maximum randomization delay to end */
+    rand_ticks = max_delay_ticks;
+    sch->end_time += max_delay_ticks;
 
+    start_overlap = NULL;
+    before = NULL;
     rc = 0;
     OS_ENTER_CRITICAL(sr);
 
-    /* The schedule item must occur after current running item (if any) */
-    if (ble_ll_sched_overlaps_current(sch)) {
-        OS_EXIT_CRITICAL(sr);
-        return -1;
-    }
-
     entry = ble_ll_sched_insert_if_empty(sch);
     if (entry) {
         os_cputime_timer_stop(&g_ble_ll_sched_timer);
         while (1) {
-            /* Insert before if adv event is before this event */
             next_sch = entry->link.tqe_next;
-            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
-                rc = 0;
-                TAILQ_INSERT_BEFORE(entry, sch, link);
-                break;
-            }
-
             if (ble_ll_sched_is_overlap(sch, entry)) {
-                if (ble_ll_sched_conn_overlap(entry)) {
-                    assert(0);
+                if (start_overlap == NULL) {
+                    start_overlap = entry;
+                    end_overlap = entry;
+                } else {
+                    end_overlap = entry;
+                }
+            } else {
+                if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
+                    before = entry;
+                    break;
                 }
             }
 
-            /* Move to next entry */
             entry = next_sch;
-
-            /* Insert at tail if none left to check */
-            if (!entry) {
-                rc = 0;
-                TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+            if (entry == NULL) {
                 break;
             }
         }
 
-        if (!rc) {
-            sch->enqueued = 1;
+        /*
+         * If there is no overlap, we either insert before the 'before' entry
+         * or we insert at the end if there is no before entry.
+         */
+        if (start_overlap == NULL) {
+            if (before) {
+                TAILQ_INSERT_BEFORE(before, sch, link);
+            } else {
+                TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+            }
+        } else {
+            /*
+             * This item will overlap with others. See if we can fit it in
+             * with original duration.
+             */
+            before = NULL;
+            orig_start = sch->start_time;
+            entry = start_overlap;
+            sch->end_time = sch->start_time + duration;
+            while (1) {
+                next_sch = entry->link.tqe_next;
+                if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
+                    rand_ticks = entry->start_time - sch->end_time;
+                    before = entry;
+                    TAILQ_INSERT_BEFORE(before, sch, link);
+                    break;
+                } else {
+                    sch->start_time = entry->end_time;
+                    sch->end_time = sch->start_time + duration;
+                }
+
+                if (entry == end_overlap) {
+                    rand_ticks = (orig_start + max_delay_ticks) - sch->start_time;
+                    if (rand_ticks > max_delay_ticks) {
+                        /* No place for advertisement. */
+                        rc = -1;
+                    } else {
+                        if (next_sch == NULL) {
+                            TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+                        } else {
+                            TAILQ_INSERT_BEFORE(next_sch, sch, link);
+                        }
+                    }
+                    break;
+                }
+                entry = next_sch;
+                assert(entry != NULL);
+            }
         }
+    }
 
-        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+    if (!rc) {
+        sch->enqueued = 1;
+        if (rand_ticks) {
+            sch->start_time += rand() % rand_ticks;
+        }
+        sch->end_time = sch->start_time + duration;
+        *start = sch->start_time;
     }
 
     OS_EXIT_CRITICAL(sr);
 
+    sch = TAILQ_FIRST(&g_ble_ll_sched_q);
     os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
 
     return rc;
 }
 
+int
+ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch)
+{
+    uint8_t lls;
+    os_sr_t sr;
+    struct ble_ll_sched_item *entry;
+
+    OS_ENTER_CRITICAL(sr);
+
+    lls = ble_ll_state_get();
+    if ((lls == BLE_LL_STATE_ADV) || (lls == BLE_LL_STATE_CONNECTION)) {
+        goto adv_resched_pdu_fail;
+    }
+
+    entry = ble_ll_sched_insert_if_empty(sch);
+    if (entry) {
+        /* If we overlap with the first item, simply re-schedule */
+        if (ble_ll_sched_is_overlap(sch, entry)) {
+            goto adv_resched_pdu_fail;
+        }
+        os_cputime_timer_stop(&g_ble_ll_sched_timer);
+        TAILQ_INSERT_BEFORE(entry, sch, link);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+    os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+    return 0;
+
+adv_resched_pdu_fail:
+    OS_EXIT_CRITICAL(sr);
+    return -1;
+}
+
 /**
  * Remove a schedule element
  *
@@ -645,11 +761,10 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
             ble_ll_state_set(BLE_LL_STATE_STANDBY);
         } else if (lls == BLE_LL_STATE_ADV) {
             STATS_INC(ble_ll_stats, sched_state_adv_errs);
-            ble_ll_adv_halt();
+            ble_ll_adv_halt((struct ble_ll_adv_sm *)sch->cb_arg);
         } else {
             STATS_INC(ble_ll_stats, sched_state_conn_errs);
             ble_ll_conn_event_halt();
-            return -1;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/controller/syscfg.yml
----------------------------------------------------------------------
diff --git a/net/nimble/controller/syscfg.yml b/net/nimble/controller/syscfg.yml
index 1b0e7d7..b5119cd 100644
--- a/net/nimble/controller/syscfg.yml
+++ b/net/nimble/controller/syscfg.yml
@@ -109,8 +109,15 @@ syscfg.defs:
 
     # The number of slots that will be allocated to each connection
     BLE_LL_CONN_INIT_SLOTS:
-        description: 'TBD'
-        value: '2'
+        description: >
+            This is the number of "slots" allocated to a connection when scheduling
+            connections. Each slot is 1.25 msecs long. Note that a connection event may
+            last longer than the number of slots allocated here and may also end earlier
+            (depending on when the next scheduled event occurs and how much data needs
+            to be transferred in the connection). However, you will be guaranteed that
+            a connection event will be given this much time, if needed. Consecutively
+            scheduled items will be at least this far apart
+        value: '4'
 
     # The number of random bytes to store
     BLE_LL_RNG_BUFSIZE:

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8c876d8c/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index bff3e9d..29f335c 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -27,6 +27,7 @@ extern "C" {
 
 /* XXX: some or all of these should not be here */
 #include "os/os.h"
+#include "syscfg/syscfg.h"
 
 /* BLE encryption block definitions */
 #define BLE_ENC_BLOCK_SIZE       (16)
@@ -63,6 +64,9 @@ struct ble_mbuf_hdr_rxinfo
     uint8_t channel;
     uint8_t handle;
     int8_t  rssi;
+#if MYNEWT_VAL(BLE_MULTI_ADV_SUPPORT)
+    void *advsm;   /* advertising state machine */
+#endif
 };
 
 /* Flag definitions for rxinfo  */