Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master df59850fe -> 7a82be0e5


Connection update procedure implemented. Most of connection parameter request 
implemented but not final so connection parameter


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

Branch: refs/heads/master
Commit: 262b1be2f72c5e42d254dcc92e62598590988332
Parents: df59850
Author: wes3 <w...@micosa.io>
Authored: Fri Jan 22 15:19:39 2016 -0800
Committer: wes3 <w...@micosa.io>
Committed: Fri Jan 22 15:19:39 2016 -0800

----------------------------------------------------------------------
 hw/bsp/nrf52pdk/include/bsp/bsp.h               |   3 +
 .../controller/include/controller/ble_ll_conn.h |  46 +-
 .../controller/include/controller/ble_ll_ctrl.h |  24 +-
 .../controller/include/controller/ble_ll_hci.h  |   2 +-
 net/nimble/controller/src/ble_ll.c              |  14 +-
 net/nimble/controller/src/ble_ll_adv.c          |   2 +-
 net/nimble/controller/src/ble_ll_conn.c         | 127 +++-
 net/nimble/controller/src/ble_ll_conn_hci.c     | 256 ++++++-
 net/nimble/controller/src/ble_ll_conn_priv.h    |   4 +
 net/nimble/controller/src/ble_ll_ctrl.c         | 696 ++++++++++++++++---
 net/nimble/controller/src/ble_ll_hci.c          |  26 +-
 net/nimble/controller/src/ble_ll_scan.c         | 134 ++--
 project/bletest/src/main.c                      |  59 +-
 13 files changed, 1174 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/hw/bsp/nrf52pdk/include/bsp/bsp.h
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf52pdk/include/bsp/bsp.h 
b/hw/bsp/nrf52pdk/include/bsp/bsp.h
index 2451c31..7ec6b58 100644
--- a/hw/bsp/nrf52pdk/include/bsp/bsp.h
+++ b/hw/bsp/nrf52pdk/include/bsp/bsp.h
@@ -27,6 +27,9 @@ extern "C" {
 /* UART info */
 #define CONSOLE_UART    0
 
+/* Declaration of "non-zeroed" bss */
+#define nzbss_t   __attribute__((section(".nzbss")))
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 444ee72..4df87b7 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -19,7 +19,9 @@
 
 #include "os/os.h"
 #include "nimble/ble.h"
+#include "nimble/hci_common.h"
 #include "controller/ble_ll_sched.h"
+#include "controller/ble_ll_ctrl.h"
 #include "hal/hal_cputime.h"
 
 /* Roles */
@@ -58,7 +60,7 @@ struct ble_ll_conn_sm
 {
     /* Current connection state and role */
     uint8_t conn_state;
-    uint8_t conn_role;
+    uint8_t conn_role;          /* Can possibly be 1 bit */
 
     /* Connection data length management */
     uint8_t max_tx_octets;
@@ -91,37 +93,47 @@ struct ble_ll_conn_sm
     uint8_t last_rxd_hdr_byte;  /* note: possibly can make 1 bit since we
                                    only use the MD bit now */
 
-    /* connection event timing/mgmt */
+    /* connection event mgmt */
     uint8_t pdu_txd;                /* 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 awaiting_host_reply;    /* note: can be 1 bit */
+    uint8_t send_conn_upd_event;    /* note: can be 1 bit */
+    uint8_t conn_update_scheduled;  /* note: can be 1 bit */
+    uint8_t host_expects_upd_event;  /* note: can be 1 bit */
+    uint8_t reject_reason;
+    uint8_t host_reply_opcode;
     uint8_t master_sca;
     uint8_t tx_win_size;
     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;
-    uint16_t tx_win_off;
-    uint16_t min_ce_len;
-    uint16_t max_ce_len;
     uint16_t event_cntr;
-    uint16_t supervision_tmo;
     uint16_t conn_handle;
     uint16_t completed_pkts;
     uint32_t access_addr;
-    uint32_t crcinit;           /* only low 24 bits used */
-    uint32_t anchor_point;
-    uint32_t last_anchor_point; /* slave only */
+    uint32_t crcinit;               /* only low 24 bits used */
     uint32_t ce_end_time;   /* cputime at which connection event should end */
     uint32_t terminate_timeout;
+    uint32_t last_scheduled;
+
+    /* Connection timing */
+    uint16_t conn_itvl_min;
+    uint16_t conn_itvl_max;
+    uint16_t conn_itvl;
+    uint16_t slave_latency;
+    uint16_t supervision_tmo;
+    uint16_t min_ce_len;
+    uint16_t max_ce_len;
+    uint16_t tx_win_off;
+    uint32_t anchor_point;
+    uint32_t last_anchor_point;
     uint32_t slave_cur_tx_win_usecs;
     uint32_t slave_cur_window_widening;
-    uint32_t last_scheduled;
 
     /* address information */
     uint8_t own_addr_type;
@@ -154,6 +166,16 @@ struct ble_ll_conn_sm
 
     /* For scheduling connections */
     struct ble_ll_sched_item conn_sch;
+
+    /* XXX: ifdef this by feature? */
+    /* 
+     * For connection update procedure. XXX: can make this a pointer and
+     * malloc it if we want to save space.
+     */ 
+    struct hci_conn_update conn_param_req;
+
+    /* For connection update procedure */
+    struct ble_ll_conn_upd_req conn_update_req;
 };
 
 /* 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 8920f08..1f3de56 100644
--- a/net/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -22,7 +22,7 @@
  * It is used to determine which LL control procedure is currently running
  * in a connection and which ones may be pending.
  */
-#define BLE_LL_CTRL_PROC_CONN_UPD       (0)
+#define BLE_LL_CTRL_PROC_CONN_UPDATE    (0)
 #define BLE_LL_CTRL_PROC_CHAN_MAP_UPD   (1)
 #define BLE_LL_CTRL_PROC_ENCRYPT        (2)
 #define BLE_LL_CTRL_PROC_FEATURE_XCHG   (3)
@@ -37,6 +37,9 @@
 /* Checks if a particular control procedure is running */
 #define IS_PENDING_CTRL_PROC_M(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
 
+/* LL control procedure timeout */
+#define BLE_LL_CTRL_PROC_TIMEOUT        (40)    /* in secs */
+
 /* 
  * LL CTRL PDU format
  *  -> Opcode   (1 byte)
@@ -65,6 +68,11 @@
 #define BLE_LL_CTRL_LENGTH_REQ          (20)
 #define BLE_LL_CTRL_LENGTH_RSP          (21)
 
+/* Maximum opcode value */
+#define BLE_LL_CTRL_OPCODES             (BLE_LL_CTRL_LENGTH_RSP + 1)
+
+extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
+
 /* Maximum # of payload bytes in a LL control PDU */
 #define BLE_LL_CTRL_MAX_PAYLOAD         (26)
 
@@ -169,7 +177,7 @@ struct ble_ll_conn_params
     uint16_t interval_max;
     uint16_t latency;
     uint16_t timeout;
-    uint16_t pref_periodicity;
+    uint8_t pref_periodicity;
     uint16_t ref_conn_event_cnt;
     uint16_t offset0;
     uint16_t offset1;
@@ -215,9 +223,19 @@ struct ble_ll_conn_sm;
 void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
 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(uint8_t hdr, uint8_t opcode);
+int ble_ll_ctrl_is_reject_ind_ext(uint8_t hdr, uint8_t opcode);
+uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, 
+                                     uint8_t *rsp,
+                                     struct ble_ll_conn_params *req);
+int ble_ll_ctrl_reject_ind_ext_send(struct ble_ll_conn_sm *connsm,
+                                    uint8_t rej_opcode, uint8_t err);
+
+void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm);
+void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
+                                     struct ble_ll_conn_params *cp);
+void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status);
 
 #endif /* H_BLE_LL_CTRL_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 32a093a..862fbad 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -41,7 +41,7 @@ void ble_ll_hci_init(void);
 void ble_ll_hci_cmd_proc(struct os_event *ev);
 
 /* Used to determine if the LE event is enabled/disabled */
-uint8_t ble_ll_hci_is_le_event_enabled(int bitpos);
+uint8_t ble_ll_hci_is_le_event_enabled(int subev);
 
 /* Used to determine if event is enabled/disabled */
 uint8_t ble_ll_hci_is_event_enabled(int bitpos);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 eb44261..4eb4a8e 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <string.h>
 #include "os/os.h"
+#include "bsp/bsp.h"
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
 #include "controller/ble_phy.h"
@@ -49,6 +50,7 @@
 
 /* Configuration for supported features */
 #define BLE_LL_CFG_FEAT_DATA_LEN_EXT
+#undef BLE_LL_CFG_FEAT_CONN_PARAM_REQ
 #undef BLE_LL_CFG_FEAT_LE_ENCRYPTION
 #undef BLE_LL_CFG_FEAT_EXT_REJECT_IND
 
@@ -78,7 +80,10 @@ struct ble_ll_log
 
 #define BLE_LL_LOG_LEN  (256)
 
-static struct ble_ll_log g_ble_ll_log[BLE_LL_LOG_LEN];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+static nzbss_t struct ble_ll_log g_ble_ll_log[BLE_LL_LOG_LEN];
 static uint8_t g_ble_ll_log_index;
 
 void
