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/11/28 17:01:03 UTC

incubator-mynewt-larva git commit: Refactor connection handle code. Place all connections on a free list and assign the handles on init. Add active/free connection lists

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 48d5b34fc -> 15a4a8cf3


Refactor connection handle code. Place all connections on a free list and assign the handles on init. Add active/free connection lists


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/15a4a8cf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/15a4a8cf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/15a4a8cf

Branch: refs/heads/master
Commit: 15a4a8cf3c33c842ce409d70d0da9ea4c75c8e03
Parents: 48d5b34
Author: wes3 <wi...@micosa.io>
Authored: Sat Nov 28 08:00:33 2015 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Sat Nov 28 08:00:49 2015 -0800

----------------------------------------------------------------------
 .../controller/include/controller/ble_ll.h      |   25 +-
 .../controller/include/controller/ble_ll_conn.h |    4 +-
 net/nimble/controller/src/ble_ll.c              |  170 ++-
 net/nimble/controller/src/ble_ll_adv.c          |    1 -
 net/nimble/controller/src/ble_ll_conn.c         | 1077 +++++++++++++-----
 net/nimble/drivers/native/src/ble_phy.c         |    4 +-
 net/nimble/drivers/nrf52/src/ble_phy.c          |   16 +-
 net/nimble/include/nimble/ble.h                 |    8 +
 project/bletest/src/main.c                      |    4 +-
 9 files changed, 942 insertions(+), 367 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 91ff4cf..a39f4a1 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -17,6 +17,11 @@
 #ifndef H_BLE_LL_
 #define H_BLE_LL_
 
+#include "hal/hal_cputime.h"
+
+/* Wait for response timer */
+typedef void (*ble_ll_wfr_func)(void *arg);
+
 /* 
  * Global Link Layer data object. There is only one Link Layer data object
  * per controller although there may be many instances of the link layer state
@@ -33,6 +38,10 @@ struct ble_ll_obj
     /* Receive packet (from phy) event */
     struct os_event ll_rx_pkt_ev;
 
+    /* Wait for response timer */
+    struct cpu_timer ll_wfr_timer;
+    ble_ll_wfr_func ll_wfr_func;
+
     /* Packet receive queue */
     STAILQ_HEAD(ll_rxpkt_qh, os_mbuf_pkthdr) ll_rx_pkt_q;
 };
@@ -41,6 +50,10 @@ extern struct ble_ll_obj g_ble_ll_data;
 /* Link layer statistics */
 struct ble_ll_stats
 {
+    uint32_t hci_cmds;
+    uint32_t hci_cmd_errs;
+    uint32_t hci_events_sent;
+    uint32_t bad_ll_state;
     uint32_t rx_crc_ok;
     uint32_t rx_crc_fail;
     uint32_t rx_bytes;
@@ -53,10 +66,6 @@ struct ble_ll_stats
     uint32_t rx_scan_ind;
     uint32_t rx_unk_pdu;
     uint32_t rx_malformed_pkts;
-    uint32_t hci_cmds;
-    uint32_t hci_cmd_errs;
-    uint32_t hci_events_sent;
-    uint32_t bad_ll_state;
 };
 extern struct ble_ll_stats g_ble_ll_stats;
 
@@ -404,7 +413,7 @@ int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
 int ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan);
 
 /* Called by the PHY when a packet reception ends */
-int ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok);
+int ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok);
 
 /*--- Controller API ---*/
 /* Set the link layer state */
@@ -416,4 +425,10 @@ void ble_ll_event_send(struct os_event *ev);
 /* Set random address */
 int ble_ll_set_random_addr(uint8_t *addr);
 
+/* Enable wait for response timer */
+void ble_ll_wfr_enable(uint32_t cputime, ble_ll_wfr_func wfr_cb, void *arg);
+
+/* Disable wait for response timer */
+void ble_ll_wfr_disable(void);
+
 #endif /* H_LL_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 4c3d535..f58a140 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -37,6 +37,8 @@ void ble_ll_conn_slave_start(uint8_t *rxbuf);
 void ble_ll_conn_spvn_timeout(void *arg);
 void ble_ll_conn_event_end(void *arg);
 void ble_ll_conn_init(void);
-void ble_ll_conn_rsp_rxd(void);
+void ble_ll_conn_rx_pdu_start(void);
+int ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok);
+void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok);
 
 #endif /* H_BLE_LL_CONN_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 691a057..c196725 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -26,6 +26,7 @@
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_conn.h"
 #include "controller/ble_ll_hci.h"
+#include "hal/hal_cputime.h"
 
 /* 
  * XXX: Just thought of something! Can I always set the DEVMATCH bit at
@@ -67,12 +68,12 @@ struct os_task g_ble_ll_task;
 os_stack_t g_ble_ll_stack[BLE_LL_STACK_SIZE];
 
 /**
- * Counts received packets by type 
+ * Counts the number of advertising PDU's by type. 
  * 
  * @param pdu_type 
  */
 static void
-ble_ll_count_rx_pkts(uint8_t pdu_type)
+ble_ll_count_rx_adv_pdus(uint8_t pdu_type)
 {
     /* Count received packet types  */
     switch (pdu_type) {
@@ -104,8 +105,6 @@ ble_ll_count_rx_pkts(uint8_t pdu_type)
         ++g_ble_ll_stats.rx_unk_pdu;
         break;
     }
-
-    /* XXX: what about data packets? */
 }
 
 int
@@ -232,6 +231,48 @@ ble_ll_pdu_tx_time_get(uint16_t len)
 }
 
 /**
+ * Wait for response timeout function 
+ *  
+ * Context: interrupt (ble scheduler) 
+ * 
+ * @param arg 
+ */
+void
+ble_ll_wfr_timer_exp(void *arg)
+{
+    struct ble_ll_obj *lldata;
+
+    lldata = &g_ble_ll_data;
+    lldata->ll_wfr_func(arg);
+}
+
+/**
+ * Enable the wait for response timer 
+ * 
+ * @param cputime 
+ * @param wfr_cb 
+ * @param arg 
+ */
+void
+ble_ll_wfr_enable(uint32_t cputime, ble_ll_wfr_func wfr_cb, void *arg)
+{
+    /* XXX: should I reset func callback here too? Not use a global
+       ble_ll_wfr_timer expiration? */
+    g_ble_ll_data.ll_wfr_func = wfr_cb;
+    g_ble_ll_data.ll_wfr_timer.arg = arg;
+    cputime_timer_start(&g_ble_ll_data.ll_wfr_timer, cputime);
+}
+
+/**
+ * Disable the wait for response timer
+ */
+void
+ble_ll_wfr_disable(void)
+{
+    cputime_timer_stop(&g_ble_ll_data.ll_wfr_timer);
+}
+
+/**
  * ll rx pkt in proc
  *  
  * Process received packet from PHY.
@@ -260,61 +301,56 @@ ble_ll_rx_pkt_in_proc(void)
         STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_rx_pkt_q, omp_next);
         OS_EXIT_CRITICAL(sr);
 
-        /* XXX: need to check if this is an adv channel or data channel */
-
         /* Count statistics */
         rxbuf = m->om_data;
-        pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
         ble_hdr = BLE_MBUF_HDR_PTR(m); 
         if (ble_hdr->crcok) {
             /* The total bytes count the PDU header and PDU payload */
             g_ble_ll_stats.rx_bytes += pkthdr->omp_len;
             ++g_ble_ll_stats.rx_crc_ok;
-            ble_ll_count_rx_pkts(pdu_type);
         } else {
             ++g_ble_ll_stats.rx_crc_fail;
         }
 
