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 2016/01/26 07:27:39 UTC

incubator-mynewt-larva git commit: Add local and remote version info commands, events and LL control procedures

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 088ede8da -> 9263db577


Add local and remote version info commands, events and LL control procedures


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

Branch: refs/heads/master
Commit: 9263db577c210254d638a86ddfbe4628731481f7
Parents: 088ede8
Author: wes3 <wi...@micosa.io>
Authored: Mon Jan 25 22:20:08 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Mon Jan 25 22:27:27 2016 -0800

----------------------------------------------------------------------
 .../controller/include/controller/ble_ll.h      |   4 +
 .../controller/include/controller/ble_ll_conn.h |   6 +
 .../controller/include/controller/ble_ll_ctrl.h |   6 +-
 net/nimble/controller/src/ble_ll_conn.c         |  12 +-
 net/nimble/controller/src/ble_ll_conn_hci.c     |  50 +++++++-
 net/nimble/controller/src/ble_ll_conn_priv.h    |   1 +
 net/nimble/controller/src/ble_ll_ctrl.c         | 128 +++++++++++++++----
 net/nimble/controller/src/ble_ll_hci.c          |  11 +-
 net/nimble/controller/src/ble_ll_hci_ev.c       |  24 +++-
 net/nimble/host/include/host/host_hci.h         |   1 +
 net/nimble/host/src/host_dbg.c                  |  18 +++
 net/nimble/host/src/host_hci_cmd.c              |  12 ++
 net/nimble/include/nimble/hci_common.h          |   6 +-
 project/bletest/src/main.c                      |  11 ++
 14 files changed, 249 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 948d8e6..d76dccb 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -19,6 +19,10 @@
 
 #include "hal/hal_cputime.h"
 
+/* Controller revision. */
+#define BLE_LL_SUB_VERS_NR      (0x0000)
+#define BLE_LL_MFRG_ID          (0xFFFF)    /* XXX: replace with real one */
+
 /* 
  * The amount of time that we will wait to hear the start of a receive
  * packet after we have transmitted a packet. This time is at least

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 f4ad0e5..3f4d48f 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -104,6 +104,8 @@ struct ble_ll_conn_sm
     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 version_ind_sent;       /* note: can be 1 bit */
+    uint8_t rxd_version_ind;        /* not can be 1 bit */
     uint8_t reject_reason;
     uint8_t host_reply_opcode;
     uint8_t master_sca;
@@ -112,10 +114,14 @@ struct ble_ll_conn_sm
     uint8_t disconnect_reason;
     uint8_t rxd_disconnect_reason;
     uint8_t common_features;        /* Just a uint8 for now */
+    uint8_t vers_nr;
     uint16_t pending_ctrl_procs;
     uint16_t event_cntr;
     uint16_t conn_handle;
     uint16_t completed_pkts;
+    uint16_t comp_id;
+    uint16_t sub_vers_nr;
+
     uint32_t access_addr;
     uint32_t crcinit;               /* only low 24 bits used */
     uint32_t ce_end_time;   /* cputime at which connection event should end */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 0dfe129..ecd1541 100644
--- a/net/nimble/controller/include/controller/ble_ll_ctrl.h
+++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h
@@ -35,7 +35,8 @@
 #define BLE_LL_CTRL_PROC_IDLE           (255)
 
 /* Checks if a particular control procedure is running */
-#define IS_PENDING_CTRL_PROC_M(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
+#define IS_PENDING_CTRL_PROC(sm, proc)  (sm->pending_ctrl_procs & (1 << proc))
+#define CLR_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs &= ~(1 << proc))
 
 /* LL control procedure timeout */
 #define BLE_LL_CTRL_PROC_TIMEOUT        (40)    /* in secs */
@@ -237,7 +238,8 @@ 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);
-void ble_ll_hci_ev_read_rem_used_feat(struct ble_ll_conn_sm *connsm, 
+void ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, 
                                       uint8_t status);