@@ -939,6 +944,13 @@ ble_ll_init(void)
 #ifdef BLE_LL_CFG_FEAT_DATA_LEN_EXT
     features |= BLE_LL_FEAT_DATA_LEN_EXT;
 #endif
+#ifdef BLE_LL_CFG_FEAT_CONN_PARAM_REQ
+    features |= BLE_LL_FEAT_CONN_PARM_REQ;
+#endif
+#ifdef BLE_LL_CFG_FEAT_EXT_REJECT_IND
+    features |= BLE_LL_FEAT_EXTENDED_REJ;
+#endif
+
     lldata->ll_supp_features = features;
 
     /* Initialize the LL task */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 d74b61a..116da9a 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -1136,7 +1136,7 @@ ble_ll_adv_event_done(void *arg)
     os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
 
     /* For debug purposes */
-#ifdef BLETEST
+#ifdef BLETEST_ADV_PKT_NUM
     bletest_inc_adv_pkt_num();
 #endif
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 373909b..a4b3b44 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -103,9 +103,9 @@ extern int ble_hs_rx_data(struct os_mbuf *om);
 #define BLE_LL_CFG_CONN_TX_WIN_SIZE         (1)
 #define BLE_LL_CFG_CONN_TX_WIN_OFF          (0)
 #define BLE_LL_CFG_CONN_MASTER_SCA          (BLE_MASTER_SCA_251_500_PPM << 5)
-#define BLE_LL_CFG_CONN_MAX_CONNS           (8)
+#define BLE_LL_CFG_CONN_MAX_CONNS           (32)
 #define BLE_LL_CFG_CONN_OUR_SCA             (60)    /* in ppm */
-#define BLE_LL_CFG_CONN_INIT_SLOTS          (8)
+#define BLE_LL_CFG_CONN_INIT_SLOTS          (2)
 
 /* We cannot have more than 254 connections given our current implementation */
 #if (BLE_LL_CFG_CONN_MAX_CONNS >= 255)
@@ -142,7 +142,10 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
 struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
 
 /* Connection state machine array */
-struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+nzbss_t struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
 
 /* List of active connections */
 struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
@@ -928,6 +931,8 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
     }
 
     /* XXX: for now, just make connection interval equal to max */
+    connsm->conn_itvl_min = hcc->conn_itvl_min;
+    connsm->conn_itvl_max = hcc->conn_itvl_max;
     connsm->conn_itvl = hcc->conn_itvl_max;
 
     /* Check the min/max CE lengths are less than connection interval */
@@ -973,24 +978,35 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
 {
     struct ble_ll_conn_global_params *conn_params;
 
-    /* Reset event counter and last unmapped channel */
-    connsm->last_unmapped_chan = 0;
+    /* Reset following elements */
     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;
+    connsm->awaiting_host_reply = 0;
+    connsm->send_conn_upd_event = 0;
+    connsm->conn_update_scheduled = 0;
+    connsm->host_expects_upd_event = 0;
 
     /* Reset current control procedure */
     connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
     connsm->pending_ctrl_procs = 0;
 
+    /* 
+     * Set handle in connection update procedure to 0. If the handle
+     * is non-zero it means that the host initiated the connection
+     * parameter update request and the rest of the parameters are valid.
+     */
+    connsm->conn_param_req.handle = 0;
+
     /* Initialize connection supervision timer */
     cputime_timer_init(&connsm->conn_spvn_timer, ble_ll_conn_spvn_timer_cb, 
                        connsm);
 
     /* Calculate the next data channel */
+    connsm->last_unmapped_chan = 0;
     connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
 
     /* Initialize event */
@@ -1079,7 +1095,7 @@ ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm,
     }
 
     if (send_event) {
-        ble_ll_ctrl_datalen_chg_event(connsm);
+        ble_ll_hci_ev_datalen_chg(connsm);
     }
 }
 
@@ -1151,13 +1167,52 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t 
ble_err)
     
ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
 }
 
+/**
+ * Called to move to the next connection event. 
+ * 
+ * @param connsm 
+ * 
+ * @return int 
+ */
 static int
 ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
 {
+    uint8_t update_status;
     uint16_t latency;
     uint32_t itvl;
+    uint32_t tmo;
     uint32_t cur_ww;
     uint32_t max_ww;
+    struct ble_ll_conn_upd_req *upd;
+
+    /* 
+     * XXX: we could send the connection update event a bit earlier. The
+     * way this is coded is that we will generally send it when the
+     * connection event corresponding to the instant ends. We can send
+     * it when it begins if we want.
+     */
+
+    /* XXX: deal with connection request procedure here as well */
+
+    /* 
+     * There are two cases where this flag gets set:
+     * 1) A connection update procedure was started and the event counter
+     * has passed the instant.
+     * 2) We successfully sent the reject reason.
+     */
+    if (connsm->host_expects_upd_event) {
+        update_status = BLE_ERR_SUCCESS;
+        if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
+            ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE);
+        } else {
+            if (IS_PENDING_CTRL_PROC_M(connsm, 
BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+                ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+                update_status = connsm->reject_reason;
+            }
+        }
+        ble_ll_hci_ev_conn_update(connsm, update_status);
+        connsm->host_expects_upd_event = 0;
+    }
 
     /* 
      * XXX: not quite sure I am interpreting slave latency correctly here.
@@ -1169,7 +1224,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     /* 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->allow_slave_latency && !connsm->conn_update_scheduled) {
         if (connsm->pkt_rxd) {
             latency += connsm->slave_latency;
             itvl = itvl * latency;
@@ -1180,6 +1235,43 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
     /* Set next connection event start time */
     connsm->anchor_point += cputime_usecs_to_ticks(itvl);
 
