You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2015/12/14 08:00:21 UTC

incubator-mynewt-larva git commit: Add disconnect command and code to terminate a connection

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 6377a6941 -> 8323f4b76


Add disconnect command and code to terminate a connection


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/8323f4b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/8323f4b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/8323f4b7

Branch: refs/heads/master
Commit: 8323f4b76fb8440d8937e0b9401d6dc932afa7b2
Parents: 6377a69
Author: wes3 <wi...@micosa.io>
Authored: Sun Dec 13 23:00:05 2015 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Sun Dec 13 23:00:14 2015 -0800

----------------------------------------------------------------------
 .../controller/include/controller/ble_ll.h      |   1 +
 .../controller/include/controller/ble_ll_conn.h |  23 +-
 .../controller/include/controller/ble_ll_ctrl.h |   5 +
 .../controller/include/controller/ble_ll_hci.h  |   5 +-
 net/nimble/controller/src/ble_ll.c              |   2 +-
 net/nimble/controller/src/ble_ll_conn.c         | 273 ++++++++++++++++---
 net/nimble/controller/src/ble_ll_ctrl.c         |  80 +++++-
 net/nimble/controller/src/ble_ll_hci.c          | 129 ++++++++-
 net/nimble/host/include/host/host_hci.h         |   2 +
 net/nimble/host/src/ble_hs.c                    |   2 +-
 net/nimble/host/src/host_dbg.c                  |  29 ++
 net/nimble/host/src/host_hci.c                  |  14 -
 net/nimble/host/src/host_hci_cmd.c              |  54 +++-
 net/nimble/include/nimble/hci_common.h          |   7 +
 project/bletest/src/main.c                      |  83 +++++-
 15 files changed, 629 insertions(+), 80 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/include/controller/ble_ll.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h
index 64ee545..53782d7 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -296,6 +296,7 @@ uint8_t ble_ll_read_supp_features(void);
 #define BLE_LL_LOG_ID_RX_END            (2)
 #define BLE_LL_LOG_ID_CONN_EV_START     (4)
 #define BLE_LL_LOG_ID_CONN_EV_END       (5)
+#define BLE_LL_LOG_ID_CONN_END          (6)
 #define BLE_LL_LOG_ID_PHY_SETCHAN       (200)
 #define BLE_LL_LOG_ID_PHY_DISABLE       (201)
 #define BLE_LL_LOG_ID_PHY_ISR           (202)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h
index 5236dec..3abc62a 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -20,6 +20,9 @@
 #include "os/os.h"
 #include "hal/hal_cputime.h"
 
+/* Connection handle range */
+#define BLE_LL_CONN_MAX_CONN_HANDLE     (0x0EFF)
+
 /* Channel map size */
 #define BLE_LL_CONN_CHMAP_LEN           (5)
 
@@ -86,14 +89,18 @@ struct ble_ll_conn_sm
                                    only use the MD bit now */
 
     /* connection event timing/mgmt */
-    uint8_t pdu_txd;            /* note: can be 1 bit */
-    uint8_t rsp_rxd;            /* note: can be 1 bit */
-    uint8_t pkt_rxd;            /* note: can be 1 bit */
+    uint8_t pdu_txd;                /* note: can be 1 bit */
+    uint8_t rsp_rxd;                /* note: can be 1 bit */
+    uint8_t pkt_rxd;                /* note: can be 1 bit */
+    uint8_t terminate_ind_txd;      /* note: can be 1 bit */
+    uint8_t terminate_ind_rxd;      /* note: can be 1 bit */
+    uint8_t allow_slave_latency;    /* note: can be 1 bit */
+    uint8_t slave_set_last_anchor;  /* note: can be 1 bit */
     uint8_t master_sca;
     uint8_t tx_win_size;
-    uint8_t allow_slave_latency;    /* note: can be 1 bit  */
-    uint8_t slave_set_last_anchor;  /* note: can be 1 bit */
     uint8_t cur_ctrl_proc;
+    uint8_t disconnect_reason;
+    uint8_t rxd_disconnect_reason;
     uint16_t pending_ctrl_procs;
     uint16_t conn_itvl;
     uint16_t slave_latency;
@@ -108,6 +115,7 @@ struct ble_ll_conn_sm
     uint32_t anchor_point;
     uint32_t last_anchor_point;
     uint32_t ce_end_time;   /* cputime at which connection event should end */
+    uint32_t terminate_timeout;
     uint32_t slave_cur_tx_win_usecs;
     uint32_t slave_cur_window_widening;
 
@@ -142,7 +150,7 @@ struct ble_ll_conn_sm
 };
 
 /* API */
-void ble_ll_conn_init(void);
+void ble_ll_conn_module_init(void);
 int ble_ll_conn_create(uint8_t *cmdbuf);
 int ble_ll_conn_create_cancel(void);
 void ble_ll_init_rx_pdu_proc(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr);
@@ -157,9 +165,12 @@ void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len);
 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);
 void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status);
+int ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf);
 
 struct ble_ll_len_req;
 void ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm, 
                                 struct ble_ll_len_req *req);
 
+struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
+
 #endif /* H_BLE_LL_CONN_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/include/controller/ble_ll_ctrl.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_ctrl.h b/net/nimble/controller/include/controller/ble_ll_ctrl.h