+void ble_ll_hci_ev_rd_rem_ver(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/9263db57/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 623628c..e219bbb 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -986,6 +986,12 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
     connsm->send_conn_upd_event = 0;
     connsm->conn_update_scheduled = 0;
     connsm->host_expects_upd_event = 0;
+    connsm->version_ind_sent = 0;
+    connsm->common_features = 0;
+    connsm->vers_nr = 0;
+    connsm->comp_id = 0;
+    connsm->sub_vers_nr = 0;
+    connsm->rxd_version_ind = 0;
 
     /* Reset current control procedure */
     connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
@@ -1199,10 +1205,10 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
      */
     if (connsm->host_expects_upd_event) {
         update_status = BLE_ERR_SUCCESS;
-        if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
+        if (IS_PENDING_CTRL_PROC(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)) {
+            if (IS_PENDING_CTRL_PROC(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;
             }
@@ -2108,7 +2114,7 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
          * no use sending the terminate ind. We need to get an ACK for the
          * terminate ind (master and/or slave) so that is why it is two packets.
          */ 
-        if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_TERMINATE)) {
+        if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_TERMINATE)) {
             ticks = BLE_TX_DUR_USECS_M(0) +
                 BLE_TX_DUR_USECS_M(BLE_LL_CTRL_TERMINATE_IND_LEN + 1) + 
                 BLE_LL_IFS;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 2d28f83..102462e 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -486,8 +486,8 @@ ble_ll_conn_update(uint8_t *cmdbuf)
     }
 
     /* 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)) {
+    if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) ||
+        IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
         return BLE_ERR_CMD_DISALLOWED;
     }
 
@@ -682,8 +682,7 @@ ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf)
                     rc = BLE_ERR_CMD_DISALLOWED;
                 } else {
                     /* This control procedure better not be pending! */
-                    assert(!IS_PENDING_CTRL_PROC_M(connsm,
-                                                   BLE_LL_CTRL_PROC_TERMINATE));
+                    assert(!IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_TERMINATE));
 
                     /* Record the disconnect reason */
                     connsm->disconnect_reason = reason;
@@ -704,3 +703,46 @@ ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf)
 
     return rc;
 }
+
+/**
+ * Called to process a HCI disconnect command 
+ *  
+ * Context: Link Layer task (HCI command parser). 
+ * 
+ * @param cmdbuf 
+ * 
+ * @return int 
+ */
+int
+ble_ll_conn_hci_rd_rem_ver_cmd(uint8_t *cmdbuf)
+{
+    uint16_t handle;
+    struct ble_ll_conn_sm *connsm;
+
+    /* Check for valid parameters */
+    handle = le16toh(cmdbuf);
+    connsm = ble_ll_conn_find_active_conn(handle);
+    if (!connsm) {
+        return BLE_ERR_UNK_CONN_ID;
+    }
+
+    /* Return error if in progress */
+    if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) {
+        return BLE_ERR_CMD_DISALLOWED;
+    }
+
+    /* 
+     * Start this control procedure. If we have already done this control
+     * procedure we set the pending bit so that the host gets an event because
+     * it is obviously expecting one (or would not have sent the command).
+     * NOTE: we cant just send the event here. That would cause the event to
+     * be queued before the command status.
+     */
+    if (!connsm->version_ind_sent) {
+        ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG);
+    } else {
+        connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_VERSION_XCHG);
+    }
+
+    return BLE_ERR_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 39d4353..e309396 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -96,6 +96,7 @@ void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
                                     uint8_t reason);
 
 int ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf);
+int ble_ll_conn_hci_rd_rem_ver_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);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 493b056..0d84b8d 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -302,7 +302,7 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
             ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_FEATURE);
         } else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) {
             /* XXX: should only get this if a slave initiated this */
-            ble_ll_hci_ev_read_rem_used_feat(connsm, BLE_ERR_UNSUPP_FEATURE);
+            ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNSUPP_FEATURE);
         }
     }
 }
@@ -376,6 +376,18 @@ ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
     htole16(dptr + 21, invalid_offset);
 }
 
+static void
+ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
+{
+    /* Set flag to denote we have sent/received this */
+    connsm->version_ind_sent = 1;
+
+    /* Fill out response */
+    pyld[0] = BLE_HCI_VER_BCS_4_2;
+    htole16(pyld + 1, BLE_LL_MFRG_ID);
+    htole16(pyld + 3, BLE_LL_SUB_VERS_NR);
+}
+
 /**
  * Called to make a connection update request LL control PDU
  *  
@@ -539,6 +551,17 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
     return rsp_opcode;
 }
 
+/**
+ * 
+ * 
+ * Context: Link Layer task 
+ *  
+ * @param connsm 
+ * @param dptr 
+ * @param rspbuf 
+ * 
+ * @return int 
+ */
 static int
 ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
                               uint8_t *rspbuf)