+    /* 
+     * If a connection update has been scheduled and the event counter
+     * is now equal to the instant, we need to adjust the start of the
+     * connection by the the transmit window offset. We also copy in the
+     * update parameters as they now should take effect.
+     */
+    if (connsm->conn_update_scheduled && 
+        (connsm->event_cntr == connsm->conn_update_req.instant)) {
+
+        /* Set flag so we send connection update event */
+        upd = &connsm->conn_update_req;
+        if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER)  ||
+            (connsm->conn_itvl != upd->interval)            ||
+            (connsm->slave_latency != upd->latency)         || 
+            (connsm->supervision_tmo != upd->timeout)) {
+            connsm->host_expects_upd_event = 1;
+        }
+
+        connsm->conn_itvl = upd->interval;
+        connsm->supervision_tmo = upd->timeout;
+        connsm->slave_latency = upd->latency;
+        connsm->tx_win_size = upd->winsize;
+        connsm->slave_cur_tx_win_usecs =  
+            connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
+        connsm->tx_win_off = upd->winoffset;
+        connsm->anchor_point += 
+            cputime_usecs_to_ticks(upd->winoffset * BLE_LL_CONN_ITVL_USECS);
+
+        /* 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_start(&connsm->conn_spvn_timer, 
connsm->anchor_point+tmo);
+
+        /* Reset update scheduled flag */
+        connsm->conn_update_scheduled = 0;
+    }
+
     /* Calculate data channel index of next connection event */
     connsm->last_unmapped_chan = connsm->unmapped_chan;
     while (latency > 0) {
@@ -1370,6 +1462,8 @@ ble_ll_conn_event_end(void *arg)
     /* Set initial schedule callback */
     connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
 
+    /* XXX: I think all this fine for when we do connection updates, but
+       we may want to force the first event to be scheduled. Not sure */
     /* Schedule the next connection event */
     while (ble_ll_sched_conn_reschedule(connsm)) {
         if (ble_ll_conn_next_event(connsm)) {
@@ -1514,7 +1608,7 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr 
*ble_hdr)
     if (connsm && BLE_MBUF_HDR_CRC_OK(ble_hdr) && 
         (ble_hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
         /* Set address of advertiser to which we are connecting. */
-        if (!ble_ll_scan_whitelist_enabled()) {
+        if (ble_ll_scan_whitelist_enabled()) {
             /* 
              * XXX: need to see if the whitelist tells us exactly what peer
              * addr type we should use? Not sure it matters. If whitelisting
@@ -1960,6 +2054,19 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t 
aa)
                         goto conn_rx_pdu_end;
                     }
 
+                    /* 
+                     * Did we transmit a REJECT_IND_EXT? If so we need
+                     * to make sure we send the connection update event
+                     */
+                    if (ble_ll_ctrl_is_reject_ind_ext(txhdr->txinfo.hdr_byte,
+                                                      txpdu->om_data[0])) {
+                        if (connsm->cur_ctrl_proc == 
+                            BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+                            connsm->reject_reason = txpdu->om_data[2];
+                            connsm->host_expects_upd_event = 1; 
+                        }
+                    }
+
                     /* Increment offset based on number of bytes sent */
                     txhdr->txinfo.offset += txhdr->txinfo.pyld_len;
                     if (txhdr->txinfo.offset >= pkthdr->omp_len) {
@@ -2126,7 +2233,7 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t 
handle, uint16_t length)
  *  
  * Context: Link Layer 
  *  
- * @param rxbuf Pointer to received PDU 
+ * @param rxbuf Pointer to received Connect Request PDU
  * @param conn_req_end receive end time of connect request 
  *  
  * @return 0: connection not started; 1 connecton started 
@@ -2294,6 +2401,8 @@ ble_ll_conn_module_init(void)
      */
     connsm = &g_ble_ll_conn_sm[0];
     for (i = 0; i < BLE_LL_CFG_CONN_MAX_CONNS; ++i) {
+        memset(connsm, 0, sizeof(struct ble_ll_conn_sm));
+
         connsm->conn_handle = i + 1;
         STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c 
b/net/nimble/controller/src/ble_ll_conn_hci.c
index a051318..4a26a9d 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -38,6 +38,47 @@ static uint32_t g_ble_ll_next_num_comp_pkt_evt;
     ((BLE_LL_CFG_NUM_COMP_PKT_RATE * OS_TICKS_PER_SEC) / 1000)
 
 /**
+ * Called to check that the connection parameters are within range 
+ * 
+ * @param itvl_min 
+ * @param itvl_max 
+ * @param latency 
+ * @param spvn_tmo 
+ * 
+ * @return int BLE_ERR_INV_HCI_CMD_PARMS if invalid parameters, 0 otherwise
+ */
+int
+ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
+                                uint16_t latency, uint16_t spvn_tmo)
+{
+    uint32_t spvn_tmo_usecs;
+    uint32_t min_spvn_tmo_usecs;
+
+    if ((itvl_min > itvl_max) || 
+        (itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
+        (itvl_min > BLE_HCI_CONN_ITVL_MAX) ||
+        (latency > BLE_HCI_CONN_LATENCY_MAX) ||
+        (spvn_tmo < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
+        (spvn_tmo > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* 
+    * Supervision timeout (in msecs) must be more than:
+    *  (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
+    */
+    spvn_tmo_usecs = spvn_tmo;
+    spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
+    min_spvn_tmo_usecs = (uint32_t)itvl_max * 2 * BLE_LL_CONN_ITVL_USECS;
+    min_spvn_tmo_usecs *= (1 + latency);
+    if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    return BLE_ERR_SUCCESS;
+}
+
+/**
  * Make a connect request PDU 
  * 
  * @param connsm 
@@ -102,7 +143,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, 
uint8_t status)
 {
     uint8_t *evbuf;
 
-    if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE - 1)) {
+    if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE)) {
         evbuf = os_memblock_get(&g_hci_cmd_pool);
         if (evbuf) {
             evbuf[0] = BLE_HCI_EVCODE_LE_META;
@@ -260,8 +301,6 @@ int
 ble_ll_conn_create(uint8_t *cmdbuf)
 {
     int rc;
-    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;
@@ -311,36 +350,17 @@ ble_ll_conn_create(uint8_t *cmdbuf)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    /* Check connection interval */
+    /* Check connection interval, latency and supervision timeoout */
     hcc->conn_itvl_min = le16toh(cmdbuf + 13);
     hcc->conn_itvl_max = le16toh(cmdbuf + 15);
     hcc->conn_latency = le16toh(cmdbuf + 17);
-    if ((hcc->conn_itvl_min > hcc->conn_itvl_max)       ||
-        (hcc->conn_itvl_min < BLE_HCI_CONN_ITVL_MIN)    ||
-        (hcc->conn_itvl_min > BLE_HCI_CONN_ITVL_MAX)    ||
-        (hcc->conn_latency > BLE_HCI_CONN_LATENCY_MAX)) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    /* Check supervision timeout */
     hcc->supervision_timeout = le16toh(cmdbuf + 19);
-    if ((hcc->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
-        (hcc->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX))
-    {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
-    }
-
-    /* 
-     * Supervision timeout (in msecs) must be more than:
-     *  (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
-     */
-    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;
+    rc = ble_ll_conn_hci_chk_conn_params(hcc->conn_itvl_min,
+                                         hcc->conn_itvl_max,
+                                         hcc->conn_latency, 
+                                         hcc->supervision_timeout);
+    if (rc) {
+        return rc;
     }
 
     /* Min/max connection event lengths */
@@ -376,6 +396,184 @@ ble_ll_conn_create(uint8_t *cmdbuf)
     return rc;
 }
 
+static int
+ble_ll_conn_process_conn_params(uint8_t *cmdbuf, struct ble_ll_conn_sm *connsm)
+{
+    int rc;
+    struct hci_conn_update *hcu;
+
+    /* Retrieve command data */
+    hcu = &connsm->conn_param_req;
+    hcu->handle = connsm->conn_handle;
+    hcu->conn_itvl_min = le16toh(cmdbuf + 2);
+    hcu->conn_itvl_max = le16toh(cmdbuf + 4);
+    hcu->conn_latency = le16toh(cmdbuf + 6);
+    hcu->supervision_timeout = le16toh(cmdbuf + 8);
+    hcu->min_ce_len = le16toh(cmdbuf + 10);
+    hcu->max_ce_len = le16toh(cmdbuf + 12);
+
+    /* Check that parameter values are in range */
+    rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
+                                         hcu->conn_itvl_max,
+                                         hcu->conn_latency, 
+                                         hcu->supervision_timeout);
+
+    /* Check valid min/max ce length */
+    if (rc || (hcu->min_ce_len > hcu->max_ce_len)) {
+        hcu->handle = 0;
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+    return rc;
+}
+
+/**
+ * Called to process a connection update command.
+ * 
+ * @param cmdbuf 
+ * 
+ * @return int 
+ */
+int
+ble_ll_conn_update(uint8_t *cmdbuf)
+{
+    int rc;
+    uint8_t ctrl_proc;
+    uint16_t handle;
+    struct ble_ll_conn_sm *connsm;
+    struct hci_conn_update *hcu;
+
+    /* XXX: must deal with slave not supporting this feature and using
+       conn update */
+
+    /* If no connection handle exit with error */
+    handle = le16toh(cmdbuf);
+    connsm = ble_ll_conn_find_active_conn(handle);
+    if (!connsm) {
+        return BLE_ERR_UNK_CONN_ID;
+    }
+
+    /* Better not have this procedure ongoing! */
+    if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) ||
+        IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
+        return BLE_ERR_CMD_DISALLOWED;
+    }
+
+    /* See if we support this feature */
+    if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
+        ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
+    } else {
+        ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+    }
+
+    /* 
+     * If we are a slave and the master has initiated the procedure already
+     * we should deny the slave request for now. If we are a master and the
+     * slave has initiated the procedure, we need to send a reject to the
+     * slave.
+     */
+    if (connsm->awaiting_host_reply) {
+        if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+            return BLE_ERR_LMP_COLLISION;
+        } else {
+            connsm->awaiting_host_reply = 0;
+
+            /* XXX: If this fails no reject ind will be sent! */
+            ble_ll_ctrl_reject_ind_ext_send(connsm,
+                                            connsm->host_reply_opcode, 
+                                            BLE_ERR_LMP_COLLISION);
+        }
+    }
+
+    /* Retrieve command data */
+    hcu = &connsm->conn_param_req;
+    hcu->handle = handle;
+    hcu->conn_itvl_min = le16toh(cmdbuf + 2);
+    hcu->conn_itvl_max = le16toh(cmdbuf + 4);
+    hcu->conn_latency = le16toh(cmdbuf + 6);
+    hcu->supervision_timeout = le16toh(cmdbuf + 8);
+    hcu->min_ce_len = le16toh(cmdbuf + 10);
+    hcu->max_ce_len = le16toh(cmdbuf + 12);
+    if (hcu->min_ce_len > hcu->max_ce_len) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check that parameter values are in range */
+    rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
+                                         hcu->conn_itvl_max,
+                                         hcu->conn_latency, 
+                                         hcu->supervision_timeout);
+    if (!rc) {
+        /* Start the control procedure */
+        ble_ll_ctrl_proc_start(connsm, ctrl_proc);
+    }
+
+    return rc;
+}
+
+int
+ble_ll_conn_param_reply(uint8_t *cmdbuf, int positive_reply)
+{
+    int rc;
+    uint8_t ble_err;
+    uint8_t *dptr;
+    uint8_t rsp_opcode;
+    uint8_t len;
+    uint16_t handle;
+    struct os_mbuf *om;
+    struct ble_ll_conn_sm *connsm;
+
+    /* See if we support this feature */
+    if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
+        return BLE_ERR_UNSUPP_FEATURE;
+    }
+
+    /* If no connection handle exit with error */
+    handle = le16toh(cmdbuf);
+
+    /* If we dont have a handle we cant do anything */
+    connsm = ble_ll_conn_find_active_conn(handle);
+    if (!connsm) {
+        return BLE_ERR_UNK_CONN_ID;
+    }
+
+    /* Make sure connection parameters are valid if this is a positive reply */
+    rc = BLE_ERR_SUCCESS;
+    ble_err = cmdbuf[2];
+    if (positive_reply) {
+        rc = ble_ll_conn_process_conn_params(cmdbuf, connsm);
+        if (rc) {
+            ble_err = BLE_ERR_CONN_PARMS;
+        }
+    }
+
+    /* The connection should be awaiting a reply. If not, just discard */
+    if (connsm->awaiting_host_reply) {
+        /* Get a control packet buffer */
+        if (positive_reply && (rc == BLE_ERR_SUCCESS)) {
+            om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+            if (om) {
+                dptr = om->om_data;
+                rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, dptr, NULL);
+                dptr[0] = rsp_opcode;
+                len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
+                ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
+            }
+        } else {
+            /* XXX: check return code and deal */
+            ble_ll_ctrl_reject_ind_ext_send(connsm, 
+                                            connsm->host_reply_opcode,
+                                            ble_err);
+        }
+        connsm->awaiting_host_reply = 0;
+
+        /* XXX: if we cant get a buffer, what do we do? We need to remember
+         * reason if it was a negative reply. We also would need to have
+           some state to tell us this happened */
+    }
+
+    return rc;
+}
+
 /**
  * Called when HCI command to cancel a create connection command has been 
  * received. 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h 
b/net/nimble/controller/src/ble_ll_conn_priv.h
index 47015a3..5c3a700 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -97,10 +97,14 @@ void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm 
*connsm,
 
 int ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf);
 int ble_ll_conn_create(uint8_t *cmdbuf);
+int ble_ll_conn_update(uint8_t *cmdbuf);
+int ble_ll_conn_param_reply(uint8_t *cmdbuf, int negative_reply);
 int ble_ll_conn_create_cancel(void);
 void ble_ll_conn_num_comp_pkts_event_send(void);
 void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t 
status);
 void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
+int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
+                                    uint16_t latency, uint16_t spvn_tmo);
 
 
 #endif /* H_BLE_LL_CONN_PRIV_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 0e5df2d..04b965e 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -49,6 +49,38 @@
  *  sent (actually attempted to tx). Do we count failures? How?
  */
 
+ /* XXX: NOTE: we are not supposed to send a REJECT_IND_EXT unless we know the
+   slave supports that feature */
+
+/* XXX:
+ * 1) One thing I need to make sure I do: if we initiated this procedure and
+ * we stop it, we have to make sure we send the update complete event! I
+ * am referring to the connection parameter request procedure. The code is
+ * already there to send the event when the connection update procedure
+ * is over.
+ */
+
+/* 
+ * XXX: I definitely have an issue with control procedures and connection
+ * param request procedure and connection update procedure. This was
+ * noted when receiving an unknown response. Right now, I am getting confused
+ * with connection parameter request and updates regarding which procedures
+ * are running. So I need to go look through all the code and see where I
+ * used the request procedure and the update procedure and make sure I am doing
+ * the correct thing.
+ */
+
+/* 
+ * This array contains the length of the CtrData field in LL control PDU's.
+ * Note that there is a one byte opcode which precedes this field in the LL
+ * control PDU, so total data channel payload length for the control pdu is
+ * one greater.
+ */
+const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
+{
+    11, 7, 1, 22, 12, 0, 0, 1, 8, 8, 0, 0, 5, 1, 8, 23, 23, 2, 0, 0, 8, 8
+};
+
 /* XXX: Improvements
  * 1) We can inititalize the procedure timer once per connection state machine
  */
@@ -88,10 +120,10 @@ ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, 
uint8_t *dptr)
     struct ble_ll_len_req ctrl_req;
 
     /* Extract parameters and check if valid */
-    ctrl_req.max_rx_bytes = le16toh(dptr + 3); 
-    ctrl_req.max_rx_time = le16toh(dptr + 5);
-    ctrl_req.max_tx_bytes = le16toh(dptr + 7);
-    ctrl_req.max_tx_time = le16toh(dptr + 9);
+    ctrl_req.max_rx_bytes = le16toh(dptr); 
+    ctrl_req.max_rx_time = le16toh(dptr + 2);
+    ctrl_req.max_tx_bytes = le16toh(dptr + 4);
+    ctrl_req.max_tx_time = le16toh(dptr + 6);
 
     if (!ble_ll_ctrl_chk_supp_bytes(ctrl_req.max_rx_bytes) ||
         !ble_ll_ctrl_chk_supp_bytes(ctrl_req.max_tx_bytes) ||
@@ -107,6 +139,122 @@ ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, 
uint8_t *dptr)
     return rc;
 }
 
+static int
+ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+                                uint8_t *rspbuf, uint8_t opcode)
+{
+    int rc;
+    int indicate;
+    uint8_t rsp_opcode;
+    uint8_t ble_err;
+    struct ble_ll_conn_params cp;
+    struct ble_ll_conn_params *req;
+    struct hci_conn_update *hcu;
+
+    /* Extract parameters and check if valid */
+    cp.interval_min = le16toh(dptr);
+    cp.interval_max = le16toh(dptr + 2);
+    cp.latency = le16toh(dptr + 4);
+    cp.timeout = le16toh(dptr + 6);
+    cp.pref_periodicity = dptr[8];
+    cp.ref_conn_event_cnt  = le16toh(dptr + 9);
+    cp.offset0 = le16toh(dptr + 11);
+    cp.offset1 = le16toh(dptr + 13);
+    cp.offset2 = le16toh(dptr + 15);
+    cp.offset3 = le16toh(dptr + 17);
+    cp.offset4 = le16toh(dptr + 19);
+    cp.offset5 = le16toh(dptr + 21);
+
+    /* Check if parameters are valid */
+    ble_err = BLE_ERR_SUCCESS;
+    rc = ble_ll_conn_hci_chk_conn_params(cp.interval_min, 
+                                         cp.interval_max,
+                                         cp.latency, 
+                                         cp.timeout);
+    if (rc) {
+        ble_err = BLE_ERR_INV_LMP_LL_PARM;
+        goto conn_param_pdu_exit;
+    }
+
+    /* 
+     * Check if there is a requested change to either the interval, timeout
+     * or latency. If not, this may just be an anchor point change and we do
+     * not have to notify the host.
+     *  XXX: what if we dont like the parameters? When do we check that out?
+     */ 
+    req = NULL;
+    indicate = 1;
+    if ((connsm->conn_itvl >= cp.interval_min) && 
+        (connsm->conn_itvl <= cp.interval_max) &&
+        (connsm->supervision_tmo == cp.timeout) &&
+        (connsm->slave_latency == cp.latency)) {
+        indicate = 0;
+        /* XXX: For now, if we are a master, we wont send a response that
+         * needs to remember the request. That might change with connection
+           update pdu. Not sure. */
+        if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+            req = &cp;
+        }
+        goto conn_parm_req_do_indicate;
+    }
+
+    /* 
+     * A change has been requested. Is it within the values specified by
+     * the host? Note that for a master we will not be processing a
+     * connect param request from a slave if we are currently trying to
+     * update the connection parameters. This means that the previous
+     * check is all we need for a master (when receiving a request).
+     */
+    if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) || 
+        (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) {
+        /* 
+         * Not sure what to do about the slave. It is possible that the 
+         * current connection parameters are not the same ones as the local 
host
+         * has provided? Not sure what to do here. Do we need to remember what
+         * host sent us? For now, I will assume that we need to remember what
+         * the host sent us and check it out.
+         */
+        hcu = &connsm->conn_param_req;
+        if (hcu->handle != 0) {
+            if (!((cp.interval_min < hcu->conn_itvl_min) ||
+                  (cp.interval_min > hcu->conn_itvl_max) ||
+                  (cp.interval_max < hcu->conn_itvl_min) ||
+                  (cp.interval_max > hcu->conn_itvl_max) ||
+                  (cp.latency != hcu->conn_latency) ||
+                  (cp.timeout != hcu->supervision_timeout))) {
+                indicate = 0;
+            }
+        }
+    }
+
+conn_parm_req_do_indicate:
+    /* 
+     * XXX: are the connection update parameters acceptable? If not, we will
+     * need to know before we indicate to the host that they are acceptable.
+     */ 
+    if (indicate) {
+        /* 
+         * Send event to host. At this point we leave and wait to get
+         * an answer.
+         */ 
+        ble_ll_hci_ev_rem_conn_parm_req(connsm, &cp);
+        connsm->host_reply_opcode = opcode;
+        connsm->awaiting_host_reply = 1;
+        rsp_opcode = 255;
+    } else {
+        /* Create reply to connection request */
+        rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, rspbuf, req);
+    }
+
+conn_param_pdu_exit:
+    if (ble_err) {
+        rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
+        rspbuf[1] = opcode;
+        rspbuf[2] = ble_err;
+    }
+    return rsp_opcode;
+}
+
 /**
  * Called to process and UNKNOWN_RSP LL control packet.
  * 
@@ -121,47 +269,34 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, 
uint8_t *dptr)
     uint8_t opcode;
 
     /* Get opcode of unknown LL control frame */