-        /* 
-         * XXX: The reason I dont bail earlier on bad CRC is that
-         * there may be some connection stuff I need to do with a packet
-         * that has failed the CRC.
-         */ 
-
-        /* Process the PDU */
-        switch (g_ble_ll_data.ll_state) {
-        case BLE_LL_STATE_ADV:
-            if (ble_hdr->crcok && (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
-                ble_ll_adv_conn_req_rxd(rxbuf, ble_hdr->flags);
-            }
-            break;
-        case BLE_LL_STATE_SCANNING:
+        if (ble_hdr->channel < BLE_PHY_NUM_DATA_CHANS) {
+            ble_ll_conn_rx_data_pdu(m, ble_hdr->crcok);
+        } else {
             if (ble_hdr->crcok) {
-                ble_ll_scan_rx_pdu_proc(pdu_type, rxbuf, ble_hdr->rssi,
-                                        ble_hdr->flags);
+                /* Get advertising PDU type */
+                pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
+                ble_ll_count_rx_adv_pdus(pdu_type);
+
+                /* Process the PDU */
+                switch (g_ble_ll_data.ll_state) {
+                case BLE_LL_STATE_ADV:
+                    if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
+                        ble_ll_adv_conn_req_rxd(rxbuf, ble_hdr->flags);
+                    }
+                    break;
+                case BLE_LL_STATE_SCANNING:
+                    ble_ll_scan_rx_pdu_proc(pdu_type, rxbuf, ble_hdr->rssi,
+                                            ble_hdr->flags);
+
+                    /* We need to re-enable the PHY if we are in idle state */
+                    if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
+                        /* XXX: If this returns error, we will need to attempt
+                         * to re-start scanning! */
+                        ble_phy_rx();
+                    }
+                    break;
+                case BLE_LL_STATE_INITIATING:
+                    ble_ll_init_rx_pdu_proc(rxbuf, ble_hdr);
+                    break;
+                default:
+                    /* Any other state should never occur */
+                    assert(0);
+                    break;
+                }
             }
 
-            /* We need to re-enable the PHY if we are in idle state */
-            if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
-                /* XXX: If this returns error, we will need to attempt to
-                   re-start scanning! */
-                ble_phy_rx();
-            }
-            break;
-        case BLE_LL_STATE_INITIATING:
-            ble_ll_init_rx_pdu_proc(rxbuf, ble_hdr);
-            break;
-        case BLE_LL_STATE_CONNECTION:
-            /* XXX: implement */
-            break;
-        default:
-            /* We should not receive packets in standby state! */
-            assert(0);
-            break;
+            /* Free the packet buffer */
+            os_mbuf_free(&g_mbuf_pool, m);
         }
-
-        /* Free the packet buffer */
-        os_mbuf_free(&g_mbuf_pool, m);
     }
 }
 
@@ -351,7 +387,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
     uint8_t pdu_type;
     uint8_t *rxbuf;
 
-    /* XXX: need to check if this is an adv channel or data channel */
+    /* Check channel type */
     rxbuf = rxpdu->om_data;
     if (chan < BLE_PHY_NUM_DATA_CHANS) {
         /* 
@@ -360,8 +396,8 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
          */
         /* XXX: check access address for surety? What to do... */
         if (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION) {
-            /* Set flag in connection noting we have received a response */
-            ble_ll_conn_rsp_rxd();
+            /* Call conection pdu rx start function */
+            ble_ll_conn_rx_pdu_start();
 
             /* Set up to go from rx to tx */
             rc = 1;
@@ -403,7 +439,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
         rc = 0;
         break;
     default:
-        /* Should not be in this state */
+        /* Should not be in this state! */
         rc = -1;
         ++g_ble_ll_stats.bad_ll_state;
         break;
@@ -425,7 +461,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok)
+ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
 {
     int rc;
     int badpkt;
@@ -437,7 +473,34 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok)
     /* Set the rx buffer pointer to the start of the received data */
     rxbuf = rxpdu->om_data;
 
-    /* XXX: need to check if this is an adv channel or data channel */
+    /* Check channel type */
+    if (chan < BLE_PHY_NUM_DATA_CHANS) {
+        /* Better be in connection state */
+        assert(g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION);
+
+        /* Set length in the received PDU */
+        mblen = rxbuf[1] + BLE_LL_PDU_HDR_LEN;
+        OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
+        rxpdu->om_len = mblen;
+
+        /* 
+         * NOTE: this looks a bit odd, and it is, but for now we place the
+         * received PDU on the Link Layer task before calling the rx end
+         * function. We do this to guarantee connection event end ordering
+         * and receive PDU processing.
+         */
+        ble_ll_rx_pdu_in(rxpdu);
+
+        /* 
+         * Data channel pdu. We should be in CONNECTION state with an
+         * ongoing connection.
+         */
+        /* XXX: check access address for surety? What to do... */
+        rc = ble_ll_conn_rx_pdu_end(rxpdu, crcok);
+        return rc;
+    } 
+
+    /* Get advertising PDU type */
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
     len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
 
@@ -501,9 +564,10 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t crcok)
         }
         break;
     case BLE_LL_STATE_CONNECTION:
-        /* XXX */
+        /* XXX: we should never get here! What to do??? */
         break;
     default:
+        /* This is an invalid state. */
         assert(0);
         break;
     }
@@ -610,6 +674,10 @@ ble_ll_init(void)
     /* Initialize receive packet (from phy) event */
     lldata->ll_rx_pkt_ev.ev_type = BLE_LL_EVENT_RX_PKT_IN;
 
+    /* Initialize wait for response timer */
+    cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp, 
+                       NULL);
+
     /* Initialize LL HCI */
     ble_ll_hci_init();
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 08eee0e..a04a395 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -345,7 +345,6 @@ ble_ll_adv_rx_cb(struct ble_ll_sched_item *sch)
     return BLE_LL_SCHED_STATE_DONE;
 }
 
-
 /**
  * Scheduler callback when an advertising PDU has been sent. 
  * 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/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 474af09..82700e1 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -31,45 +31,57 @@
 #include "hal/hal_cputime.h"
 
 /* XXX TODO
- * 1) Implemement connection supervisor timeout.
- *  -> Need to re-start when we receive a packet and set the proper timeout.
- * 2) Add set channel map command and implement channel change procedure.
- * 3) Closing the connection: the MD bit.
- * 4) notifying host about connections: how often do we need to do this? On
- * creation, establishment and/or loss?
- * 5) Deal with window widening. Easy...
- * 6) Close connection if window widening gets too big! 4.5.7
- * 7) How does state get set to ESTABLISHED? Do that...
- * 8) Set up later connection schedule events.
- * 8.5) How do we set the end event? Especially if we are receiving? Need
- * to figure this out.
- * 9) Implement flow control and all that.
- * 10) Implement getting a data packet. How do we do that?
- * 11) Send connection complete event when connection dies.
- * 12) Data channel index and all that code. Must make sure we are setting this
- * correctly. Set for 1st connection event but not for other events.
- * 13) Add more statistics
- * 14) Update event counter with each event!
- * 15) Link layer control procedures and timers
- * 16) Did we implement what happens if we receive a connection request from
+ * 1) Add set channel map command and implement channel change procedure.
+ * 5) Implement getting a data packet. How do we do that?
+ * 6) Make sure we have implemented all ways a connection can die/end. Not
+ * a connection event; I mean the termination of a connection.
+ * 8) Link layer control procedures and timers
+ * 9) Did we implement what happens if we receive a connection request from
  * a device we are already connected to? We also need to check to see if we
  * were asked to create a connection when one already exists. Note that
  * an initiator should only send connection requests to devices it is not
  * already connected to. Make sure this cant happen.
- * 17) Dont forget to set pkt_rxd flag for slave latency. Needs to get reset
- * after each M-S transaction.
- * 18) Make sure we check incoming data packets for size and all that. You
+ * 10) Make sure we check incoming data packets for size and all that. You
  * know, supported octets and all that. For both rx and tx.
- * 19) Make sure we handle rsp_rxd and pkt_rxd correctly (clearing/checking
- * setting them).
+ * 11) What kind of protection do I need on the conn_txq? The LL will need to
+ * disable interrupts... not sure about ISR's.
+ * 12) Add/remove connection from the active connection list.
+ * 13) Make sure we are setting the schedule end time properly for both slave
+ * and master. We should just set this to the end of the connection event.
+ * 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).
+ * 14) Make sure we set LLID correctly!
+ * 15) So what if I fail an empty pdu? Do I have to specifically retransmit
+ * that one? If I were to take a new data pdu and replace the empty pdu with
+ * the new data pdu? Could I do this or is that bad?
+ * 16) Make sure we are doing the right thing in the connection rx pdu start
+ * and end functions if we are a slave.
+ */
+
+/* 
+ * XXX: Possible improvements
+ * 1) Not sure I like the fact that the wait for response timer will still
+ * fire off if we get a received packet. I need to look into that. I think
+ * I should disable the sucker if we get a reception and not have it fire off.
+ * 2) See what connection state machine elements are purely master and
+ * purely slave. We can make a union of them.
+ * 3) Do I need a memory pool of connection elements? Probably not.
  */
 
 /* Connection event timing */
 #define BLE_LL_CONN_ITVL_USECS              (1250)
 #define BLE_LL_CONN_TX_WIN_USECS            (1250)
 #define BLE_LL_CONN_CE_USECS                (625)
+#define BLE_LL_CONN_TX_WIN_MIN              (1)         /* in tx win units */
+#define BLE_LL_CONN_SLAVE_LATENCY_MAX       (499)
 
-/* XXX: probably should be moved and made more accurate */
+/* 
+ * The amount of time that we will wait to hear the start of a receive
+ * packet in a connection event.
+ * 
+ * XXX: move this definition and make it more accurate.
+ */
 #define BLE_LL_WFR_USECS                    (100)
 
 /* Channel map size */