@@ -575,15 +598,9 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
      * 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 (IS_PENDING_CTRL_PROC(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_ctrl_proc_stop(connsm, 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 */
@@ -622,7 +639,7 @@ ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
     }
 
     /* 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)) {
+    if (!IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
         return BLE_ERR_MAX;
     }
 
@@ -633,6 +650,43 @@ ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
 }
 
 /**
+ * Called to process the LL control PDU VERSION_IND
+ *  
+ * Context: Link Layer task 
+ * 
+ * @param connsm 
+ * @param dptr 
+ * @param rspbuf 
+ * 
+ * @return int 
+ */
+static int
+ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, 
+                           uint8_t *rspbuf)
+{
+    uint8_t rsp_opcode;
+
+    /* Process the packet */
+    connsm->vers_nr = dptr[0];
+    connsm->comp_id = le16toh(dptr + 1);
+    connsm->sub_vers_nr = le16toh(dptr + 3);
+    connsm->rxd_version_ind = 1;
+
+    rsp_opcode = BLE_ERR_MAX;
+    if (!connsm->version_ind_sent) {
+        rsp_opcode = BLE_LL_CTRL_VERSION_IND;
+        ble_ll_ctrl_version_ind_make(connsm, rspbuf);
+    }
+
+    /* Stop the control procedure */
+    if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) {
+        ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS);
+        ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG);
+    }
+    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. 
@@ -671,9 +725,9 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
         dptr = om->om_data;
 
         switch (ctrl_proc) {
-        case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
-            opcode = BLE_LL_CTRL_LENGTH_REQ;
-            ble_ll_ctrl_datalen_upd_make(connsm, dptr);
+        case BLE_LL_CTRL_PROC_CONN_UPDATE:
+            opcode = BLE_LL_CTRL_CONN_UPDATE_REQ;
+            ble_ll_ctrl_conn_upd_make(connsm, dptr + 1);
             break;
         case BLE_LL_CTRL_PROC_FEATURE_XCHG:
             if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
@@ -683,6 +737,10 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
             }
             dptr[1] = ble_ll_read_supp_features();
             break;
+        case BLE_LL_CTRL_PROC_VERSION_XCHG:
+            opcode = BLE_LL_CTRL_VERSION_IND;
+            ble_ll_ctrl_version_ind_make(connsm, dptr + 1);
+            break;
         case BLE_LL_CTRL_PROC_TERMINATE:
             opcode = BLE_LL_CTRL_TERMINATE_IND;
             dptr[1] = connsm->disconnect_reason;
@@ -691,9 +749,9 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
             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);
+        case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
+            opcode = BLE_LL_CTRL_LENGTH_REQ;
+            ble_ll_ctrl_datalen_upd_make(connsm, dptr);
             break;
         default:
             assert(0);
@@ -767,11 +825,11 @@ ble_ll_ctrl_is_reject_ind_ext(uint8_t hdr, uint8_t opcode)
 void
 ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int 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 (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;
+    }
+    CLR_PENDING_CTRL_PROC(connsm, ctrl_proc);
 
     /* If there are others, start them */
     ble_ll_ctrl_chk_proc_start(connsm);
@@ -877,7 +935,18 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
          * so just start from the first one for now.
          */
         for (i = 0; i < BLE_LL_CTRL_PROC_NUM; ++i) {
-            if (IS_PENDING_CTRL_PROC_M(connsm, i)) {
+            if (IS_PENDING_CTRL_PROC(connsm, i)) {
+                /* 
+                 * The version exchange is a special case. If we have already
+                 * received the information dont start it.
+                 */ 
+                if (i == BLE_LL_CTRL_PROC_VERSION_XCHG) {
+                    if (connsm->rxd_version_ind) {
+                        ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS);
+                        CLR_PENDING_CTRL_PROC(connsm, i);
+                    }
+                }
+
                 ble_ll_ctrl_proc_start(connsm, i);
                 break;
             }
@@ -976,8 +1045,8 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
          * 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;
+            IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) {
+            CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
         }
 
         /* Send a response */
@@ -1018,10 +1087,14 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
     case BLE_LL_CTRL_FEATURE_RSP:
         /* Stop the control procedure */
         connsm->common_features = dptr[0];