index 1382f8c..ff47e39 100644
--- a/net/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -34,6 +34,9 @@
 #define BLE_LL_CTRL_PROC_NUM            (9)
 #define BLE_LL_CTRL_PROC_IDLE           (255)
 
+/* Checks if a particular control procedure is running */
+#define IS_PENDING_CTRL_PROC_M(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
+
 /* 
  * LL CTRL PDU format
  *  -> Opcode   (1 byte)
@@ -213,5 +216,7 @@ void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc);
 void ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om);
 void ble_ll_ctrl_datalen_chg_event(struct ble_ll_conn_sm *connsm);
 void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm);
+void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm);
+int ble_ll_ctrl_is_terminate_ind(struct os_mbuf *pdu);
 
 #endif /* H_BLE_LL_CTRL_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/include/controller/ble_ll_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h
index 222b772..aa06ee2 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -35,9 +35,12 @@ void ble_ll_hci_init(void);
 /* HCI command processing function */
 void ble_ll_hci_cmd_proc(struct os_event *ev);
 
-/* Used to determine if the LE event is enabled or disabled */
+/* Used to determine if the LE event is enabled/disabled */
 uint8_t ble_ll_hci_is_le_event_enabled(int bitpos);
 
+/* Used to determine if event is enabled/disabled */
+uint8_t ble_ll_hci_is_event_enabled(int bitpos);
+
 /* Send event from controller to host */
 int ble_ll_hci_event_send(uint8_t *evbuf);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c
index 005d3f7..260056b 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -811,7 +811,7 @@ ble_ll_init(void)
     ble_ll_scan_init();
 
     /* Initialize the connection module */
-    ble_ll_conn_init();
+    ble_ll_conn_module_init();
 
     /* Set the supported features */
     features = 0;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/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 86c681d..7be491d 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -48,6 +48,14 @@
  * We might want to guarantee a IFS time as well since the next event needs
  * to be scheduled prior to the start of the event to account for the time it
  * takes to get a frame ready (which is pretty much the IFS time).
+ * 7) Do we need to check the terminate timeout inside the connection event?
+ * I think we do.
+ * 8) Use error code 0x3E correctly! Connection failed to establish. If you
+ * read the LE connection complete event, it says that if the connection
+ * fails to be established that the connection complete event gets sent to
+ * the host that issued the create connection.
+ * 9) How does peer address get set if we are using whitelist? Look at filter
+ * policy and make sure you are doing this correctly.
  */
 
 /* XXX: this does not belong here! Move to transport? */
@@ -139,6 +147,7 @@ struct ble_ll_conn_stats
     uint32_t conn_ev_late;
     uint32_t wfr_expirations;
     uint32_t handle_not_found;
+    uint32_t bad_acl_hdr;
     uint32_t no_tx_pdu;
     uint32_t no_conn_sm;
     uint32_t no_free_conn_sm;
@@ -153,6 +162,26 @@ struct ble_ll_conn_stats
 struct ble_ll_conn_stats g_ble_ll_conn_stats;
 
 /**
+ * Given a handle, find an active connection matching the handle
+ * 
+ * @param handle 
+ * 
+ * @return struct ble_ll_conn_sm* 
+ */
+struct ble_ll_conn_sm *
+ble_ll_conn_find_active_conn(uint16_t handle)
+{
+    struct ble_ll_conn_sm *connsm;
+
+    SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
+        if (connsm->conn_handle == handle) {
+            break;
+        }
+    }
+    return connsm;
+}
+
+/**
  * Get a connection state machine.
  */
 struct ble_ll_conn_sm *
@@ -460,7 +489,7 @@ ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
     if (pkthdr) {
         m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
         nextpkthdr = STAILQ_NEXT(pkthdr, omp_next);
-        if (nextpkthdr) {
+        if (nextpkthdr && !connsm->terminate_ind_rxd) {
             md = 1;
             if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
                 /* 
@@ -529,11 +558,18 @@ ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
      * received a valid frame with the more data bit set to 0 and we dont
      * have more data.
      */
-    end_transition = BLE_PHY_TRANSITION_TX_RX;
-    if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) && 
-        (connsm->cons_rxd_bad_crc == 0) &&
-        ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0)) {
+    if (connsm->terminate_ind_rxd) {
         end_transition = BLE_PHY_TRANSITION_NONE;
+    } else {
+        /* XXX: what happens if we are sending a terminate ind? Are we sure
+           we are always going to wait for an ack? */
+        end_transition = BLE_PHY_TRANSITION_TX_RX;
+        if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) && 
+            (connsm->cons_rxd_bad_crc == 0) &&
+            ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) &&
+            !ble_ll_ctrl_is_terminate_ind(m)) {
+            end_transition = BLE_PHY_TRANSITION_NONE;
+        }
     }
 
     rc = ble_phy_tx(m, beg_transition, end_transition);
@@ -827,6 +863,9 @@ ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm)
     connsm->event_cntr = 0;
     connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
     connsm->allow_slave_latency = 0;
+    connsm->disconnect_reason = 0;
+    connsm->terminate_ind_txd = 0;
+    connsm->terminate_ind_rxd = 0;
 
     /* Reset current control procedure */
     connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