@@ -80,6 +92,7 @@
 #define BLE_LL_CONN_CFG_TX_WIN_OFF          (0)
 #define BLE_LL_CONN_CFG_MASTER_SCA          (BLE_MASTER_SCA_251_500_PPM << 5)
 #define BLE_LL_CONN_CFG_MAX_CONNS           (8)
+#define BLE_LL_CONN_CFG_OUR_SCA             (500)   /* in ppm */
 
 /* LL configuration definitions */
 #define BLE_LL_CFG_SUPP_MAX_RX_BYTES        (27)
@@ -103,13 +116,11 @@
 /* Connection request */
 #define BLE_LL_CONN_REQ_ADVA_OFF    (BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN)
 
-/* 
- * XXX: I just had a thought. Why do I need to allocate connection handles?
- * For every connection state machine I have I should just give it a handle
- * inside it. They can sit on the pool and I can use them in round robin
- * order. This might save some code! This works only if I create the pool
- * of connections to start.
- */
+/* Sleep clock accuracy table (in ppm) */
+static const uint16_t g_ble_sca_ppm_tbl[8] =
+{
+    500, 250, 150, 100, 75, 50, 30, 20
+};
 
 /* Global Link Layer connection parameters */
 struct ble_ll_conn_global_params
@@ -153,11 +164,22 @@ struct ble_ll_conn_sm
     uint8_t last_unmapped_chan;
     uint8_t num_used_chans;
 
+    /* Ack/Flow Control */
+    uint8_t tx_seqnum;          /* note: can be 1 bit */
+    uint8_t next_exp_seqnum;    /* note: can be 1 bit */
+    uint8_t last_txd_md;        /* note can be 1 bit */
+    uint8_t cons_rxd_bad_crc;   /* note: can be 1 bit */
+    uint8_t last_rxd_sn;        /* note: cant be 1 bit given current code */
+    uint8_t last_rxd_hdr_byte;  /* note: possibly can make 1 bit since we
+                                   only use the MD bit now */
+
     /* connection event timing/mgmt */
-    uint8_t rsp_rxd;
-    uint8_t pkt_rxd;
+    uint8_t rsp_rxd;            /* note: can be 1 bit */
+    uint8_t pkt_rxd;            /* 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 */
     uint16_t conn_itvl;
     uint16_t slave_latency;
     uint16_t tx_win_off;
@@ -167,8 +189,12 @@ struct ble_ll_conn_sm
     uint16_t supervision_tmo;
     uint16_t conn_handle;
     uint32_t access_addr;
-    uint32_t crcinit;       /* only low 24 bits used */
+    uint32_t crcinit;           /* only low 24 bits used */
     uint32_t anchor_point;
+    uint32_t last_anchor_point;
+    uint32_t ce_end_time;   /* cputime at which connection event should end */
+    uint32_t slave_cur_tx_win_usecs;
+    uint32_t slave_cur_window_widening;
 
     /* address information */
     uint8_t own_addr_type;
@@ -186,6 +212,12 @@ struct ble_ll_conn_sm
 
     /* Packet transmit queue */
     STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
+
+    /* List entry for active connection pool */
+    union {
+        SLIST_ENTRY(ble_ll_conn_sm) conn_sle;
+        STAILQ_ENTRY(ble_ll_conn_sm) conn_stqe;
+    };
 };
 
 /* Pointer to connection state machine we are trying to create */
@@ -194,17 +226,16 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
 /* Pointer to current connection */
 struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
 
-/* Connection handles */
-static uint8_t g_ble_ll_conn_handles[(BLE_LL_CONN_CFG_MAX_CONNS + 7) / 8];
-static uint16_t g_ble_ll_conn_handles_out;
-
 /* Connection pool elements */
 struct os_mempool g_ble_ll_conn_pool;
 os_membuf_t g_ble_ll_conn_buf[OS_MEMPOOL_SIZE(BLE_LL_CONN_CFG_MAX_CONNS, 
                                               sizeof(struct ble_ll_conn_sm))];
 
 /* List of active connections */
-static SLIST_HEAD(, ble_hs_conn) g_ble_ll_conn_active_list;
+static SLIST_HEAD(, ble_ll_conn_sm) g_ble_ll_conn_active_list;
+
+/* List of free connections */
+static STAILQ_HEAD(, ble_ll_conn_sm) g_ble_ll_conn_free_list;
 
 /* Statistics */
 struct ble_ll_conn_stats
@@ -212,16 +243,75 @@ struct ble_ll_conn_stats
     uint32_t cant_set_sched;
     uint32_t conn_ev_late;
     uint32_t wfr_expirations;
+    uint32_t no_tx_pdu;
+    uint32_t no_conn_sm;
+    uint32_t no_free_conn_sm;
+    uint32_t slave_rxd_bad_conn_req_params;
+    uint32_t slave_ce_failures;
+    uint32_t rx_resent_pdus;
+    uint32_t data_pdu_rx_valid;
+    uint32_t data_pdu_rx_invalid;
+    uint32_t data_pdu_txg;
+    uint32_t data_pdu_txf;
 };
 struct ble_ll_conn_stats g_ble_ll_conn_stats;
 
 /* "Dummy" mbuf containing an "Empty PDU" */
-#define BLE_LL_DUMMY_EMPTY_PDU_SIZE     \
-    ((sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + 4) / 4)
+#define BLE_LL_DUMMY_EMPTY_PDU_SIZE ((BLE_MBUF_PKT_OVERHEAD + 4) / 4)
 
 static uint32_t g_ble_ll_empty_pdu[BLE_LL_DUMMY_EMPTY_PDU_SIZE];
 
 /**
+ * Get a connection state machine.
+ */
+struct ble_ll_conn_sm *
+ble_ll_conn_sm_get(void)
+{
+    struct ble_ll_conn_sm *connsm;
+
+    connsm = STAILQ_FIRST(&g_ble_ll_conn_free_list);
+    if (connsm) {
+        STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, conn_stqe);
+    } else {
+        ++g_ble_ll_conn_stats.no_free_conn_sm;
+    }
+
+    return connsm;
+}
+
+/**
+ * Calculate the amount of window widening for a given connection event. This 
+ * is the amount of time that a slave has to account for when listening for 
+ * the start of a connection event. 
+ * 
+ * @param connsm Pointer to connection state machine.
+ * 
+ * @return uint32_t The current window widening amount (in microseconds)
+ */
+uint32_t
+ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
+{
+    uint32_t total_sca_ppm;
+    uint32_t window_widening;
+    int32_t time_since_last_anchor;
+    uint32_t delta_msec;
+
+    window_widening = 0;
+
+    time_since_last_anchor = (int32_t)(connsm->anchor_point - 
+                                       connsm->last_anchor_point);
+    if (time_since_last_anchor > 0) {
+        delta_msec = cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
+        total_sca_ppm = g_ble_sca_ppm_tbl[connsm->master_sca] + 
+                        BLE_LL_CONN_CFG_OUR_SCA;
+        window_widening = (total_sca_ppm * delta_msec) / 1000;
+    }
+
+    /* XXX: spec gives 16 usecs error btw. Probably should add that in */
+    return window_widening;
+}
+
+/**
  * Calculates the number of used channels in the channel map 
  * 
  * @param chmap 
@@ -257,70 +347,6 @@ ble_ll_conn_calc_used_chans(uint8_t *chmap)
     return used_channels;
 }
 
-/**
- * Free an allocated connection handle 
- * 
- * @param handle The connection handle to free.
- */
-static void
-ble_ll_conn_handle_free(uint16_t handle)
-{
-    uint8_t bytepos;
-    uint8_t mask;
-
-    /* Make sure handle is valid */
-    assert(handle < BLE_LL_CONN_CFG_MAX_CONNS);
-    assert(g_ble_ll_conn_handles_out != 0);
-
-    /* Get byte position and bit position */
-    bytepos = handle / 8;
-    mask = 1 << (handle & 0x7);
-
-    assert((g_ble_ll_conn_handles[bytepos] & mask) != 0);
-
-    g_ble_ll_conn_handles[bytepos] &= ~mask;
-    --g_ble_ll_conn_handles_out;
-}
-
-/**
- * Allocate a connection handle. This will allocate an unused connection 
- * handle. 
- * 
- * @return uint16_t 
- */
-static uint16_t
-ble_ll_conn_handle_alloc(void)
-{
-    uint8_t bytepos;
-    uint8_t bitpos;
-    int handle;
-
-    /* Make sure there is a handle that exists */
-    if (g_ble_ll_conn_handles_out == BLE_LL_CONN_CFG_MAX_CONNS) {
-        /* Handles can only be in range 0 to 0x0EFF */
-        return 0xFFFF;
-    }
-
-    /* Return an unused handle */
-    for (handle = 0; handle < BLE_LL_CONN_CFG_MAX_CONNS; ++handle) {
-        /* Get byte position and bit position */
-        bytepos = handle / 8;
-        bitpos = handle & 0x7;
-
-        /* See if handle avaiable */
-        if ((g_ble_ll_conn_handles[bytepos] & (1 << bitpos)) == 0) {
-            g_ble_ll_conn_handles[bytepos] |= (1 << bitpos);
-            ++g_ble_ll_conn_handles_out;
-            break;
-        }
-    }
-
-    /* We better have a free one! If not, something wrong! */
-    assert(handle < BLE_LL_CONN_CFG_MAX_CONNS);
-
-    return handle;
-}
-
 static uint32_t
 ble_ll_conn_calc_access_addr(void)
 {
@@ -468,54 +494,190 @@ ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn)
 }
 
 /**
- * Connection end schedule callback. Called when the scheduled connection 
- * event ends. 
+ * Callback for connection wait for response timer. 
  *  
  * Context: Interrupt 
+ *
+ * @param sch 
+ * 
+ */
+static void
+ble_ll_conn_wfr_timer_exp(void *arg)
+{
+    struct ble_ll_conn_sm *connsm;
+
+    connsm = (struct ble_ll_conn_sm *)arg;
+    if (connsm->rsp_rxd == 0) {
+        ble_ll_event_send(&connsm->conn_ev_end);
+        ++g_ble_ll_conn_stats.wfr_expirations;
+    }
+}
+
+/**
+ * Callback for slave when it transmits a data pdu and the connection event
+ * ends after the transmission.
  *  
+ * Context: Interrupt 
+ *
  * @param sch 
  * 
- * @return int 
  */