-    opcode = dptr[3];
+    opcode = dptr[0];
 
+    /* XXX: add others here */
     /* Convert opcode to control procedure id */
     switch (opcode) {
     case BLE_LL_CTRL_LENGTH_REQ:
         ctrl_proc = BLE_LL_CTRL_PROC_DATA_LEN_UPD;
         break;
+    case BLE_LL_CTRL_CONN_UPDATE_REQ:
+        ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
+        break;
+    case BLE_LL_CTRL_CONN_PARM_RSP:
+    case BLE_LL_CTRL_CONN_PARM_REQ:
+        ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+        break;
     default:
         ctrl_proc = BLE_LL_CTRL_PROC_NUM;
         break;
     }
 
+    /* XXX: are there any other events that we need to send when we get
+       the unknown response? */
     /* If we are running this one currently, stop it */
     if (connsm->cur_ctrl_proc == ctrl_proc) {
         /* Stop the control procedure */
         ble_ll_ctrl_proc_stop(connsm, ctrl_proc);
-    }
-}
-
-/**
- * Send a data length change event for a connection to the host.
- * 
- * @param connsm Pointer to connection state machine
- */
-void
-ble_ll_ctrl_datalen_chg_event(struct ble_ll_conn_sm *connsm)
-{
-    uint8_t *evbuf;
-
-    if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG - 1)) {
-        evbuf = os_memblock_get(&g_hci_cmd_pool);
-        if (evbuf) {
-            evbuf[0] = BLE_HCI_EVCODE_LE_META;
-            evbuf[1] = BLE_HCI_LE_DATA_LEN_CHG_LEN;
-            evbuf[2] = BLE_HCI_LE_SUBEV_DATA_LEN_CHG;
-            htole16(evbuf + 3, connsm->conn_handle);
-            htole16(evbuf + 5, connsm->eff_max_tx_octets);
-            htole16(evbuf + 7, connsm->eff_max_tx_time);
-            htole16(evbuf + 9, connsm->eff_max_rx_octets);
-            htole16(evbuf + 11, connsm->eff_max_rx_time);
-            ble_ll_hci_event_send(evbuf);
+        if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+            ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_FEATURE);
         }
     }
 }