@@ -923,6 +962,32 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status)
 }
 
 /**
+ * Send a disconnection complete event. 
+ *  
+ * NOTE: we currently only send this event when we have a reason to send it; 
+ * not when it fails. 
+ * 
+ * @param reason The BLE error code to send as a disconnect reason
+ */
+void
+ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason)
+{
+    uint8_t *evbuf;
+
+    if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DISCONN_CMP - 1)) {
+        evbuf = os_memblock_get(&g_hci_cmd_pool);
+        if (evbuf) {
+            evbuf[0] = BLE_HCI_EVCODE_DISCONN_CMP;
+            evbuf[1] = BLE_HCI_EVENT_DISCONN_COMPLETE_LEN;
+            evbuf[2] = BLE_ERR_SUCCESS;
+            htole16(evbuf + 3, connsm->conn_handle);
+            evbuf[5] = reason;
+            ble_ll_hci_event_send(evbuf);
+        }
+    }
+}
+
+/**
  * Called when a remotes data length parameters change. 
  *  
  * Context: Link Layer task 
@@ -1026,14 +1091,31 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     /* Connection state machine is now idle */
     connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
 
+    /* Set current LL connection to NULL */
+    g_ble_ll_conn_cur_sm = NULL;
+
     /* Set Link Layer state to standby */
     ble_ll_state_set(BLE_LL_STATE_STANDBY);
 
-    /* Send connection complete event */
-    ble_ll_conn_comp_event_send(connsm, ble_err);
+    /* 
+     * We need to send a disconnection complete event or a connection complete
+     * event when the connection ends. We send a connection complete event
+     * only when we were told to cancel the connection creation.
+     */ 
+    if (ble_err == BLE_ERR_UNK_CONN_ID) {
+        ble_ll_conn_comp_event_send(connsm, ble_err);
+    } else {
+        ble_ll_disconn_comp_event_send(connsm, ble_err);
+    }
 
     /* Put connection state machine back on free list */
     STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
+
+    /* Log connection end */
+    ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
+
+    /* turn led off */
+    gpio_set(LED_BLINK_PIN);
 }
 
 /**
@@ -1102,6 +1184,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm)
 void
 ble_ll_conn_event_end(void *arg)
 {
+    uint8_t ble_err;
     uint16_t latency;
     uint32_t itvl;
     uint32_t cur_ww;
@@ -1110,6 +1193,21 @@ ble_ll_conn_event_end(void *arg)
 
     connsm = (struct ble_ll_conn_sm *)arg;
 
+    /* If we have transmitted the terminate IND successfully, we are done */
+    if ((connsm->terminate_ind_txd) || (connsm->terminate_ind_rxd)) {
+        if (connsm->terminate_ind_txd) {
+            ble_err = BLE_ERR_CONN_TERM_LOCAL;
+        } else {
+            /* Make sure the disconnect reason is valid! */
+            ble_err = connsm->rxd_disconnect_reason;
+            if (ble_err == 0) {
+                ble_err = BLE_ERR_REM_USER_CONN_TERM;
+            } 
+        }
+        ble_ll_conn_end(connsm, ble_err);
+        return;
+    }
+
     /* Disable the PHY */
     ble_phy_disable();
 
@@ -1171,11 +1269,17 @@ ble_ll_conn_event_end(void *arg)
     connsm->cons_rxd_bad_crc = 0;
     connsm->pkt_rxd = 0;
 
-    /* Link-layer is in standby state now */
-    ble_ll_state_set(BLE_LL_STATE_STANDBY);
-
-    /* Set current LL connection to NULL */
-    g_ble_ll_conn_cur_sm = NULL;
+    /* 
+     * If we are trying to terminate connection, check if next wake time is
+     * passed the termination timeout. If so, no need to continue with
+     * connection as we will time out anyway.
+     */
+    if (connsm->pending_ctrl_procs & (1 << BLE_LL_CTRL_PROC_TERMINATE)) {
+        if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
+            ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
+            return;
+        }
+    }
 
     /* Calculate window widening for next event. If too big, end conn */
     if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
@@ -1188,6 +1292,12 @@ ble_ll_conn_event_end(void *arg)
         connsm->slave_cur_window_widening = cur_ww;
     }
 
+    /* Link-layer is in standby state now */
+    ble_ll_state_set(BLE_LL_STATE_STANDBY);
+
+    /* Set current LL connection to NULL */
+    g_ble_ll_conn_cur_sm = NULL;
+
     /* Log event end */
     ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, 0, connsm->event_cntr);
 
@@ -1904,6 +2014,14 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok)
                 if (pkthdr) {
                     STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
                     txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+
+                    /* Did we transmit a TERMINATE_IND? If so, we are done */
+                    if (ble_ll_ctrl_is_terminate_ind(txpdu)) {
+                        connsm->terminate_ind_txd = 1;
+                        os_mbuf_free(txpdu);
+                        rc = -1;
+                        goto conn_event_done;
+                    }
                     os_mbuf_free(txpdu);
                 } else {
                     /* No packet on queue? This is an error! */
@@ -1913,7 +2031,12 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok)
         }
 
         /* Should we continue connection event? */