-        if (IS_PENDING_CTRL_PROC_M(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) {
-            ble_ll_hci_ev_read_rem_used_feat(connsm, BLE_ERR_SUCCESS);
+        if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) {
+            ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
+            ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
         }
-        ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
+        break;
+
+    case BLE_LL_CTRL_VERSION_IND:
+        rsp_opcode = ble_ll_ctrl_rx_version_ind(connsm, dptr, rspbuf + 1);
         break;
 
     case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
@@ -1040,7 +1113,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
     case BLE_LL_CTRL_START_ENC_REQ:
     case BLE_LL_CTRL_PAUSE_ENC_REQ:
     case BLE_LL_CTRL_PING_REQ:
-    case BLE_LL_CTRL_VERSION_IND:
         /* Construct unknown pdu */
         rspbuf[1] = opcode;
         rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/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 f09f958..3fb1127 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -106,7 +106,7 @@ ble_ll_hci_rd_local_version(uint8_t *rspbuf, uint8_t *rsplen)
 
     hci_rev = 0;
     lmp_subver = 0;
-    mfrg = 0xFFFF;  /* XXXX: to be replaced by actual MFRG */
+    mfrg = BLE_LL_MFRG_ID;
 
     /* Place the data packet length and number of packets in the buffer */
     rspbuf[0] = BLE_HCI_VER_BCS_4_2;
@@ -429,6 +429,15 @@ ble_ll_hci_link_ctrl_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, uint8_t *rsplen)
         /* Send command status instead of command complete */
         rc += (BLE_ERR_MAX + 1);
         break;
+
+    case BLE_HCI_OCF_RD_REM_VER_INFO:
+        if (len == sizeof(uint16_t)) {
+            rc = ble_ll_conn_hci_rd_rem_ver_cmd(cmdbuf);
+        }
+        /* Send command status instead of command complete */
+        rc += (BLE_ERR_MAX + 1);
+        break;
+
     default:
         rc = BLE_ERR_UNKNOWN_HCI_CMD;
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/net/nimble/controller/src/ble_ll_hci_ev.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c
index fa77a3f..7bebc5f 100644
--- a/net/nimble/controller/src/ble_ll_hci_ev.c
+++ b/net/nimble/controller/src/ble_ll_hci_ev.c
@@ -106,11 +106,11 @@ ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status)
 }
 
 void
-ble_ll_hci_ev_read_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
+ble_ll_hci_ev_rd_rem_used_feat(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_UPD_COMPLETE)) {
+    if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) {
         evbuf = os_memblock_get(&g_hci_cmd_pool);
         if (evbuf) {
             evbuf[0] = BLE_HCI_EVCODE_LE_META;
@@ -126,3 +126,23 @@ ble_ll_hci_ev_read_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
         }
     }
 }