@@ -185,6 +320,285 @@ ble_ll_ctrl_datalen_upd_make(struct ble_ll_conn_sm 
*connsm, uint8_t *dptr)
 }
 
 /**
+ * Called to make a connection parameter request or response control pdu.
+ * 
+ * @param connsm 
+ * @param dptr Pointer to start of data. NOTE: the opcode is not part 
+ *             of the data. 
+ */
+static void
+ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+                                struct ble_ll_conn_params *req)
+{
+    uint16_t invalid_offset;
+    struct hci_conn_update *hcu;
+
+    invalid_offset = 0xFFFF;
+    /* If we were passed in a request, we use the parameters from the request 
*/
+    if (req) {
+        htole16(dptr, req->interval_min);
+        htole16(dptr + 2, req->interval_max);
+        htole16(dptr + 4, req->latency);
+        htole16(dptr + 6, req->timeout);
+    } else {
+        hcu = &connsm->conn_param_req;
+        /* The host should have provided the parameters! */
+        assert(hcu->handle != 0);
+        htole16(dptr, hcu->conn_itvl_min);
+        htole16(dptr + 2, hcu->conn_itvl_max);
+        htole16(dptr + 4, hcu->conn_latency);
+        htole16(dptr + 6, hcu->supervision_timeout);
+    }
+
+    /* XXX: NOTE: if interval min and interval max are != to each
+     * other this value should be set to non-zero. I think this
+     * applies only when an offset field is set. See section 5.1.7.1 pg 103
+     * Vol 6 Part B.
+     */
+    /* XXX: for now, set periodicity to 0 */
+    dptr[8] = 0;
+
+    /* XXX: deal with reference event count. what to put here? */
+    htole16(dptr + 9, connsm->event_cntr);
+
+    /* XXX: For now, dont use offsets */
+    htole16(dptr + 11, invalid_offset);
+    htole16(dptr + 13, invalid_offset);
+    htole16(dptr + 15, invalid_offset);
+    htole16(dptr + 17, invalid_offset);
+    htole16(dptr + 19, invalid_offset);
+    htole16(dptr + 21, invalid_offset);
+}
+
+/**
+ * Called to make a connection update request LL control PDU
+ *  
+ * Context: Link Layer 
+ * 
+ * @param connsm 
+ * @param rsp 
+ */
+static void
+ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
+{
+    uint16_t instant;
+    struct hci_conn_update *hcu;
+    struct ble_ll_conn_upd_req *req;
+
+    /* Make sure we have the parameters! */
+    assert(connsm->conn_param_req.handle != 0);
+
+
+    /* 
+     * Set instant. We set the instant to the current event counter plus
+     * the amount of slave latency as the slave may not be listening
+     * at every connection interval and we are not sure when the connect
+     * request will actually get sent. We add one more event plus the
+     * minimum as per the spec of 6 connection events.
+     */ 
+    instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
+
+    /* 
+     * XXX: This should change in the future, but for now we will just
+     * start the new instant at the same anchor using win offset 0.
+     */
+    /* Copy parameters in connection update structure */
+    hcu = &connsm->conn_param_req;
+    req = &connsm->conn_update_req;
+    req->winsize = connsm->tx_win_size;
+    req->winoffset = 0;
+    req->interval = hcu->conn_itvl_max;
+    req->timeout = hcu->supervision_timeout;
+    req->latency = hcu->conn_latency;
+    req->instant = instant;
+
+    /* XXX: make sure this works for the connection parameter request proc. */
+    pyld[0] = req->winsize;
+    htole16(pyld + 1, req->winoffset);
+    htole16(pyld + 3, req->interval);
+    htole16(pyld + 5, req->latency);
+    htole16(pyld + 7, req->timeout);
+    htole16(pyld + 9, instant);
+
+    /* Set flag in state machine to denote we have scheduled an update */
+    connsm->conn_update_scheduled = 1;
+}
+
+/**
+ * Called to respond to a LL control PDU connection parameter request or 
+ * response. 
+ * 
+ * @param connsm 
+ * @param rsp 
+ * @param req 
+ * 
+ * @return uint8_t 
+ */
+uint8_t
+ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp,
+                             struct ble_ll_conn_params *req)
+{
+    uint8_t rsp_opcode;
+
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        /* Create a connection parameter response */
+        ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req);
+        rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP;
+    } else {
+        /* Create a connection update pdu */
+        ble_ll_ctrl_conn_upd_make(connsm, rsp + 1);
+        rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_REQ;
+    }
+
+    return rsp_opcode;
+}
+
+/**
+ * Called when we receive a connection update event
+ * 
+ * @param connsm 
+ * @param dptr 
+ * @param rspbuf 
+ * 
+ * @return int 
+ */
+static int
+ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+                           uint8_t *rspbuf)
+{
+    uint8_t rsp_opcode;
+    uint16_t conn_events;
+    struct ble_ll_conn_upd_req *reqdata;
+
+    /* Only a slave should receive this */
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
+        return BLE_ERR_MAX;
+    }
+
+#if 0
+    /* Deal with receiving this when in this state. I think we are done */
+    if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+    }
+#endif
+
+    /* Retrieve parameters */
+    reqdata = &connsm->conn_update_req;
+    reqdata->winsize = dptr[0]; 
+    reqdata->winoffset = le16toh(dptr + 1);
+    reqdata->interval = le16toh(dptr + 3);
+    reqdata->latency = le16toh(dptr + 5);
+    reqdata->timeout = le16toh(dptr + 7);
+    reqdata->instant = le16toh(dptr + 9);
+
+    /* XXX: validate them at some point. If they dont check out, we
+       return the unknown response */
+
+    /* If instant is in the past, we have to end the connection */
+    conn_events = (reqdata->instant - connsm->event_cntr) & 0xFFFF;
+    if (conn_events >= 32767) {
+        ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
+        rsp_opcode = BLE_ERR_MAX;
+    } else {
+        connsm->conn_update_scheduled = 1;
+    }
+
+    return rsp_opcode;
+}
+
+static int
+ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+                              uint8_t *rspbuf)
+{
+    uint8_t rsp_opcode;
+
+    /* 
+     * This is not in the specification per se but it simplifies the
+     * implementation. If we get a connection parameter request and we
+     * are awaiting a reply from the host, simply ignore the request. This
+     * might not be a good idea if the parameters are different, but oh
+     * well. This is not expected to happen anyway. A return of BLE_ERR_MAX
+     * means that we will simply discard the connection parameter request
+     */
+    if (connsm->awaiting_host_reply) {
+        return BLE_ERR_MAX;
+    }
+
+    /* XXX: remember to deal with this on the master: if the slave has
+     * initiated a procedure we may have received its connection parameter
+     * update request and have signaled the host with an event. If that
+     * is the case, we will need to drop the host command when we get it
+       and also clear any applicable states. */
+
+    /* XXX: Read 5.3 again. There are multiple control procedures that might
+     * be pending (a connection update) that will cause collisions and the
+       behavior below. */
+    /*
+     * Check for procedure collision (Vol 6 PartB 5.3). If we are a slave
+     * and we receive a request we "consider the slave initiated
+     * procedure as complete". This means send a connection update complete
+     * event (with error).
+     * 
+     * If a master, we send reject with a
+     * transaction collision error code.
+     */
+    if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+        if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+            if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+                ble_ll_ctrl_proc_stop(connsm,
+                                      BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+            } else {
+                connsm->pending_ctrl_procs &= 
+                    ~BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
+            }
+            ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION);
+        } else {
+            /* The master sends reject ind ext w/error code 0x23 */
+            rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
+            rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ;
+            rspbuf[2] = BLE_ERR_LMP_COLLISION;
+            return rsp_opcode;
+        }
+    }
+
+    /* Process the received connection parameter request */
+    rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
+                                                 BLE_LL_CTRL_CONN_PARM_REQ);
+    return rsp_opcode;
+}
+
+static int
+ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
+                              uint8_t *rspbuf)
+{
+    uint8_t rsp_opcode;
+
+    /* A slave should never receive this response */
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        return BLE_ERR_MAX;
+    }
+
+    /* 
+     * This case should never happen! It means that the slave initiated a
+     * procedure and the master initiated one as well. If we do get in this
+     * state just clear the awaiting reply. The slave will hopefully stop its
+     * procedure when we reply.
+     */ 
+    if (connsm->awaiting_host_reply) {
+        connsm->awaiting_host_reply = 0;
+    }
+
+    /* If we receive a response and no procedure is pending, just leave */
+    if (!IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
+        return BLE_ERR_MAX;
+    }
+
+    /* Process the received connection parameter response */
+    rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
+                                                 BLE_LL_CTRL_CONN_PARM_RSP);
+    return rsp_opcode;
+}
+
+/**
  * Callback when LL control procedure times out (for a given connection). If 
  * this is called, it means that we need to end the connection because it 
  * has not responded to a LL control request. 
@@ -224,15 +638,21 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int 
ctrl_proc)
 
         switch (ctrl_proc) {
         case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
-            len = BLE_LL_CTRL_LENGTH_REQ_LEN;
             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[1] = connsm->disconnect_reason;
             break;
+        case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
+            opcode = BLE_LL_CTRL_CONN_PARM_REQ;
+            ble_ll_ctrl_conn_param_pdu_make(connsm, dptr + 1, NULL);
+            break;
+        case BLE_LL_CTRL_PROC_CONN_UPDATE:
+            opcode = BLE_LL_CTRL_CONN_UPDATE_REQ;
+            ble_ll_ctrl_conn_upd_make(connsm, dptr + 1);
+            break;
         default:
             assert(0);
             break;
@@ -240,7 +660,7 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int 
ctrl_proc)
 
         /* Set llid, length and opcode */
         dptr[0] = opcode;