-        if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+        /* If this is a TERMINATE_IND, we have to reply */
+        if (ble_ll_ctrl_is_terminate_ind(rxpdu)) {
+            connsm->terminate_ind_rxd = 1;
+            connsm->rxd_disconnect_reason = rxpdu->om_data[3];
+            reply = 1;
+        } else if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
             reply = connsm->last_txd_md || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK);
             if (reply) {
                 pkthdr = STAILQ_FIRST(&connsm->conn_txq);
@@ -1939,9 +2062,25 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok)
     /* If reply flag set, send data pdu and continue connection event */
     rc = -1;
     if (reply) {
+        /* 
+         * While this is not perfect, we will just check to see if the
+         * terminate timer will expire within two packet times. If it will,
+         * no use sending the terminate ind. We need to get an ACK for the
+         * terminate ind (master and/or slave) so that is why it is two packets.
+         */ 
+        if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_TERMINATE)) {
+            ticks = ble_ll_pdu_tx_time_get(BLE_LL_PDU_HDR_LEN) +
+                ble_ll_pdu_tx_time_get(BLE_LL_CTRL_TERMINATE_IND_LEN + 3) + 
+                BLE_LL_IFS;
+            ticks = cputime_usecs_to_ticks(ticks) + cputime_get32();
+            if ((int32_t)(connsm->terminate_timeout - ticks) < 0) {
+                goto conn_event_done;
+            }
+        }
         rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_RX_TX);
     }
 
+conn_event_done:
     if (rc) {
         ble_ll_event_send(&connsm->conn_ev_end);
     }
@@ -1997,31 +2136,31 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length)
 
     /* See if we have an active matching connection handle */
     conn_handle = handle & 0x0FFF;