-static int
-ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
+static void
+ble_ll_conn_wait_txend(void *arg)
 {
-    int rc;
     struct ble_ll_conn_sm *connsm;
 
-    connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
+    connsm = (struct ble_ll_conn_sm *)arg;
     ble_ll_event_send(&connsm->conn_ev_end);
-    rc = BLE_LL_SCHED_STATE_DONE;
+}
+
+/**
+ * Called when we want to send a data channel pdu inside a connection event. 
+ * 
+ * @param connsm 
+ * 
+ * @return int 0: success; otherwise failure to transmit
+ */
+static int
+ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
+{
+    int rc;
+    uint8_t md;
+    uint8_t hdr_byte;
+    uint8_t end_transition;
+    uint32_t wfr_time;
+    uint32_t ticks;
+    struct os_mbuf *m;
+    struct ble_mbuf_hdr *ble_hdr;
+    struct os_mbuf_pkthdr *pkthdr;
+    struct os_mbuf_pkthdr *nextpkthdr;
+
+    /*
+     * Get packet off transmit queue. If not available, send empty PDU. Set
+     * the more data bit as well. For a slave, we will set it regardless of
+     * connection event end timing (master will deal with that for us or the
+     * connection event will be terminated locally). For a master, we only
+     * set the MD bit if we have enough time to send the current PDU, get
+     * a response and send the next packet and get a response.
+     */
+    md = 0;
+    pkthdr = STAILQ_FIRST(&connsm->conn_txq);
+    if (pkthdr) {
+        m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+        nextpkthdr = STAILQ_NEXT(pkthdr, omp_next);
+        if (nextpkthdr) {
+            md = 1;
+            if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+                /* 
+                 * XXX: this calculation is based on using the current time
+                 * and assuming the transmission will occur an IFS time from
+                 * now. This is not the most accurate especially if we have
+                 * received a frame and we are replying to it.
+                 */ 
+                ticks = (BLE_LL_IFS * 4) + (2 * connsm->eff_max_rx_time) +
+                    ble_ll_pdu_tx_time_get(pkthdr->omp_len) + 
+                    ble_ll_pdu_tx_time_get(nextpkthdr->omp_len);
+                ticks = cputime_usecs_to_ticks(ticks);
+                if ((cputime_get32() + ticks) >= connsm->ce_end_time) {
+                    md = 0;
+                }
+            }
+        }
+    } else {
+        /* Send empty pdu */
+        m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
+    }
+
+    /* Set SN, MD, NESN in transmit PDU */
+    hdr_byte = m->om_data[0];
+
+    /* 
+     * If this is a retry, we keep the LLID and SN. If not, we presume
+     * that the LLID is set and all other bits are 0 in the first header
+     * byte.
+     */
+    ble_hdr = BLE_MBUF_HDR_PTR(m);
+    if (ble_hdr->flags & BLE_MBUF_HDR_F_TXD) {
+        hdr_byte &= ~(BLE_LL_DATA_HDR_MD_MASK | BLE_LL_DATA_HDR_NESN_MASK);
+    } else {
+        if (connsm->tx_seqnum) {
+            hdr_byte |= BLE_LL_DATA_HDR_SN_MASK;
+        }
+        ble_hdr->flags |= BLE_MBUF_HDR_F_TXD;
+    }
+
+    /* If we have more data, set the bit */
+    if (md) {
+        hdr_byte |= BLE_LL_DATA_HDR_MD_MASK;
+    }
+
+    /* Set NESN (next expected sequence number) bit */
+    if (connsm->next_exp_seqnum) {
+        hdr_byte |= BLE_LL_DATA_HDR_NESN_MASK;
+    }
+
+    /* Set the header byte in the outgoing frame */
+    m->om_data[0] = hdr_byte;
+
+    /* 
+     * If we are a slave, check to see if this transmission will end the
+     * connection event. We will end the connection event if we have
+     * 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)) {
+        end_transition = BLE_PHY_TRANSITION_NONE;
+    }
+
+    rc = ble_phy_tx(m, beg_transition, end_transition);
+    if (!rc) {
+        /* Set last transmitted MD bit */
+        connsm->last_txd_md = md;
+
+        /* Reset response received flag */
+        connsm->rsp_rxd = 0;
+
+        /* XXX: at some point I should implement the transmit end interrupt
+           from the PHY. When I do that I will change this code */
+        /* Set wait for response timer */
+        wfr_time = cputime_get32();
+        if (end_transition == BLE_PHY_TRANSITION_TX_RX) {
+            wfr_time += cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
+                                       ble_ll_pdu_tx_time_get(m->om_len) +
+                                       BLE_LL_IFS +
+                                       BLE_LL_WFR_USECS);
+            ble_ll_wfr_enable(wfr_time, ble_ll_conn_wfr_timer_exp, connsm);
+        } else {
+            wfr_time += cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
+                                       ble_ll_pdu_tx_time_get(m->om_len));
+            ble_ll_wfr_enable(wfr_time, ble_ll_conn_wait_txend, connsm);
+        }
+    }
+
     return rc;
 }
 
 /**
- * Callback for connection wait for response timer. 
+ * Connection end schedule callback. Called when the scheduled connection 
+ * event ends. 
  *  
  * Context: Interrupt 
- *
+ *  
  * @param sch 
  * 
  * @return int 
  */
 static int