+
+void
+ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status)
+{
+    uint8_t *evbuf;
+
+    if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) {
+        evbuf = os_memblock_get(&g_hci_cmd_pool);
+        if (evbuf) {
+            evbuf[0] = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP;
+            evbuf[1] = BLE_HCI_EVENT_RD_RM_VER_LEN;
+            evbuf[2] = status;
+            htole16(evbuf + 3, connsm->conn_handle);
+            evbuf[5] = connsm->vers_nr;
+            htole16(evbuf + 6, connsm->comp_id);
+            htole16(evbuf + 8, connsm->sub_vers_nr);
+            ble_ll_hci_event_send(evbuf);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index 1c13b20..3a18423 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -26,6 +26,7 @@ int host_hci_event_rx(uint8_t *data);
 int host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata);
 int host_hci_cmd_set_event_mask(uint64_t event_mask);
 int host_hci_cmd_disconnect(uint16_t handle, uint8_t reason);
+int host_hci_cmd_rd_rem_version(uint16_t handle);
 int host_hci_cmd_rd_local_version(void);
 int host_hci_cmd_le_set_scan_rsp_data(uint8_t *data, uint8_t len);
 int host_hci_cmd_le_set_adv_data(uint8_t *data, uint8_t len);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/net/nimble/host/src/host_dbg.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/host_dbg.c
index abe1776..9352eb5 100644
--- a/net/nimble/host/src/host_dbg.c
+++ b/net/nimble/host/src/host_dbg.c
@@ -153,6 +153,21 @@ host_hci_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len)
 }
 
 /**
+ * Display a version information event 
+ * 
+ * @param evdata 
+ * @param len 
+ */
+static void
+host_hci_dbg_rd_rem_ver_disp(uint8_t *evdata, uint8_t len)
+{
+    console_printf("Remote Version Info: status=%u handle=%u vers_nr=%u "
+                   "compid=%u subver=%u\n",
+                   evdata[0], le16toh(evdata + 1), evdata[3],
+                   le16toh(evdata + 4), le16toh(evdata + 6));
+}
+
+/**
  * Display the number of completed packets event
  * 
  * @param evdata 
@@ -262,6 +277,9 @@ host_hci_dbg_event_disp(uint8_t *evbuf)
     case BLE_HCI_EVCODE_DISCONN_CMP:
         host_hci_dbg_disconn_comp_disp(evdata, len);
         break;
+    case BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP:
+        host_hci_dbg_rd_rem_ver_disp(evdata, len);
+        break;
     case BLE_HCI_EVCODE_COMMAND_COMPLETE:
         host_hci_dbg_cmd_complete_disp(evdata, len);
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c
index 7fe3f0e..99b5660 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -261,6 +261,18 @@ host_hci_cmd_disconnect(uint16_t handle, uint8_t reason)
 }
 
 int
+host_hci_cmd_rd_rem_version(uint16_t handle)
+{
+    int rc;
+    uint8_t cmd[sizeof(uint16_t)];
+
+    htole16(cmd, handle);
+    rc = host_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL,
+                           BLE_HCI_OCF_RD_REM_VER_INFO, sizeof(uint16_t), cmd);
+    return rc;
+}
+
+int
 host_hci_cmd_le_set_event_mask(uint64_t event_mask)
 {
     int rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 985ae5f..d322929 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -48,6 +48,7 @@
 
 /* List of OCF for Link Control commands (OGF=0x01) */
 #define BLE_HCI_OCF_DISCONNECT_CMD          (0x0006)
+#define BLE_HCI_OCF_RD_REM_VER_INFO         (0x001D)
 
 /* Command specific definitions */
 /* Disconnect command */
@@ -395,7 +396,7 @@
 
 /* Event specific definitions */
 /* Event disconnect complete */
-#define BLE_HCI_EVENT_DISCONN_COMPLETE_LEN  (6)
+#define BLE_HCI_EVENT_DISCONN_COMPLETE_LEN  (4)
 
 /* Event command complete */
 #define BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN  (5)
@@ -408,6 +409,9 @@
 #define BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN (1)
 #define BLE_HCI_EVENT_NUM_COMP_PKTS_ENT_LEN (4)
 
+/* Read remote version informaton */
+#define BLE_HCI_EVENT_RD_RM_VER_LEN         (8)
+
 /* Advertising report */
 #define BLE_HCI_ADV_RPT_EVTYPE_ADV_IND      (0)
 #define BLE_HCI_ADV_RPT_EVTYPE_DIR_IND      (1)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9263db57/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index 9a03295..4658e06 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -66,6 +66,7 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
 #define BLETEST_ROLE_ADVERTISER         (0)
 #define BLETEST_ROLE_SCANNER            (1)
 #define BLETEST_ROLE_INITIATOR          (2)
+//#define BLETEST_CFG_ROLE                (BLETEST_ROLE_INITIATOR)
 #define BLETEST_CFG_ROLE                (BLETEST_ROLE_ADVERTISER)
 #define BLETEST_CFG_FILT_DUP_ADV        (0)
 #define BLETEST_CFG_ADV_ITVL            (60000 / BLE_HCI_ADV_ITVL)
@@ -340,6 +341,11 @@ bletest_execute(void)
             /* Set next os time to start the connection update */
             g_next_os_time = 0;
 
+            /* Ask for version information */
+            rc = host_hci_cmd_rd_rem_version(handle);
+            assert(rc == 0);
+            host_hci_outstanding_opcode = 0;
+
             /* Scanning better be stopped! */
             assert(ble_ll_scan_enabled() == 0);
 
@@ -494,6 +500,11 @@ bletest_execute(void)
             host_hci_outstanding_opcode = 0;
             assert(rc == 0);
 
+            /* Send the remote used features command */
+            rc = host_hci_cmd_rd_rem_version(handle);
+            host_hci_outstanding_opcode = 0;
+            assert(rc == 0);
+
             /* Add to current connections */
             ++g_bletest_current_conns;