-    SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
-        if (connsm->conn_handle == conn_handle) {
-            /* Construct LL header in buffer */
-            /* XXX: deal with length later */
-            assert(length <= 251);
-            pb = handle & 0x3000;
-            if (pb == 0) {
-                om->om_data[0] = BLE_LL_LLID_DATA_START;
-            } else if (pb == 0x1000) {
-                om->om_data[0] = BLE_LL_LLID_DATA_FRAG;
-            } else {
-                /* This should never happen! */
-                break;
-            }
-            om->om_data[1] = (uint8_t)length;
-
-            /* Clear flags field in BLE header */
-            ble_ll_conn_enqueue_pkt(connsm, om);
+    connsm = ble_ll_conn_find_active_conn(conn_handle);
+    if (connsm) {
+        /* Construct LL header in buffer */
+        /* XXX: deal with length later */
+        assert(length <= 251);
+        pb = handle & 0x3000;
+        if (pb == 0) {
+            om->om_data[0] = BLE_LL_LLID_DATA_START;
+        } else if (pb == 0x1000) {
+            om->om_data[0] = BLE_LL_LLID_DATA_FRAG;
+        } else {
+            /* This should never happen! */
+            ++g_ble_ll_conn_stats.bad_acl_hdr;
+            os_mbuf_free(om);
             return;
         }
-    }
+        om->om_data[1] = (uint8_t)length;
 
-    /* No connection found! */
-    ++g_ble_ll_conn_stats.handle_not_found;
-    os_mbuf_free(om);
+        /* Clear flags field in BLE header */
+        ble_ll_conn_enqueue_pkt(connsm, om);
+    } else {
+        /* No connection found! */
+        ++g_ble_ll_conn_stats.handle_not_found;
+        os_mbuf_free(om);
+    }
 }
 
 /**
@@ -2144,9 +2283,71 @@ err_slave_start:
     return 0;
 }
 
+/**
+ * Called to process a HCI disconnect command 
+ *  
+ * Context: Link Layer task (HCI command parser). 
+ * 
+ * @param cmdbuf 
+ * 
+ * @return int 
+ */
+int
+ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf)
+{
+    int rc;
+    uint8_t reason;
+    uint16_t handle;
+    struct ble_ll_conn_sm *connsm;
+
+    /* Check for valid parameters */
+    handle = le16toh(cmdbuf);
+    reason = cmdbuf[2];
+
+    rc = BLE_ERR_INV_HCI_CMD_PARMS;
+    if (handle <= BLE_LL_CONN_MAX_CONN_HANDLE) {
+        /* Make sure reason is valid */
+        switch (reason) {
+        case BLE_ERR_AUTH_FAIL:
+        case BLE_ERR_REM_USER_CONN_TERM:
+        case BLE_ERR_RD_CONN_TERM_RESRCS:
+        case BLE_ERR_RD_CONN_TERM_PWROFF:
+        case BLE_ERR_UNSUPP_FEATURE:
+        case BLE_ERR_UNIT_KEY_PAIRING:
+        case BLE_ERR_CONN_PARMS:
+            connsm = ble_ll_conn_find_active_conn(handle);
+            if (connsm) {
+                /* Do not allow command if we are in process of disconnecting */
+                if (connsm->disconnect_reason) {
+                    rc = BLE_ERR_CMD_DISALLOWED;
+                } else {
+                    /* This control procedure better not be pending! */
+                    assert(!IS_PENDING_CTRL_PROC_M(connsm,
+                                                   BLE_LL_CTRL_PROC_TERMINATE));
+
+                    /* Record the disconnect reason */
+                    connsm->disconnect_reason = reason;
+
+                    /* Start this control procedure */
+                    ble_ll_ctrl_terminate_start(connsm);
+
+                    rc = BLE_ERR_SUCCESS;
+                }
+            } else {
+                rc = BLE_ERR_UNK_CONN_ID;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    return rc;
+}
+
 /* Initialize the connection module */
 void
-ble_ll_conn_init(void)
+ble_ll_conn_module_init(void)
 {
     uint16_t i;
     uint16_t maxbytes;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index 73d1727..2ad3772 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -52,10 +52,6 @@
 /* XXX: Improvements
  * 1) We can inititalize the procedure timer once per connection state machine
  */
-
-/* Checks if a particular control procedure is running */
-#define IS_PENDING_CTRL_PROC_M(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
-
 static int
 ble_ll_ctrl_chk_supp_bytes(uint16_t bytes)
 {
@@ -231,6 +227,11 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
             opcode = BLE_LL_CTRL_LENGTH_REQ;
             ble_ll_ctrl_datalen_upd_make(connsm, dptr);
             break;
+        case BLE_LL_CTRL_PROC_TERMINATE:
+            len = BLE_LL_CTRL_TERMINATE_IND_LEN;
+            opcode = BLE_LL_CTRL_TERMINATE_IND;
+            dptr[3] = connsm->disconnect_reason;
+            break;
         default:
             assert(0);
             break;
@@ -249,6 +250,29 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
 }
 
 /**
+ * Called to determine if the pdu is a TERMINATE_IND 
+ * 
+ * @param pdu 
+ *  
+ * XXX: should we set a BLE header flag instead to denote TERMINATE_IND? 
+ * 
+ * @return int 0: not a terminate. 1: yes
+ */
+int
+ble_ll_ctrl_is_terminate_ind(struct os_mbuf *pdu)
+{
+    int rc;
+
+    rc = 0;
+    if ((pdu->om_data[0] & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
+        if (pdu->om_data[BLE_LL_PDU_HDR_LEN] == BLE_LL_CTRL_TERMINATE_IND) {
+            rc = 1;
+        }
+    }
+    return rc;
+}
+
+/**
  * Stops the LL control procedure indicated by 'ctrl_proc'. 
  *  
  * Context: Link Layer task 
@@ -270,9 +294,38 @@ ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc)
 }
 
 /**
- * Called to start a LL control procedure. We always set the control 
- * procedure pending bit even if the input control procedure has been 
- * initiated. 
+ * Called to start the terminate procedure. 
+ *  
+ * Context: Link Layer task. 
+ *  
+ * @param connsm 
+ */
+void
+ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm)
+{
+    int ctrl_proc;
+    uint32_t usecs;
+    struct os_mbuf *om;
+
+    assert(connsm->disconnect_reason != 0);
+
+    ctrl_proc = BLE_LL_CTRL_PROC_TERMINATE;
+    om = ble_ll_ctrl_proc_init(connsm, ctrl_proc);
+    if (om) {
+        ble_ll_conn_enqueue_pkt(connsm, om);
+        connsm->pending_ctrl_procs |= (1 << ctrl_proc);
+
+        /* Set terminate "timeout" */
+        usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
+        connsm->terminate_timeout = cputime_get32() + 
+            cputime_usecs_to_ticks(usecs);
+    }
+}
+
+/**
+ * Called to start a LL control procedure except for the terminate procedure. We
+ * always set the control procedure pending bit even if the control procedure
+ * has been initiated. 
  *  
  * Context: Link Layer task. 
  * 
@@ -283,6 +336,8 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc)
 {
     struct os_mbuf *om;
 
+    assert(ctrl_proc != BLE_LL_CTRL_PROC_TERMINATE);
+
     om = NULL;
     if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) {
         /* Initiate the control procedure. */
@@ -323,6 +378,17 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
 {
     int i;
 
+    /* If we are terminating, dont start any new procedures */
+    if (connsm->disconnect_reason) {
+        /* 
+         * If the terminate procedure is not pending it means we were not
+         * able to start it right away (no control pdu was available).
+         * Start it now
+         */ 
+        ble_ll_ctrl_terminate_start(connsm);
+        return;
+    }
+
     /* If there is a running procedure or no pending, do nothing */
     if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) &&
         (connsm->pending_ctrl_procs != 0)) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/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 9fe7c9e..eff56d8 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -138,9 +138,35 @@ ble_ll_hci_is_le_event_enabled(int bitpos)
     uint8_t bytenum;
     uint8_t bitmask;
 
+    /* The LE meta event must be enabled for any LE event to be enabled */
+    enabled = 0;
+    if (g_ble_ll_hci_event_mask[7] & 0x20) {
+        bytenum = bitpos / 8;
+        bitmask = 1 << (bitpos & 0x7);
+        enabled = g_ble_ll_hci_le_event_mask[bytenum] & bitmask;
+    }
+
+    return enabled;
+}
+
+/**
+ * Checks to see if an event has been disabled by the host. 
+ * 
+ * @param bitpos This is the bit position of the event. Note that this can 
+ * be a value from 0 to 63, inclusive. 
+ * 
+ * @return uint8_t 0: event is not enabled; otherwise event is enabled.
+ */
+uint8_t
+ble_ll_hci_is_event_enabled(int bitpos)
+{
+    uint8_t enabled;
+    uint8_t bytenum;
+    uint8_t bitmask;
+
     bytenum = bitpos / 8;
     bitmask = 1 << (bitpos & 0x7);
-    enabled = g_ble_ll_hci_le_event_mask[bytenum] & bitmask;
+    enabled = g_ble_ll_hci_event_mask[bytenum] & bitmask;
 
     return enabled;
 }
@@ -283,6 +309,101 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
     return rc;
 }
 
+/**
+ * Process a link control 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_link_ctrl_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
+{
+    int rc;
+    uint8_t len;
+    /* XXX: use this? */
+    //uint8_t *rspbuf;
+
+    /* Assume error; if all pass rc gets set to 0 */
+    rc = BLE_ERR_INV_HCI_CMD_PARMS;
+
+    /* Get length from command */
+    len = 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.
+     */ 
+    /* XXX */
+    //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_DISCONNECT_CMD:
+        if (len == BLE_HCI_DISCONNECT_CMD_LEN) {
+            rc = ble_ll_conn_hci_disconnect_cmd(cmdbuf);
+        }
+        /* Send command status instead of command complete */
+        rc += (BLE_ERR_MAX + 1);
+        break;
+    default:
+        rc = BLE_ERR_UNKNOWN_HCI_CMD;
+        break;
+    }
+
+    return rc;
+}
+
+static int
+ble_ll_hci_ctlr_bb_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
+{
+    int rc;
+    uint8_t len;
+    /* XXX: use this? */
+    //uint8_t *rspbuf;
+
+    /* Assume error; if all pass rc gets set to 0 */
+    rc = BLE_ERR_INV_HCI_CMD_PARMS;
+
+    /* Get length from command */
+    len = 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.
+     */ 
+    /* XXX */
+    //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_CB_SET_EVENT_MASK:
+        if (len == BLE_HCI_SET_EVENT_MASK_LEN) {
+            memcpy(g_ble_ll_hci_event_mask, cmdbuf, len);
+            rc = BLE_ERR_SUCCESS;
+        }
+        break;
+    default:
+        rc = BLE_ERR_UNKNOWN_HCI_CMD;
+        break;
+    }
+
+    return rc;
+}
+
 void
 ble_ll_hci_cmd_proc(struct os_event *ev)
 {
@@ -314,9 +435,11 @@ 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_LINK_CTRL:
+        rc = ble_ll_hci_link_ctrl_cmd_proc(cmdbuf, ocf, &rsplen);
+        break;
     case BLE_HCI_OGF_CTLR_BASEBAND:
-        /* XXX: Implement  */
-        rc = BLE_ERR_UNKNOWN_HCI_CMD;
+        rc = ble_ll_hci_ctlr_bb_cmd_proc(cmdbuf, ocf, &rsplen);
         break;
     default:
         /* XXX: Need to support other OGF. For now, return unsupported */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index a8e3d12..c37de90 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -23,6 +23,8 @@ struct os_mbuf;
 
 int host_hci_os_event_proc(struct os_event *ev);
 int host_hci_event_rx(uint8_t *data);
+int host_hci_cmd_set_event_mask(uint64_t event_mask);
+int host_hci_cmd_disconnect(uint16_t handle, uint8_t reason);
 int host_hci_cmd_le_set_scan_rsp_data(uint8_t *data, uint8_t len);
 int host_hci_cmd_le_set_adv_data(uint8_t *data, uint8_t len);
 int host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/host/src/ble_hs.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs.c b/net/nimble/host/src/ble_hs.c
index cc283b1..488bd5e 100644
--- a/net/nimble/host/src/ble_hs.c
+++ b/net/nimble/host/src/ble_hs.c
@@ -39,7 +39,7 @@
 static struct os_task ble_hs_task;
 static os_stack_t ble_hs_stack[BLE_HS_STACK_SIZE];
 
-#define HCI_CMD_BUFS        (6)
+#define HCI_CMD_BUFS        (8)
 #define HCI_CMD_BUF_SIZE    (260)       /* XXX: temporary, Fix later */
 struct os_mempool g_hci_cmd_pool;
 static os_membuf_t g_hci_cmd_buf[OS_MEMPOOL_BYTES(HCI_CMD_BUFS,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/host/src/host_dbg.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/host_dbg.c
index 736a719..4c545be 100644
--- a/net/nimble/host/src/host_dbg.c
+++ b/net/nimble/host/src/host_dbg.c
@@ -90,6 +90,32 @@ host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata)
     }
 }
 