-ble_ll_conn_wfr_sched_cb(struct ble_ll_sched_item *sch)
+ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
 {
-    int rc;
     struct ble_ll_conn_sm *connsm;
 
     connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
-    if (connsm->rsp_rxd) {
-        /* For now just set to end time */
-        sch->next_wakeup = sch->end_time;
-        sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
-        rc = BLE_LL_SCHED_STATE_RUNNING;
-    } else {
-        ble_ll_event_send(&connsm->conn_ev_end);
-        rc = BLE_LL_SCHED_STATE_DONE;
-        ++g_ble_ll_conn_stats.wfr_expirations;
-    }
-    return rc;
+    ble_ll_event_send(&connsm->conn_ev_end);
+    return BLE_LL_SCHED_STATE_DONE;
 }
 
 /**
@@ -525,14 +687,14 @@ ble_ll_conn_wfr_sched_cb(struct ble_ll_sched_item *sch)
  * 
  * @param sch 
  * 
- * @return int 
+ * @return int 0: scheduled item is still running. 1: schedule item is done.
  */
 static int
 ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
 {
     int rc;
-    struct os_mbuf *m;
-    struct os_mbuf_pkthdr *pkthdr;
+    uint32_t usecs;
+    uint32_t wfr_time;
     struct ble_ll_conn_sm *connsm;
 
     /* Set current connection state machine */
@@ -548,55 +710,41 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
     assert(rc == 0);
 
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
-        /* Get packet off transmit queue. If none there, what to do? */
-        pkthdr = STAILQ_FIRST(&connsm->conn_txq);
-        if (pkthdr) {
-            /* Remove from queue */
-            m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
-            STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
-        } else {
-            /* Send empty pdu */
-            m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
-        }
-
-        /* WWW: must modify the header */
-
-        rc = ble_phy_tx(m, BLE_PHY_TRANSITION_NONE, BLE_PHY_TRANSITION_RX_TX);
+        rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_NONE);
         if (!rc) {
-            /* Set next schedule wakeup to check for wait for response */
-            sch->next_wakeup = cputime_get32() + 
-                cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS +
-                                       ble_ll_pdu_tx_time_get(m->om_len) +
-                                       BLE_LL_IFS +
-                                       BLE_LL_WFR_USECS);
-            sch->sched_cb = ble_ll_conn_wfr_sched_cb;
+            sch->next_wakeup = sch->end_time;
+            sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
             rc = BLE_LL_SCHED_STATE_RUNNING;
         } else {
-            /* Error transmitting! Put back on transmit queue */
-            STAILQ_INSERT_HEAD(&connsm->conn_txq, pkthdr, omp_next);
-
             /* Inform LL task of connection event end */
             ble_ll_event_send(&connsm->conn_ev_end);
             rc = BLE_LL_SCHED_STATE_DONE;
-
-            /* XXX: Is there anything else we need to do on failure? */
         }
     } else {
         rc = ble_phy_rx();
         if (rc) {
-            /* XXX: what happens if this fails? */
-        }
-    }
-
-    /* XXX: set state to connection here? */
+            /* End the connection event as we have no more buffers */
+            ++g_ble_ll_conn_stats.slave_ce_failures;
+            ble_ll_event_send(&connsm->conn_ev_end);
+            rc = BLE_LL_SCHED_STATE_DONE;
+        } else {
+            /* 
+             * Set flag that tell slave to set last anchor point if a packet
+             * has been received.
+             */ 
+            connsm->slave_set_last_anchor = 1;
 
-    /* XXX: make sure we set the end time of the event (if needed) not sure
-     * it is for master role. Have to think about it.
-     */
+            usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS +
+                connsm->slave_cur_window_widening;
+            wfr_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
+            ble_ll_wfr_enable(wfr_time, ble_ll_conn_wfr_timer_exp, connsm);
 
-    /* XXX: The return code here tells the scheduler whether
-     * to use the next wakeup time or determines if the scheduled event is
-       over. */
+            /* Set next wakeup time to connection event end time */
+            sch->next_wakeup = sch->end_time;
+            sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
+            rc = BLE_LL_SCHED_STATE_RUNNING;
+        }
+    }
     return rc;
 }
 
@@ -631,15 +779,21 @@ ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
             /* We will attempt to schedule the maximum CE length */
             usecs = connsm->max_ce_len * BLE_LL_CONN_CE_USECS;
         } else {
-            /* XXX: account for window widening/drift */
+            /* Include window widening and scheduling delay */
+            usecs = connsm->slave_cur_window_widening+XCVR_RX_SCHED_DELAY_USECS;
             sch->start_time = connsm->anchor_point - 
-                cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS);
+                cputime_usecs_to_ticks(usecs);
 
-            /* XXX: what to do for slave? Not sure how much to schedule here.
-               For now, just schedule entire connection interval */
+            /* Schedule entire connection interval for slave */
             usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
         }
+
+        /* XXX: we will need to subtract more than just the IFS since we need
+         * some time to deal with stuff. Gotta make sure we dont miss
+           next connection event. */
+        usecs -= BLE_LL_IFS;
         sch->end_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
+        connsm->ce_end_time = sch->end_time;
 
         /* XXX: for now, we cant get an overlap so assert on error. */
         /* Add the item to the scheduler */
@@ -656,76 +810,6 @@ ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
     return sch;
 }
 
-/* WWW:
- *  -> deal with data channel index (calculation it).
- *  -> deal with slave latency                      .
- */
-
-/**
- * Called upon end of connection event
- *  
- * Context: Link-layer task 
- * 
- * @param void *arg Pointer to connection state machine
- * 
- */
-void
-ble_ll_conn_event_end(void *arg)
-{
-    uint16_t latency;
-    uint32_t itvl;
-    struct ble_ll_conn_sm *connsm;
-
-    /* 
-     * XXX: if we received a response we can apply slave latency. I am not
-     * sure how this applies to the master. I guess the master could possibly 
-     * keep sending each anchor if it does not receive a reply. Possible that
-     * slave receives master but master does not get reply. This would cause
-     * master to re-transmit every connection event even though slave was
-     * asleep.
-     */
-    connsm = (struct ble_ll_conn_sm *)arg;
-
-    /* Set event counter to the next connection event that we will tx/rx in */
-    itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
-    latency = 1;
-    if (connsm->pkt_rxd) {
-        latency += connsm->slave_latency;
-        itvl = itvl * latency;
-        connsm->pkt_rxd = 0;
-    }
-    connsm->event_cntr += latency;
-
-    /* Set next connection event start time */
-    connsm->anchor_point += cputime_usecs_to_ticks(itvl);
-
-    /* Calculate data channel index of next connection event */
-    while (latency >= 0) {
-        --latency;
-        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
-    }
-
-    /* We better not be late for the anchor point. If so, skip events */
-    while ((int32_t)(connsm->anchor_point - cputime_get32()) <= 0) {
-        ++connsm->event_cntr;
-        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
-        connsm->anchor_point += 
-            cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
-        ++g_ble_ll_conn_stats.conn_ev_late;
-    }
-
-    /* XXX: window widening for slave */
-
-    /* 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;
-
-    /* Schedule the next connection event */
-    ble_ll_conn_sched_set(connsm);
-}
-
 /**
  * Connection supervision timer callback; means that the connection supervision
  * timeout has been reached and we should perform the appropriate actions. 
@@ -739,24 +823,19 @@ ble_ll_conn_spvn_timer_cb(void *arg)
 {
     struct ble_ll_conn_sm *connsm;
 
-    /* 
-     * WWW: What should we do with the PHY here? We could be transmitting or
-     * receiving. Need to figure out what to do.
-     */
-
     connsm = (struct ble_ll_conn_sm *)arg;
     ble_ll_event_send(&connsm->conn_spvn_ev);
 }
 
 /**
- * Initialize the connection state machine. This is done once per connection 
+ * Start the connection state machine. This is done once per connection 
  * when the HCI command "create connection" is issued to the controller or 
  * when a slave receives a connect request, 
  * 
  * @param connsm 
  */
 static void
-ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
+ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
 {
     struct ble_ll_conn_global_params *conn_params;
 
@@ -764,10 +843,7 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
     connsm->last_unmapped_chan = 0;
     connsm->event_cntr = 0;
     connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
-
-    /* We better have an unused handle or we are in trouble! */
-    connsm->conn_handle = ble_ll_conn_handle_alloc();
-    assert(connsm->conn_handle < BLE_LL_CONN_CFG_MAX_CONNS);
+    connsm->allow_slave_latency = 0;
 
     if (hcc != NULL) {
         /* Must be master */
@@ -838,8 +914,13 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
     connsm->conn_ev_end.ev_queued = 0;
     connsm->conn_ev_end.ev_type = BLE_LL_EVENT_CONN_EV_END;
 
-    /* Initialize transmit queue */
+    /* Initialize transmit queue and ack/flow control elements */
     STAILQ_INIT(&connsm->conn_txq);
+    connsm->tx_seqnum = 0;
+    connsm->next_exp_seqnum = 0;
+    connsm->last_txd_md = 0;
+    connsm->cons_rxd_bad_crc = 0;
+    connsm->last_rxd_sn = 1;
 
     /* XXX: Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
        exceeds the minimum, data length procedure needs to occur */
@@ -859,6 +940,9 @@ ble_ll_conn_sm_init(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc)
     connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
 
     /* XXX: Controller notifies host of changes to effective tx/rx time/bytes*/
+
+    /* Add to list of active connections */
+    SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, conn_sle);
 }
 
 /**
@@ -908,10 +992,21 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     struct os_mbuf_pkthdr *pkthdr;
 
     /* XXX: stop any connection schedule timers we created */
-    /* XXX: make sure phy interrupts are off and all that. We want to
-     * make sure that if a scheduled event fires off here we dont care;
-     * we just need to clean up properly
-     */
+
+    /* Disable the PHY */
+    ble_phy_disable();
+
+    /* Remove scheduler events just in case */
+    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
+
+    /* Stop supervision timer */
+    cputime_timer_stop(&connsm->conn_spvn_timer);
+
+    /* Disable any wait for response interrupt that might be running */
+    ble_ll_wfr_disable();
+
+    /* Remove from the active connection list */
+    SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle);
 
     /* Free all packets on transmit queue */
     while (1) {
@@ -922,15 +1017,14 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
         }
         STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
 