-        ++len;
+        len = g_ble_ll_ctrl_pkt_lengths[opcode] + 1;
 
         /* Add packet to transmit queue of connection */
         ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
@@ -272,6 +692,29 @@ ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode)
 }
 
 /**
+ * Called to determine if the pdu is a TERMINATE_IND 
+ * 
+ * @param hdr 
+ * @param opcode 
+ * 
+ * @return int 
+ */
+int
+ble_ll_ctrl_is_reject_ind_ext(uint8_t hdr, uint8_t opcode)
+{
+    int rc;
+
+    rc = 0;
+    if ((hdr & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
+        if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) {
+            rc = 1;
+        }
+    }
+    return rc;
+}
+
+
+/**
  * Stops the LL control procedure indicated by 'ctrl_proc'. 
  *  
  * Context: Link Layer task 
@@ -282,11 +725,11 @@ ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode)
 void
 ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc)
 {
-    if (connsm->cur_ctrl_proc == ctrl_proc) {
-        os_callout_stop(&connsm->ctrl_proc_rsp_timer.cf_c);
-        connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
-        connsm->pending_ctrl_procs &= ~(1 << ctrl_proc);
-    }
+    assert(connsm->cur_ctrl_proc == ctrl_proc);
+    
+    os_callout_stop(&connsm->ctrl_proc_rsp_timer.cf_c);
+    connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
+    connsm->pending_ctrl_procs &= ~(1 << ctrl_proc);
 
     /* If there are others, start them */
     ble_ll_ctrl_chk_proc_start(connsm);
@@ -352,7 +795,7 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int 
ctrl_proc)
 
             /* Re-start the timer. Control procedure timeout is 40 seconds */
             os_callout_reset(&connsm->ctrl_proc_rsp_timer.cf_c, 
-                             OS_TICKS_PER_SEC * 40);
+                             OS_TICKS_PER_SEC * BLE_LL_CTRL_PROC_TIMEOUT);
         }
     }
 
@@ -378,7 +821,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
         /* 
          * 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
+         * Start it now.
          */ 
         ble_ll_ctrl_terminate_start(connsm);
         return;
@@ -413,70 +856,91 @@ void
 ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
 {
     uint8_t features;
+    uint8_t feature;
     uint8_t len;
     uint8_t opcode;
+    uint8_t rsp_opcode;
     uint8_t *dptr;
+    uint8_t *rspbuf;
 
     /* XXX: where do we validate length received and packet header length?
      * do this in LL task when received. Someplace!!! What I mean
      * is we should validate the over the air length with the mbuf length.
        Should the PHY do that???? */
 
-    /* Get length and opcode from PDU */
+    /* Get length and opcode from PDU.*/
     dptr = om->om_data;
+    rspbuf = dptr;
     len = dptr[1];
     opcode = dptr[2];
 
+    /* Move data pointer to start of control data (2 byte PDU hdr + opcode) */
+    dptr += (BLE_LL_PDU_HDR_LEN + 1);
+
+    /* 
+     * Subtract the opcode from the length. Note that if the length was zero,
+     * which would be an error, we will fail the check against the length
+     * of the control packet.
+     */
+    --len;
+
     /* opcode must be good */
-    if ((opcode > BLE_LL_CTRL_LENGTH_RSP) || (len < 1) || 
-        (len > BLE_LL_CTRL_MAX_PAYLOAD)) {
+    if ((opcode >= BLE_LL_CTRL_OPCODES) || 
+        (len != g_ble_ll_ctrl_pkt_lengths[opcode])) {
         goto rx_malformed_ctrl;
     }
 
-    /* Subtract the opcode from the length */
-    --len;
-
+    /* Check if the feature is supported. */
     switch (opcode) {
     case BLE_LL_CTRL_LENGTH_REQ:
-        /* Check length */
-        if (len != BLE_LL_CTRL_LENGTH_REQ_LEN) {
-            goto rx_malformed_ctrl;
-        }
+        feature = BLE_LL_FEAT_DATA_LEN_EXT;
+        break;
+    case BLE_LL_CTRL_CONN_PARM_REQ:
+    case BLE_LL_CTRL_CONN_PARM_RSP:
+        feature = BLE_LL_FEAT_CONN_PARM_REQ;
+        break;
+    default:
+        feature = 0;
+        break;
+    }
 
-        /* Check parameters for validity */
+    if (feature) {
         features = ble_ll_read_supp_features();
-        if (features & BLE_LL_FEAT_DATA_LEN_EXT) {
-            /* Extract parameters and check if valid */
-            if (ble_ll_ctrl_len_proc(connsm, dptr)) {
-                goto rx_malformed_ctrl;
-            }
-
-            /* 
-             * If we have not started this procedure ourselves and it is
-             * pending, no need to perform it.
-             */
-            if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) &&
-                IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) 
{
-                connsm->pending_ctrl_procs &= ~BLE_LL_CTRL_PROC_DATA_LEN_UPD;
-            }
-
-            /* Send a response */
-            opcode = BLE_LL_CTRL_LENGTH_RSP;
-            ble_ll_ctrl_datalen_upd_make(connsm, dptr);
-        } else {
-            /* XXX: construct unknown pdu */
-            opcode = BLE_LL_CTRL_UNKNOWN_RSP;
-            len = BLE_LL_CTRL_UNK_RSP_LEN;
-            dptr[1] = BLE_LL_CTRL_LENGTH_REQ;
+        if ((features & feature) == 0) {
+            /* Construct unknown rsp pdu */
+            rspbuf[1] = opcode;
+            rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
+            goto ll_ctrl_send_rsp;
         }
+    }
+
+    /* Process opcode */
+    rsp_opcode = 255;
+    switch (opcode) {
+    case BLE_LL_CTRL_CONN_UPDATE_REQ:
+        rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr, rspbuf);
         break;
-    case BLE_LL_CTRL_LENGTH_RSP:
-        /* Check length (response length same as request length) */
-        if (len != BLE_LL_CTRL_LENGTH_REQ_LEN) {
+    case BLE_LL_CTRL_LENGTH_REQ:
+        /* Extract parameters and check if valid */
+        if (ble_ll_ctrl_len_proc(connsm, dptr)) {
             goto rx_malformed_ctrl;
         }
 
         /* 
+         * If we have not started this procedure ourselves and it is
+         * pending, no need to perform it.
+         */
+        if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) &&
+            IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) {
+            connsm->pending_ctrl_procs &= ~BLE_LL_CTRL_PROC_DATA_LEN_UPD;
+        }
+
+        /* Send a response */
+        rsp_opcode = BLE_LL_CTRL_LENGTH_RSP;
+        ble_ll_ctrl_datalen_upd_make(connsm, rspbuf);
+        break;
+    case BLE_LL_CTRL_LENGTH_RSP:
+        /* 
          * According to specification, we should only process this if we
          * asked for it.
          */