+/**
+ * Display a disconnection complete command.
+ * 
+ * 
+ * @param evdata 
+ * @param len 
+ */
+void
+host_hci_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len)
+{
+    uint8_t status;
+    uint8_t reason;
+    uint16_t handle;
+
+    status = evdata[0];
+    handle = le16toh(evdata + 1);
+    /* Ignore reason if status is not success */
+    if (status != BLE_ERR_SUCCESS) {
+        reason = 0;
+    } else {
+        reason = evdata[3];
+    }
+    console_printf("Disconnection Complete: status=%u handle=%u reason=%u\n",
+                   status, handle, reason);
+}
+
 void
 host_hci_dbg_cmd_complete_disp(uint8_t *evdata, uint8_t len)
 {
@@ -145,6 +171,9 @@ host_hci_dbg_event_disp(uint8_t *evbuf)
     evdata = evbuf + 2;
 
     switch (evcode) {
+    case BLE_HCI_EVCODE_DISCONN_CMP:
+        host_hci_dbg_disconn_comp_disp(evdata, len);
+        break;
     case BLE_HCI_EVCODE_COMMAND_COMPLETE:
         host_hci_dbg_cmd_complete_disp(evdata, len);
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/host/src/host_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c
index a159468..47f7e64 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -41,20 +41,6 @@ static int host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len);
 static int host_hci_rx_le_meta(uint8_t event_code, uint8_t *data, int len);
 static int host_hci_rx_le_conn_complete(uint8_t subevent, uint8_t *data,
                                         int len);
-
-#define HCI_CMD_BUFS        (8)
-#define HCI_CMD_BUF_SIZE    (260)       /* XXX: temporary, Fix later */
-struct os_mempool g_hci_cmd_pool;
-os_membuf_t g_hci_cmd_buf[OS_MEMPOOL_SIZE(HCI_CMD_BUFS, HCI_CMD_BUF_SIZE)];
-
-/* XXX: this might be transport layer*/
-#define HCI_NUM_OS_EVENTS       (32)
-#define HCI_OS_EVENT_BUF_SIZE   (sizeof(struct os_event))
-
-struct os_mempool g_hci_os_event_pool;
-os_membuf_t g_hci_os_event_buf[OS_MEMPOOL_SIZE(HCI_NUM_OS_EVENTS, 
-                                               HCI_OS_EVENT_BUF_SIZE)];
-
 static uint16_t host_hci_buffer_sz;
 static uint8_t host_hci_max_pkts;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c
index 8414e77..fc0cf6a 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -29,7 +29,7 @@
 #include "ble_l2cap.h"
 
 static int
-host_hci_cmd_send(uint8_t *cmdbuf)
+host_hci_cmd_transport(uint8_t *cmdbuf)
 {
 #ifdef ARCH_sim
     return 0;
@@ -39,7 +39,7 @@ host_hci_cmd_send(uint8_t *cmdbuf)
 }
 
 static int
-host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata)
+host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata)
 {
     int rc;
     uint8_t *cmd;
@@ -51,13 +51,13 @@ host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata)
     rc = -1;
     cmd = os_memblock_get(&g_hci_cmd_pool);
     if (cmd) {
-        opcode = (BLE_HCI_OGF_LE << 10) | ocf;
+        opcode = (ogf << 10) | ocf;
         htole16(cmd, opcode);
         cmd[2] = len;
         if (len) {
             memcpy(cmd + BLE_HCI_CMD_HDR_LEN, cmddata, len);
         }
-        rc = host_hci_cmd_send(cmd);
+        rc = host_hci_cmd_transport(cmd);
         if (rc == 0) {
             host_hci_outstanding_opcode = opcode;
         } else {
@@ -69,6 +69,23 @@ host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata)
     return rc;
 }
 