+        /* XXX: what happens if the empty PDU is on this list? Should
+           we check to make sure it is not? */
+
         m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
         os_mbuf_free(&g_mbuf_pool, m);
     }
 
-    /* Remove scheduler events just in case */
-    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
-
-    /* Make sure events off queue and connection supervison timer stopped */
-    cputime_timer_stop(&connsm->conn_spvn_timer);
+    /* Make sure events off queue */
     os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_spvn_ev);
     os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
 
@@ -943,11 +1037,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     /* Send connection complete event */
     ble_ll_conn_comp_event_send(connsm, ble_err);
 
-    /* Free up the handle */
-    ble_ll_conn_handle_free(connsm->conn_handle);
-
-    /* Free the connection state machine */
-    os_memblock_put(&g_ble_ll_conn_pool, connsm);
+    /* Put connection state machine back on free list */
+    STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
 }
 
 /**
@@ -986,12 +1077,17 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm)
     /* Set first connection event time */
     usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+        /* XXX: move this into the phy transmit pdu end callback for the
+           connect request */
+        /* We have yet to transmit the connect request so add that time */
         usecs += ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_PDU_LEN) + BLE_LL_IFS;
     } else {
-        /* XXX: need to deal with drift/window widening here */
-        usecs += 0;
+        connsm->slave_cur_tx_win_usecs = 
+            connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
     }
-    connsm->anchor_point = cputime_get32() + cputime_usecs_to_ticks(usecs);
+    connsm->last_anchor_point = cputime_get32();
+    connsm->anchor_point = connsm->last_anchor_point + 
+        cputime_usecs_to_ticks(usecs);
 
     /* Send connection complete event to inform host of connection */
     ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
@@ -1001,6 +1097,96 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm)
 }
 
 /**
+ * Called upon end of connection event
+ *  
+ * Context: Link-layer task 
+ * 
+ * @param void *arg Pointer to connection state machine
+ * 
+ */
+void
+ble_ll_conn_event_end(void *arg)
+{
+    uint16_t latency;
+    uint32_t itvl;
+    uint32_t cur_ww;
+    uint32_t max_ww;
+    struct ble_ll_conn_sm *connsm;
+
+    connsm = (struct ble_ll_conn_sm *)arg;
+
+    /* Disable the wfr timer */
+    ble_ll_wfr_disable();
+
+    /* Remove any scheduled items for this connection */
+    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
+    os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
+
+    /* 
+     * If we have received a packet, we can set the current transmit window
+     * usecs to 0 since we dont need to listen in the transmit window.
+     */
+    if (connsm->pkt_rxd) {
+        connsm->slave_cur_tx_win_usecs = 0;
+    }
+
+    /* Set event counter to the next connection event that we will tx/rx in */
+    itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+    latency = 1;
+    if (connsm->allow_slave_latency) {
+        if (connsm->pkt_rxd) {
+            latency += connsm->slave_latency;
+            itvl = itvl * latency;
+        }
+    }
+    connsm->event_cntr += latency;
+
+    /* Set next connection event start time */
+    connsm->anchor_point += cputime_usecs_to_ticks(itvl);
+
+    /* Calculate data channel index of next connection event */
+    while (latency >= 0) {
+        --latency;
+        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
+    }
+
+    /* XXX: we will need more time here for a slave I bet. IFS time is not
+       enough to re-schedule. End before it a bit.*/
+    /* We better not be late for the anchor point. If so, skip events */
+    while ((int32_t)(connsm->anchor_point - cputime_get32()) <= 0) {
+        ++connsm->event_cntr;
+        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
+        connsm->anchor_point += 
+            cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
+        ++g_ble_ll_conn_stats.conn_ev_late;
+    }
+
+    /* Reset "per connection event" variables */
+    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;
+
+    /* Calculate window widening for next event. If too big, end conn */
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        cur_ww = ble_ll_conn_calc_window_widening(connsm);
+        max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
+        if (cur_ww >= max_ww) {
+            ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
+            return;
+        }
+        connsm->slave_cur_window_widening = cur_ww;
+    }
+
+    /* Schedule the next connection event */
+    ble_ll_conn_sched_set(connsm);
+}
+
+/**
  * Update the connection request PDU with the address type and address of 
  * advertiser we are going to send connect request to. 
  * 
@@ -1096,8 +1282,8 @@ int
 ble_ll_conn_create(uint8_t *cmdbuf)
 {
     int rc;
-    uint32_t spvn_tmo_msecs;
-    uint32_t min_spvn_tmo_msecs;
+    uint32_t spvn_tmo_usecs;
+    uint32_t min_spvn_tmo_usecs;
     struct hci_create_conn ccdata;
     struct hci_create_conn *hcc;
     struct ble_ll_conn_sm *connsm;
@@ -1170,10 +1356,12 @@ ble_ll_conn_create(uint8_t *cmdbuf)
      * Supervision timeout (in msecs) must be more than:
      *  (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
      */
-    spvn_tmo_msecs = hcc->supervision_timeout * BLE_HCI_CONN_SPVN_TMO_UNITS;
-    min_spvn_tmo_msecs = (hcc->conn_itvl_max << 1) + (hcc->conn_itvl_max >> 1);
-    min_spvn_tmo_msecs *= (1 + hcc->conn_latency);
-    if (spvn_tmo_msecs <= min_spvn_tmo_msecs) {
+    spvn_tmo_usecs = hcc->supervision_timeout;
+    spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
+    min_spvn_tmo_usecs = (uint32_t)hcc->conn_itvl_max * 2 * 
+        BLE_LL_CONN_ITVL_USECS;
+    min_spvn_tmo_usecs *= (1 + hcc->conn_latency);
+    if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
@@ -1185,13 +1373,13 @@ ble_ll_conn_create(uint8_t *cmdbuf)
     }
 
     /* Make sure we can accept a connection! */
-    connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
+    connsm = ble_ll_conn_sm_get();
     if (connsm == NULL) {
         return BLE_ERR_CONN_LIMIT;
     }
 
-    /* Initialize the connection sm */
-    ble_ll_conn_sm_init(connsm, hcc);
+    /* Start the connection sm */
+    ble_ll_conn_sm_start(connsm, hcc);
 
     /* Create the connection request */
     ble_ll_conn_req_pdu_make(connsm);