@@ -489,29 +953,49 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct 
os_mbuf *om)
             /* Stop the control procedure */
             ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
         }
-        opcode = 255;
         break;
     case BLE_LL_CTRL_UNKNOWN_RSP:
-        /* Check length (response length same as request length) */
-        if (len != BLE_LL_CTRL_UNK_RSP_LEN) {
-            goto rx_malformed_ctrl;
-        }
-
         ble_ll_ctrl_proc_unk_rsp(connsm, dptr);
-        opcode = 255;
+        break;
+
+    /* XXX: remember to check if feature supported */
+    case BLE_LL_CTRL_CHANNEL_MAP_REQ:
+    case BLE_LL_CTRL_ENC_REQ:
+    case BLE_LL_CTRL_START_ENC_REQ:
+    case BLE_LL_CTRL_FEATURE_REQ:
+    case BLE_LL_CTRL_PAUSE_ENC_REQ:
+    case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
+        /* Construct unknown pdu */
+        rspbuf[1] = opcode;
+        rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
+        break;
+    case BLE_LL_CTRL_CONN_PARM_REQ:
+        rsp_opcode = ble_ll_ctrl_rx_conn_param_req(connsm, dptr, rspbuf);
+        break;
+    case BLE_LL_CTRL_CONN_PARM_RSP:
+        rsp_opcode = ble_ll_ctrl_rx_conn_param_rsp(connsm, dptr, rspbuf);
+        break;
+    case BLE_LL_CTRL_REJECT_IND_EXT:
+        /* XXX: not sure what other control procedures to check out, but
+           add them when needed */
+        /* XXX: should I check to make sure that the rejected opcode is sane? 
*/
+        if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
+            ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
+            ble_ll_hci_ev_conn_update(connsm, dptr[1]);
+        }
         break;
     default:
-        /* XXX: this is an un-implemented control procedure. What to do? */
-        opcode = 255;
+        /* We really should never get here */
         break;
     }
 
     /* Free mbuf or send response */
-    if (opcode == 255) {
+ll_ctrl_send_rsp:
+    if (rsp_opcode == 255) {
         os_mbuf_free(om);
     } else {
-        ++len;
-        dptr[0] = opcode;
+        rspbuf[0] = rsp_opcode;
+        len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
         ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
     }
     return;
@@ -521,3 +1005,37 @@ rx_malformed_ctrl:
     ++g_ble_ll_stats.rx_malformed_ctrl_pdus;
     return;
 }
+
+/**
+ * Called to creeate and send a REJECT_IND_EXT control PDU
+ * 
+ * 
+ * @param connsm 
+ * @param rej_opcode 
+ * @param err 
+ * 
+ * @return int 
+ */
+int
+ble_ll_ctrl_reject_ind_ext_send(struct ble_ll_conn_sm *connsm,
+                                uint8_t rej_opcode, uint8_t err)
+{
+    int rc;
+    uint8_t len;
+    uint8_t *rspbuf;
+    struct os_mbuf *om;
+
+    om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    if (om) {
+        rspbuf = om->om_data;
+        rspbuf[0] = BLE_LL_CTRL_REJECT_IND_EXT;
+        rspbuf[1] = rej_opcode;
+        rspbuf[2] = err;
+        len = BLE_LL_CTRL_REJECT_IND_EXT_LEN + 1;
+        ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
+        rc = 0;
+    } else {
+        rc = 1;
+    }
+    return rc;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/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 3f6bd95..112e7e8 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -157,20 +157,22 @@ ble_ll_hci_le_read_local_features(uint8_t *rspbuf, 
uint8_t *rsplen)
 /**
  * Checks to see if a LE event has been disabled by the host. 
  * 
- * @param bitpos This is the bit position of the LE event. Note that this can 
+ * @param subev Sub-event code of the LE Meta 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_le_event_enabled(int bitpos)
+ble_ll_hci_is_le_event_enabled(int subev)
 {
     uint8_t enabled;
     uint8_t bytenum;
     uint8_t bitmask;
+    int bitpos;
 
     /* The LE meta event must be enabled for any LE event to be enabled */
     enabled = 0;
+    bitpos = subev - 1;
     if (g_ble_ll_hci_event_mask[7] & 0x20) {
         bytenum = bitpos / 8;
         bitmask = 1 << (bitpos & 0x7);
@@ -332,6 +334,26 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, 
uint8_t *rsplen)
             rc = ble_ll_whitelist_rmv(cmdbuf + 1, cmdbuf[0]);
         }
         break;
+    case BLE_HCI_OCF_LE_CONN_UPDATE:
+        if (len == BLE_HCI_CONN_UPDATE_LEN) {
+            rc = ble_ll_conn_update(cmdbuf);
+        }
+        /* This is a hack; command status gets sent instead of cmd complete */
+        rc += (BLE_ERR_MAX + 1);
+        break;
+
+    case BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR:
+        if (len == BLE_HCI_CONN_PARAM_NEG_REPLY_LEN) {
+            rc = ble_ll_conn_param_reply(cmdbuf, 0);
+        }
+        break;
+
+    case BLE_HCI_OCF_LE_REM_CONN_PARAM_RR:
+        if (len == BLE_HCI_CONN_PARAM_REPLY_LEN) {
+            rc = ble_ll_conn_param_reply(cmdbuf, 1);
+        }
+        break;
+
     default:
         rc = BLE_ERR_UNKNOWN_HCI_CMD;
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c 
b/net/nimble/controller/src/ble_ll_scan.c
index 1b2ec0b..93aca0e 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -124,46 +124,6 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int 
success)
 }
 
 /**
- * Called to determine if we are inside or outside the scan window. If we 
- * are inside the scan window it means that the device should be receiving 
- * on the scan channel. 
- * 
- * Context: Interrupt and Link Layer
- *  
- * @param scansm 
- * 
- * @return int 0: inside scan window 1: outside scan window
- */
-int
-ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm)
-{
-    int rc;
-    uint32_t now;
-    uint32_t itvl;
-
-    rc = 0;
-    itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
-    now = cputime_get32();
-    while ((int32_t)(now - scansm->scan_win_start_time) >= itvl) {
-        scansm->scan_win_start_time += itvl;
-        ++scansm->scan_chan;
-        if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
-            scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
-        }
-    }
-
-    if (scansm->scan_window != scansm->scan_itvl) {
-        itvl = cputime_usecs_to_ticks(scansm->scan_window * 
-                                      BLE_HCI_SCAN_ITVL);
-        if ((now - scansm->scan_win_start_time) >= itvl) {
-            rc = 1;
-        }
-    }
-
-    return rc;
-}
-
-/**
  * ble ll scan req pdu make
  *  
  * Construct a SCAN_REQ PDU. 
@@ -431,7 +391,7 @@ ble_ll_hci_send_adv_report(uint8_t pdu_type, uint8_t txadd, 
uint8_t *rxbuf,
         adv_data_len -= BLE_DEV_ADDR_LEN;
     }
 
-    if (ble_ll_hci_is_le_event_enabled(subev - 1)) {
+    if (ble_ll_hci_is_le_event_enabled(subev)) {
         evbuf = os_memblock_get(&g_hci_cmd_pool);
         if (evbuf) {
             evbuf[0] = BLE_HCI_EVCODE_LE_META;
@@ -539,12 +499,12 @@ ble_ll_scan_chk_filter_policy(uint8_t pdu_type, uint8_t 
*rxbuf, uint8_t flags)
  * @return int 
  */
 static int
-ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
+ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan)
 {
     int rc;
     
     /* Set channel */
-    rc = ble_phy_setchan(scansm->scan_chan, 0, 0);
+    rc = ble_phy_setchan(chan, 0, 0);
     assert(rc == 0);
 
     /* 
@@ -568,7 +528,6 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
         /* Set end time to end of scan window */
         rc = BLE_LL_SCHED_STATE_RUNNING;
     }
-    scansm->last_sched_time = cputime_get32();
 
     /* If there is a still a scan response pending, we have failed! */
     if (scansm->scan_rsp_pending) {
@@ -578,6 +537,75 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
     return rc;
 }
 
+static void
+ble_ll_scan_update_window(struct ble_ll_scan_sm *scansm, uint32_t cputime)
+{
+    uint8_t chan;
+    uint32_t itvl;
+    uint32_t win_start;
+
+    itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+    chan = scansm->scan_chan;
+    win_start = scansm->scan_win_start_time;
+    while ((int32_t)(cputime - win_start) >= itvl) {
+        win_start += itvl;
+        ++chan;
+        if (chan == BLE_PHY_NUM_CHANS) {
+            chan = BLE_PHY_ADV_CHAN_START;
+        }
+    }
+
+    scansm->scan_chan = chan;
+    scansm->scan_win_start_time = win_start;
+    scansm->last_sched_time = cputime;
+}
+
+/**
+ * Called to determine if we are inside or outside the scan window. If we 
+ * are inside the scan window it means that the device should be receiving 
+ * on the scan channel. 
+ * 
+ * Context: Interrupt and Link Layer
+ *  
+ * @param scansm 
+ * 
+ * @return int 0: inside scan window 1: outside scan window
+ */
+static int
+ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
+{
+    int rc;
+    uint8_t chan;
+    uint32_t itvl;
+    uint32_t win_start;
+
+    itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+    chan = scansm->scan_chan;
+    win_start = scansm->scan_win_start_time;
+    while ((int32_t)(cputime - win_start) >= itvl) {
+        win_start += itvl;
+        ++chan;
+        if (chan == BLE_PHY_NUM_CHANS) {
+            chan = BLE_PHY_ADV_CHAN_START;
+        }
+    }
+
+    rc = 0;
+    if (scansm->scan_window != scansm->scan_itvl) {
+        itvl = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+        if ((cputime - win_start) >= itvl) {
+            rc = 1;
+        }
+    }
+
+    if (!rc) {
+        /* Turn on the receiver and set state */
+        ble_ll_scan_start(scansm, chan);
+    }
+
+    return rc;
+}
+
 /**
  * Called when the scanning schedule item executes
  *  
@@ -591,6 +619,7 @@ int
 ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
 {
     int rc;
+    uint32_t now;
     struct ble_ll_scan_sm *scansm;
 
     /* 
@@ -618,23 +647,22 @@ ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
         break;
     }
 
+    now = cputime_get32();
     scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
     if (rc) {
         rc =  BLE_LL_SCHED_STATE_DONE;
     } else {
         /* Determine if we should be off or receiving */
-        rc = ble_ll_scan_window_chk(scansm);
+        rc = ble_ll_scan_window_chk(scansm, now);
         if (!rc) {
-            ble_ll_scan_start(scansm);
             rc = BLE_LL_SCHED_STATE_RUNNING;
         } else {
             rc =  BLE_LL_SCHED_STATE_DONE;
         }
     }
 
-    if (rc == BLE_LL_SCHED_STATE_DONE) {
-        scansm->last_sched_time = cputime_get32();
-    }
+    /* Update scan window start time and channel */
+    ble_ll_scan_update_window(scansm, now);
 
     /* Post scanning scheduled done event */
     ble_ll_event_send(&scansm->scan_sched_ev);
@@ -733,6 +761,7 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
     /* XXX: align to current or next slot???. */
     /* Schedule start time now */
     scansm->scan_win_start_time = cputime_get32();
+    scansm->last_sched_time = scansm->scan_win_start_time;
 
     /* 
      * If we are in standby, start scanning. Otherwise, scanning will resume
@@ -740,7 +769,7 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
      */ 
     OS_ENTER_CRITICAL(sr);
     if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
-        ble_ll_scan_start(scansm);
+        ble_ll_scan_start(scansm, BLE_PHY_ADV_CHAN_START);
     }
     OS_EXIT_CRITICAL(sr);
 
@@ -986,10 +1015,7 @@ ble_ll_scan_chk_resume(void)
     if (scansm->scan_enabled) {
         OS_ENTER_CRITICAL(sr);
         if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
-            if (!ble_ll_scan_window_chk(scansm)) {
-                /* Turn on the receiver and set state */
-                ble_ll_scan_start(scansm);
-            }
+            ble_ll_scan_window_chk(scansm, cputime_get32());
         }
         OS_EXIT_CRITICAL(sr);
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/262b1be2/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index a3c1466..67795f5 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -25,6 +25,7 @@
 /* BLE */
 #include "nimble/ble.h"
 #include "nimble/hci_transport.h"
+#include "nimble/hci_common.h"
 #include "host/host_hci.h"
 #include "host/ble_hs.h"
 #include "controller/ble_ll.h"
@@ -33,9 +34,6 @@
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_adv.h"
 
-/* Init all tasks */
-volatile int tasks_initialized;
-
 /* Task 1 */
 #define HOST_TASK_PRIO      (1)
 
@@ -53,7 +51,7 @@ uint8_t g_host_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
 uint8_t g_host_adv_len;
 
 /* Create a mbuf pool of BLE mbufs */
-#define MBUF_NUM_MBUFS      (20)
+#define MBUF_NUM_MBUFS      (40)
 #define MBUF_BUF_SIZE       \
     ((BLE_LL_CFG_ACL_DATA_PKT_LEN + sizeof(struct hci_data_hdr) + 3) & 0xFFFC)
 #define MBUF_MEMBLOCK_SIZE  (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
@@ -77,15 +75,16 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
 #define BLETEST_CFG_SCAN_WINDOW         (700000 / BLE_HCI_SCAN_ITVL)
 #define BLETEST_CFG_SCAN_TYPE           (BLE_HCI_SCAN_TYPE_ACTIVE)
 #define BLETEST_CFG_SCAN_FILT_POLICY    (BLE_HCI_SCAN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_ITVL           (1000)  /* in 1.25 msec increments */  
         
+#define BLETEST_CFG_CONN_ITVL           (64)  /* in 1.25 msec increments */    
       
 #define BLETEST_CFG_SLAVE_LATENCY       (0)
 #define BLETEST_CFG_INIT_FILTER_POLICY  (BLE_HCI_CONN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_SPVN_TMO       (1000)  /* 10 seconds */
+#define BLETEST_CFG_CONN_SPVN_TMO       (2000)  /* 20 seconds */
 #define BLETEST_CFG_MIN_CE_LEN          (6)    
 #define BLETEST_CFG_MAX_CE_LEN          (BLETEST_CFG_CONN_ITVL)
-#define BLETEST_CFG_CONCURRENT_CONNS    (8)
+#define BLETEST_CFG_CONCURRENT_CONNS    (1)
 
 /* BLETEST variables */
+#undef BLETEST_ADV_PKT_NUM
 #define BLETEST_PKT_SIZE                (128)
 #define BLETEST_STACK_SIZE              (256)
 #define BLETEST_TASK_PRIO               (HOST_TASK_PRIO + 1)
@@ -94,13 +93,16 @@ int g_bletest_state;
 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];
+#if !defined(nzbss_t)
+#define nzbss_t
+#endif
+nzbss_t os_stack_t bletest_stack[BLETEST_STACK_SIZE];
 uint32_t g_bletest_conn_end;
 uint8_t g_bletest_current_conns;
 uint8_t g_bletest_cur_peer_addr[BLE_DEV_ADDR_LEN];
 uint8_t g_last_handle_used;
 
-#if 0
+#ifdef BLETEST_ADV_PKT_NUM
 void
 bletest_inc_adv_pkt_num(void)
 {
@@ -128,12 +130,6 @@ bletest_inc_adv_pkt_num(void)
         host_hci_outstanding_opcode = 0;
     }
 }
-#else
-void
-bletest_inc_adv_pkt_num(void)
-{
-    return;
-}
 #endif
 
 /**
@@ -333,7 +329,9 @@ bletest_init_initiator(void)
 void
 bletest_execute(void)
 {
+    int rc;
     uint16_t handle;
+    struct hci_conn_update hcu;
 
     /* 
      * Determine if there is an active connection for the current handle
@@ -342,6 +340,9 @@ bletest_execute(void)
     if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
         handle = g_bletest_current_conns + 1;
         if (ble_ll_conn_find_active_conn(handle)) {
+            /* Set next os time to start the connection update */
+            g_next_os_time = 0;
+
             /* Scanning better be stopped! */
             assert(ble_ll_scan_enabled() == 0);
 
@@ -356,6 +357,30 @@ bletest_execute(void)
                 bletest_init_initiator();
             }
         }
+    } else {
+        /* Issue a connection parameter update to connection handle 1 */
+        if (g_next_os_time == 0) {
+            g_next_os_time = os_time_get();
+            g_next_os_time += OS_TICKS_PER_SEC * 5;
+        } else {
+            if (g_next_os_time != 0xffffffff) {
+                if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
+                    hcu.conn_latency = 0;
+                    hcu.supervision_timeout = 1000; 
+                    hcu.conn_itvl_min = 1000;
+                    hcu.conn_itvl_max = 1000;
+                    hcu.handle = 1;
+                    hcu.min_ce_len = 4;
+                    hcu.max_ce_len = 4;
+
+                    rc = host_hci_cmd_le_conn_update(&hcu);
+                    assert(rc == 0);
+                    host_hci_outstanding_opcode = 0;
+
+                    g_next_os_time = 0xffffffff;
+                }
+            }
+        }
     }
 }
 #endif
@@ -488,7 +513,7 @@ bletest_execute(void)
         if (g_bletest_current_conns) {
             for (i = 0; i < g_bletest_current_conns; ++i) {
                 if ((g_last_handle_used == 0) || 
-                    (g_last_handle_used >= g_bletest_current_conns)) {
+                    (g_last_handle_used > g_bletest_current_conns)) {
                     g_last_handle_used = 1;
                 }
                 handle = g_last_handle_used;
@@ -653,8 +678,6 @@ init_tasks(void)
                  BLETEST_TASK_PRIO, OS_WAIT_FOREVER, bletest_stack, 
                  BLETEST_STACK_SIZE);
 
-    tasks_initialized = 1;
-
     /* Initialize host HCI */
     rc = ble_hs_init(HOST_TASK_PRIO);
     assert(rc == 0);

Reply via email to