+/**
+ * Send a LE command from the host to the controller.
+ * 
+ * @param ocf 
+ * @param len 
+ * @param cmddata 
+ * 
+ * @return int 
+ */
+static int
+host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata)
+{
+    int rc;
+    rc = host_hci_cmd_send(BLE_HCI_OGF_LE, ocf, len, cmddata);
+    return rc;
+}
+
 static int
 host_hci_cmd_le_whitelist_chg(uint8_t *addr, uint8_t addr_type, uint8_t ocf)
 {
@@ -201,6 +218,35 @@ host_hci_cmd_le_set_rand_addr(uint8_t *addr)
 }
 
 int
+host_hci_cmd_set_event_mask(uint64_t event_mask)
+{
+    int rc;
+    uint8_t cmd[BLE_HCI_SET_EVENT_MASK_LEN];
+
+    htole64(cmd, event_mask);
+    rc = host_hci_cmd_send(BLE_HCI_OGF_CTLR_BASEBAND,
+                           BLE_HCI_OCF_CB_SET_EVENT_MASK,
+                           BLE_HCI_SET_EVENT_MASK_LEN,
+                           cmd);
+    return rc;
+}
+
+int
+host_hci_cmd_disconnect(uint16_t handle, uint8_t reason)
+{
+    int rc;
+    uint8_t cmd[BLE_HCI_DISCONNECT_CMD_LEN];
+
+    htole16(cmd, handle);
+    cmd[2] = reason;
+    rc = host_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL,
+                           BLE_HCI_OCF_DISCONNECT_CMD,
+                           BLE_HCI_DISCONNECT_CMD_LEN,
+                           cmd);
+    return rc;
+}
+
+int
 host_hci_cmd_le_set_event_mask(uint64_t event_mask)
 {
     int rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 6ff1106..f67aa81 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -46,6 +46,13 @@
 /* NOTE: 0x07 not defined in specification  */
 #define BLE_HCI_OGF_LE                      (0x08)
 
+/* List of OCF for Link Control commands (OGF=0x01) */
+#define BLE_HCI_OCF_DISCONNECT_CMD          (0x0006)
+
+/* Command specific definitions */
+/* Disconnect command */
+#define BLE_HCI_DISCONNECT_CMD_LEN          (3)
+
 /* List of OCF for Controller and Baseband commands (OGF=0x03) */
 #define BLE_HCI_OCF_CB_SET_EVENT_MASK       (0x0001)
 #define BLE_HCI_OCF_CB_RESET                (0x0003)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/8323f4b7/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index e082257..c492680 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -24,9 +24,11 @@
 
 /* BLE */
 #include "nimble/ble.h"
+#include "nimble/hci_transport.h"
 #include "host/host_hci.h"
 #include "host/ble_hs.h"
 #include "controller/ble_ll.h"
+#include "controller/ble_ll_conn.h"
 
 /* Init all tasks */
 volatile int tasks_initialized;
@@ -62,10 +64,10 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
 #define BLETEST_ROLE_ADVERTISER         (0)
 #define BLETEST_ROLE_SCANNER            (1)
 #define BLETEST_ROLE_INITIATOR          (2)
-#define BLETEST_CFG_ROLE                (BLETEST_ROLE_INITIATOR)
+#define BLETEST_CFG_ROLE                (BLETEST_ROLE_ADVERTISER)
 #define BLETEST_CFG_FILT_DUP_ADV        (0)
 #define BLETEST_CFG_ADV_ITVL            (500000 / BLE_HCI_ADV_ITVL)
-#define BLETEST_CFG_ADV_TYPE            BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD
+#define BLETEST_CFG_ADV_TYPE            BLE_HCI_ADV_TYPE_ADV_IND
 #define BLETEST_CFG_ADV_FILT_POLICY     (BLE_HCI_ADV_FILT_NONE)
 #define BLETEST_CFG_SCAN_ITVL           (700000 / BLE_HCI_SCAN_ITVL)
 #define BLETEST_CFG_SCAN_WINDOW         (650000 / BLE_HCI_SCAN_ITVL)
@@ -87,6 +89,7 @@ struct os_eventq g_bletest_evq;
 struct os_callout_func g_bletest_timer;
 struct os_task bletest_task;
 os_stack_t bletest_stack[BLETEST_STACK_SIZE];
+uint32_t g_bletest_conn_end;
 
 void
 bletest_inc_adv_pkt_num(void)
@@ -288,17 +291,71 @@ bletest_execute(void)
     int rc;
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
-    /*  */
+    int i;
+    uint16_t pktlen;
+    uint16_t handle;
+    struct os_mbuf *om;
+    struct ble_ll_conn_sm *connsm;
+
+    handle = 1;
     if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
-        if (!g_bletest_state) {
+        if (g_bletest_state == 0) {
             rc = host_hci_cmd_le_set_adv_enable(1);
             host_hci_outstanding_opcode = 0;
             assert(rc == 0);
             g_bletest_state = 1;
+        } else if (g_bletest_state == 1) {
+            /* See if handle 1 has been created. If so, send packets */
+            connsm = ble_ll_conn_find_active_conn(handle);
+            if (connsm) {
+                /* Set connection end time */
+                g_bletest_conn_end = os_time_get() + (OS_TICKS_PER_SEC * 17);
+                g_bletest_state = 2;
+            }
+        } else if (g_bletest_state == 2) {
+            if ((int32_t)(os_time_get() - g_bletest_conn_end) >= 0) {
+                g_bletest_state = 3;
+                host_hci_cmd_disconnect(handle, BLE_ERR_REM_USER_CONN_TERM);
+                g_next_os_time += OS_TICKS_PER_SEC;
+                return;
+            }
+            ble_get_packet(om);
+            if (om) {
+
+                /* set payload length */
+                pktlen = 32;
+                om->om_len = 32 + 4;
+
+                /* Put the HCI header in the mbuf */
+                htole16(om->om_data, handle);
+                htole16(om->om_data + 2, om->om_len);
+
+                /* Place L2CAP header in packet */
+                htole16(om->om_data + 4, pktlen);
+                om->om_data[6] = 0;
+                om->om_data[7] = 0;
+
+                /* Fill with incrementing pattern */
+                for (i = 0; i < pktlen; ++i) {
+                    om->om_data[8 + i] = (uint8_t)(i + 1);
+                }
+
+                /* Add length */
+                om->om_len += 4;
+                OS_MBUF_PKTHDR(om)->omp_len = om->om_len;
+                ble_hci_transport_host_acl_data_send(om);
+            }
+        } else {
+            /* We should be waiting for disconnect */
+            connsm = ble_ll_conn_find_active_conn(handle);
+            if (!connsm) {
+                g_bletest_state = 0;
+            }
         }
-        g_next_os_time += (OS_TICKS_PER_SEC * 60);
+        g_next_os_time += OS_TICKS_PER_SEC;
     }
 #endif
+
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
     /* Enable scanning */
     if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
@@ -333,7 +390,7 @@ bletest_timer_cb(void *arg)
     bletest_execute();
 
     /* Re-start the timer */
-    os_callout_reset(&g_bletest_timer.cf_c, OS_TICKS_PER_SEC);
+    os_callout_reset(&g_bletest_timer.cf_c, OS_TICKS_PER_SEC/2);
 }
 
 /**
@@ -380,6 +437,15 @@ bletest_task_handler(void *arg)
     assert(rc == 0);
     host_hci_outstanding_opcode = 0;
 
+    /* Turn on all events */
+    event_mask = 0xffffffffffffffff;
+    rc = host_hci_cmd_set_event_mask(event_mask);
+    assert(rc == 0);
+    host_hci_outstanding_opcode = 0;
+
+    /* Wait some time before starting */
+    os_time_delay(OS_TICKS_PER_SEC);
+
     /* Init bletest variables */
     g_bletest_state = 0;
     g_next_os_time = os_time_get();
@@ -412,6 +478,8 @@ bletest_task_handler(void *arg)
 static int
 init_tasks(void)
 {
+    int rc;
+
     os_task_init(&bletest_task, "bletest", bletest_task_handler, NULL, 
                  BLETEST_TASK_PRIO, OS_WAIT_FOREVER, bletest_stack, 
                  BLETEST_STACK_SIZE);
@@ -419,7 +487,8 @@ init_tasks(void)
     tasks_initialized = 1;
 
     /* Initialize host HCI */
-    ble_hs_init(HOST_TASK_PRIO);
+    rc = ble_hs_init(HOST_TASK_PRIO);
+    assert(rc == 0);
 
     /* Initialize the BLE LL */
     ble_ll_init();