@@ -1199,7 +1387,8 @@ ble_ll_conn_create(uint8_t *cmdbuf)
     /* Start scanning */
     rc = ble_ll_scan_initiator_start(hcc);
     if (rc) {
-        os_memblock_put(&g_ble_ll_conn_pool, connsm);
+        SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle);
+        STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
     } else {
         /* Set the connection state machine we are trying to create. */
         g_ble_ll_conn_create_sm = connsm;
@@ -1302,7 +1491,7 @@ ble_ll_init_rx_pdu_proc(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
     }
 
     /* If we have sent a connect request, we need to enter CONNECTION state*/
-    if (ble_hdr->crcok && (ble_hdr->flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
+    if (ble_hdr->flags & BLE_MBUF_HDR_F_CONN_REQ_TXD) {
         /* Set address of advertiser to which we are connecting. */
         if (!ble_ll_scan_whitelist_enabled()) {
             /* 
@@ -1464,14 +1653,252 @@ ble_ll_conn_spvn_timeout(void *arg)
  * been checked yet.
  */
 void
-ble_ll_conn_rsp_rxd(void)
+ble_ll_conn_rx_pdu_start(void)
 {
-    if (g_ble_ll_conn_cur_sm) {
-        g_ble_ll_conn_cur_sm->rsp_rxd = 1;
+    struct ble_ll_conn_sm *connsm;
+
+    connsm = g_ble_ll_conn_cur_sm;
+    if (connsm) {
+        connsm->rsp_rxd = 1;
+        connsm->pkt_rxd = 1;
+
+        /* Set last anchor point if 1st received frame in connection event */
+        if (connsm->slave_set_last_anchor) {
+            connsm->slave_set_last_anchor = 0;
+            /* 
+             * XXX: for now, just use the current time. Make more accurate.
+             * We subtract 40 usecs since we get the start 5 bytes after
+             * actual start. We add another 10 just in case.
+             */
+            connsm->last_anchor_point = cputime_get32() - 
+                cputime_usecs_to_ticks(50);
+        }
     }
 }
 
 /**
+ * Called from the Link Layer task when a data PDU has been received
+ *  
+ * Context: Link layer task 
+ * 
+ * @param rxpdu 
+ */
+void
+ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
+{
+    uint8_t hdr_byte;
+    uint8_t rxd_sn;
+    uint8_t *rxbuf;
+    uint16_t acl_len;
+    uint16_t acl_hdr;
+    uint32_t tmo;
+    struct ble_ll_conn_sm *connsm;
+
+    if (crcok) {
+        /* Count valid received data pdus */
+        ++g_ble_ll_conn_stats.data_pdu_rx_valid;
+
+        /* We better have a connection state machine */
+        connsm = g_ble_ll_conn_cur_sm;
+        if (connsm) {
+            /* Reset the connection supervision timeout */
+            cputime_timer_stop(&connsm->conn_spvn_timer);
+            tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
+            cputime_timer_relative(&connsm->conn_spvn_timer, tmo);
+
+            /* 
+             * If we are a slave, we can only start to use slave latency
+             * once we have received a NESN of 1 from the master
+             */ 
+            rxbuf = rxpdu->om_data;
+            hdr_byte = rxbuf[0];
+            if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+                if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) {
+                    connsm->allow_slave_latency = 1;
+                }
+            }
+
+            /* 
+             * Discard the received PDU if the sequence number is the same
+             * as the last received sequence number
+             */ 
+            rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
+            if (rxd_sn != connsm->last_rxd_sn) {
+                /* Update last rxd sn */
+                connsm->last_rxd_sn = rxd_sn;
+
+                /* XXX: use the mbuf routine for this! */
+                /* Set ACL data packet header and send to host */
+                acl_len = rxbuf[1];
+                acl_hdr = (hdr_byte & BLE_LL_DATA_HDR_LLID_MASK);
+                acl_hdr = (acl_hdr << 12) | connsm->conn_handle;
+                rxpdu->om_data = rxpdu->om_data - 2;
+                rxbuf = rxpdu->om_data;
+                htole16(rxbuf, acl_hdr);
+                htole16(rxbuf + 2, acl_len);
+
+                /* Add to length of mbuf and packet header */
+                rxpdu->om_len += 2;
+                OS_MBUF_PKTHDR(rxpdu)->omp_len += 2;
+
+                /* XXX: send to host */
+                return;
+            }
+        } else {
+            ++g_ble_ll_conn_stats.no_conn_sm;
+        }
+    } else {
+        ++g_ble_ll_conn_stats.data_pdu_rx_invalid;
+    }
+
+    /* Free the packet buffer */
+    os_mbuf_free(&g_mbuf_pool, rxpdu);
+}
+
+/**
+ * Called when a packet has been received while in the connection state.
+ *  
+ * Context: Interrupt
+ * 
+ * @param rxpdu 
+ * @param crcok 
+ * 
+ * @return int 
+ *       < 0: Disable the phy after reception.
+ *      == 0: Success. Do not disable the PHY.
+ *       > 0: Do not disable PHY as that has already been done.
+ */
+int
+ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok)
+{
+    int rc;
+    uint8_t hdr_byte;
+    uint8_t hdr_sn;
+    uint8_t hdr_nesn;
+    uint8_t conn_sn;
+    uint8_t conn_nesn;
+    uint8_t reply;
+    uint32_t ticks;
+    struct os_mbuf *txpdu;
+    struct os_mbuf_pkthdr *pkthdr;
+    struct ble_ll_conn_sm *connsm;
+
+    /* 
+     * We should have a current connection state machine. If we dont, we just
+     * hand the packet to the higher layer to count it.
+     */
+    connsm = g_ble_ll_conn_cur_sm;
+    if (!connsm) {
+        return -1;
+    }
+
+    /* 
+     * Check the packet CRC. A connection event can continue even if the
+     * received PDU does not pass the CRC check. If we receive two consecutive
+     * CRC errors we end the conection event.
+     */
+    if (!crcok) {
+        /* 
+         * Increment # of consecutively received CRC errors. If more than
+         * one we will end the connection event.
+         */ 
+        ++connsm->cons_rxd_bad_crc;
+        if (connsm->cons_rxd_bad_crc >= 2) {
+            reply = 0;
+        } else {
+            if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+                reply = connsm->last_txd_md;
+            } else {
+                /* A slave always responds with a packet */
+                reply = 1;
+            }
+        }
+    } else {
+        /* Reset consecutively received bad crcs (since this one was good!) */
+        connsm->cons_rxd_bad_crc = 0;
+
+        /* Store received header byte in state machine  */
+        hdr_byte = rxpdu->om_data[0];
+        connsm->last_rxd_hdr_byte = hdr_byte;
+
+        /* 
+         * If SN bit from header does not match NESN in connection, this is
+         * a resent PDU and should be ignored.
+         */ 
+        hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
+        conn_nesn = connsm->next_exp_seqnum;
+        if ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn)) {
+            connsm->next_exp_seqnum ^= 1;
+        } else {
+            /* Count re-sent PDUs. */
+            ++g_ble_ll_conn_stats.rx_resent_pdus;
+        }
+
+        /* 
+         * Check NESN bit from header. If same as tx seq num, the transmission
+         * is acknowledged. Otherwise we need to resend this PDU.
+         */
+        hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK;
+        conn_sn = connsm->tx_seqnum;
+        if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) {
+            /* We did not get an ACK. Must retry the PDU */
+            ++g_ble_ll_conn_stats.data_pdu_txf;
+        } else {
+            /* Transmit success */
+            connsm->tx_seqnum ^= 1;
+            ++g_ble_ll_conn_stats.data_pdu_txg;
+
+            /* We can remove this packet from the queue now */
+            pkthdr = STAILQ_FIRST(&connsm->conn_txq);
+            if (pkthdr) {
+                STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
+                txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+                os_mbuf_free(&g_mbuf_pool, txpdu);
+                /* XXX: deal with empty pdu's. Cant free them */
+            } else {
+                /* No packet on queue? This is an error! */
+                ++g_ble_ll_conn_stats.no_tx_pdu;
+            }
+        }
+
+        /* Should we continue connection event? */
+        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);
+                if (pkthdr) {
+                    ticks = ble_ll_pdu_tx_time_get(pkthdr->omp_len);
+                } else {
+                    /* We will send empty pdu (just a LL header) */
+                    ticks = ble_ll_pdu_tx_time_get(BLE_LL_PDU_HDR_LEN);
+                }
+                ticks += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
+                ticks = cputime_usecs_to_ticks(ticks);
+                /* XXX: should really use packet receive end time here */
+                if ((cputime_get32() + ticks) >= connsm->ce_end_time) {
+                    reply = 0;
+                }
+            }
+        } else {
+            /* A slave always replies */
+            reply = 1;
+        }
+    }
+
+    /* If reply flag set, send data pdu and continue connection event */
+    rc = -1;
+    if (reply) {
+        rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_RX_TX);
+    }
+
+    if (rc) {
+        ble_ll_event_send(&connsm->conn_ev_end);
+    }
+
+    return 0;
+}
+
+/**
  * Called when a device has received a connect request while advertising and 
  * the connect request has passed the advertising filter policy and is for 
  * us. This will start a connection in the slave role. 
@@ -1483,21 +1910,21 @@ ble_ll_conn_rsp_rxd(void)
 void
 ble_ll_conn_slave_start(uint8_t *rxbuf)
 {
+    uint32_t temp;
     uint32_t crcinit;
     uint8_t *dptr;
     struct ble_ll_conn_sm *connsm;
 
-    /* XXX: Should we error check the parameters? */
-
     /* Allocate a connection. If none available, dont do anything */
-    connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
-    if (!connsm) {
+    connsm = ble_ll_conn_sm_get();
+    if (connsm == NULL) {
         return;
     }
 
     /* Set the pointer at the start of the connection data */
     dptr = rxbuf + BLE_LL_CONN_REQ_ADVA_OFF + BLE_DEV_ADDR_LEN;
 
+    /* Set connection state machine information */
     connsm->access_addr = le32toh(dptr);
     crcinit = dptr[4];
     crcinit <<= 16;
@@ -1514,6 +1941,34 @@ ble_ll_conn_slave_start(uint8_t *rxbuf)
     connsm->hop_inc = dptr[21] & 0x1F;
     connsm->master_sca = dptr[21] >> 5;
 
+    /* Error check parameters */
+    if ((connsm->tx_win_off > connsm->conn_itvl) ||
+        (connsm->conn_itvl < BLE_HCI_CONN_ITVL_MIN) ||
+        (connsm->conn_itvl > BLE_HCI_CONN_ITVL_MAX) ||
+        (connsm->tx_win_size < BLE_LL_CONN_TX_WIN_MIN) ||
+        (connsm->slave_latency > BLE_LL_CONN_SLAVE_LATENCY_MAX)) {
+        goto err_slave_start;
+    }
+
+    /* Slave latency cannot cause a supervision timeout */
+    temp = (connsm->slave_latency + 1) * (connsm->conn_itvl * 2) * 
+            BLE_LL_CONN_ITVL_USECS;
+    if ((connsm->supervision_tmo * 10000) <= temp ) {
+        goto err_slave_start;
+    }
+
+    /* 
+     * The transmit window must be less than or equal to the lesser of 10 
+     * msecs or the connection interval minus 1.25 msecs.
+     */ 
+    temp = connsm->conn_itvl - 1;
+    if (temp > 8) {
+        temp = 8;
+    }
+    if (connsm->tx_win_size > temp) {
+        goto err_slave_start;
+    }
+
     /* XXX: might want to set this differently based on adv. filter policy! */
     /* Set the address of device that we are connecting with */
     memcpy(&connsm->peer_addr, rxbuf + BLE_LL_PDU_HDR_LEN, BLE_DEV_ADDR_LEN);
@@ -1523,13 +1978,24 @@ ble_ll_conn_slave_start(uint8_t *rxbuf)
         connsm->peer_addr_type = BLE_ADDR_TYPE_PUBLIC;
     }
 
+    /* Calculate number of used channels; make sure it meets min requirement */
     connsm->num_used_chans = ble_ll_conn_calc_used_chans(connsm->chanmap);
+    if (connsm->num_used_chans < 2) {
+        goto err_slave_start;
+    }
 
-    /* Need to initialize the connection state machine */
-    ble_ll_conn_sm_init(connsm, NULL);
+    /* Start the connection state machine */
+    ble_ll_conn_sm_start(connsm, NULL);
 
     /* The connection has been created. */
     ble_ll_conn_created(connsm);
+
+    return;
+
+err_slave_start:
+    STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe);
+    ++g_ble_ll_conn_stats.slave_rxd_bad_conn_req_params;
+    return;
 }
 
 /* Initialize the connection module */
@@ -1537,8 +2003,10 @@ void
 ble_ll_conn_init(void)
 {
     int rc;
+    uint16_t i;
     uint16_t maxbytes;
     struct os_mbuf *m;
+    struct ble_ll_conn_sm *connsm;
     struct ble_ll_conn_global_params *conn_params;
 
     /* Create connection memory pool */
@@ -1549,6 +2017,18 @@ ble_ll_conn_init(void)
 
     /* Initialize list of active conections */
     SLIST_INIT(&g_ble_ll_conn_active_list);
+    STAILQ_INIT(&g_ble_ll_conn_free_list);
+
+    /* 
+     * Take all the connections off the free memory pool and add them to
+     * the free connection list, assigning handles in linear order. Note:
+     * the specification allows a handle of zero; we just avoid using it.
+     */
+    for (i = 1; i <= BLE_LL_CONN_CFG_MAX_CONNS; ++i) {
+        connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool);
+        assert(connsm != NULL);
+        connsm->conn_handle = i;
+    }
 
     /* Configure the global LL parameters */
     conn_params = &g_ble_ll_conn_params;
@@ -1564,6 +2044,13 @@ ble_ll_conn_init(void)
     conn_params->conn_init_max_tx_time = ble_ll_pdu_tx_time_get(maxbytes);
     conn_params->conn_init_max_tx_octets = BLE_LL_CFG_SUPP_MAX_TX_BYTES;
 
+    /* 
+     * XXX: This approach may not work as I may need to keep these on the
+     * transmit packet queue of a connsm. If there are multiple state machines,
+     * I will need multiple empty PDU's. This is only true if I need to keep
+     * the empty PDU on the transmit queue for retransmission across connection
+     * events. 
+     */
     /* Initialize dummy empty pdu */
     m = (struct os_mbuf *)&g_ble_ll_empty_pdu;
     m->om_data = (uint8_t *)&g_ble_ll_empty_pdu[0];
@@ -1571,5 +2058,7 @@ ble_ll_conn_init(void)
     m->om_len = 2;
     m->om_flags = OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR);
     OS_MBUF_PKTHDR(m)->omp_len = 2;
+    m->om_data[0] = BLE_LL_LLID_DATA_FRAG;
+    m->om_data[1] = 0;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/net/nimble/drivers/native/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c
index aa91a14..dff2b1d 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -174,7 +174,7 @@ ble_phy_isr(void)
         /* Construct BLE header before handing up */
         ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
         ble_hdr->flags = 0;
-        ble_hdr->rssi = -77;
+        ble_hdr->rssi = -77;    /* XXX: dummy rssi */
         ble_hdr->channel = g_ble_phy_data.phy_chan;
         ble_hdr->crcok = 1;
 
@@ -188,7 +188,7 @@ ble_phy_isr(void)
         /* Call Link Layer receive payload function */
         rxpdu = g_ble_phy_data.rxpdu;
         g_ble_phy_data.rxpdu = NULL;
-        rc = ble_ll_rx_end(rxpdu, ble_hdr->crcok);
+        rc = ble_ll_rx_end(rxpdu, ble_hdr->channel, ble_hdr->crcok);
         if (rc < 0) {
             /* Disable the PHY. */
             ble_phy_disable();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/net/nimble/drivers/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c
index 43bde94..37731dd 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -100,6 +100,11 @@ ble_phy_rxpdu_get(void)
         if (!m) {
             ++g_ble_phy_stats.no_bufs;
         } else {
+            /* 
+             * XXX: fix this later but we need to prepend the ACL header
+             * which is 4 bytes but we re-use 2 bytes of the PDU header.
+             */
+            m->om_data += 2;
             g_ble_phy_data.rxpdu = m;
         }
     }
@@ -151,9 +156,6 @@ ble_phy_isr(void)
 
         transition = g_ble_phy_data.phy_transition;
         if (transition == BLE_PHY_TRANSITION_TX_RX) {
-            /* XXX: for now, assume we receive on logical address 0 */
-            NRF_RADIO->RXADDRESSES = 1;
-
             /* Debug check to make sure we go from tx to rx */
             assert((shortcuts & RADIO_SHORTS_DISABLED_RXEN_Msk) != 0);
 
@@ -262,7 +264,7 @@ ble_phy_isr(void)
         /* Call Link Layer receive payload function */
         rxpdu = g_ble_phy_data.rxpdu;
         g_ble_phy_data.rxpdu = NULL;
-        rc = ble_ll_rx_end(rxpdu, ble_hdr->crcok);
+        rc = ble_ll_rx_end(rxpdu, ble_hdr->channel, ble_hdr->crcok);
         if (rc < 0) {
             /* Disable the PHY. */
             ble_phy_disable();
@@ -359,12 +361,6 @@ ble_phy_rx(void)
         return BLE_PHY_ERR_NO_BUFS;
     }
 
-    /* XXX: Assume that this is an advertising channel */
-    NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV;
-
-    /* XXX: for now, assume we receive on logical address 0 */
-    NRF_RADIO->RXADDRESSES = 1;
-
     /* Set packet pointer */
     NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index e7d5c2f..8d98f5a 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -38,6 +38,7 @@ extern struct os_mempool g_hci_os_event_pool;
  *  flags: bitfield with the following values
  *      0x01:   Set if there was a match on the whitelist
  *      0x02:   Set if a connect request was transmitted upon receiving pdu
+ *      0x04:   Set the first time we transmit the PDU (used to detect retry).
  *  channel: The logical BLE channel PHY channel # (0 - 39)
  *  crcok: flag denoting CRC check passed (1) or failed (0).
  *  rssi: RSSI, in dBm.
@@ -53,11 +54,18 @@ struct ble_mbuf_hdr
 /* Flag definitions */
 #define BLE_MBUF_HDR_F_DEVMATCH         (0x01)
 #define BLE_MBUF_HDR_F_CONN_REQ_TXD     (0x02)
+#define BLE_MBUF_HDR_F_TXD              (0x04)
 
 #define BLE_MBUF_HDR_PTR(om)    \
     (struct ble_mbuf_hdr *)((uint8_t *)om + sizeof(struct os_mbuf) + \
                             sizeof(struct os_mbuf_pkthdr))
 
+/* BLE mbuf overhead per packet header mbuf */
+#define BLE_MBUF_PKT_OVERHEAD   (sizeof(struct os_mbuf) +           \
+                                 sizeof(struct os_mbuf_pkthdr) +    \
+                                 sizeof(struct ble_mbuf_hdr))
+
+
 #define BLE_DEV_ADDR_LEN        (6)
 extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN];
 extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN];

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/15a4a8cf/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index 9cbdcd8..43186fb 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -50,9 +50,7 @@ uint8_t g_host_adv_len;
 /* Create a mbuf pool of BLE mbufs */
 #define MBUF_NUM_MBUFS      (16)
 #define MBUF_BUF_SIZE       (256)
-#define MBUF_MEMBLOCK_SIZE  \
-    (MBUF_BUF_SIZE + sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + \
-     sizeof(struct ble_mbuf_hdr))
+#define MBUF_MEMBLOCK_SIZE  (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
 
 #define MBUF_MEMPOOL_SIZE   OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE)