You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/01/14 00:24:30 UTC

[3/3] incubator-mynewt-larva git commit: GAP Auto Connection Establishment procedure.

GAP Auto Connection Establishment procedure.


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

Branch: refs/heads/master
Commit: ca671d23694e97280816b1c97acdeabb20387cfb
Parents: b2fde97
Author: Christopher Collins <cc...@gmail.com>
Authored: Tue Jan 12 19:20:25 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Wed Jan 13 15:24:08 2016 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_gap.h        |   7 +
 net/nimble/host/include/host/ble_hs_test.h    |   1 +
 net/nimble/host/src/ble_gap_conn.c            | 290 +++++++++++++++++++--
 net/nimble/host/src/test/ble_gap_test.c       | 284 ++++++++++++++++++++
 net/nimble/host/src/test/ble_gatt_read_test.c |  10 +-
 net/nimble/host/src/test/ble_hs_test.c        |   1 +
 net/nimble/host/src/test/ble_hs_test_util.c   |  20 ++
 net/nimble/host/src/test/ble_hs_test_util.h   |   2 +
 8 files changed, 582 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/include/host/ble_gap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h
index 589f049..54f34d0 100644
--- a/net/nimble/host/include/host/ble_gap.h
+++ b/net/nimble/host/include/host/ble_gap.h
@@ -77,11 +77,18 @@ typedef void ble_gap_connect_fn(struct ble_gap_conn_event *event, void *arg);
 #define BLE_GAP_DISC_MODE_LTD               2
 #define BLE_GAP_DISC_MODE_GEN               3
 
+struct ble_gap_white_entry {
+    uint8_t addr_type;
+    uint8_t addr[6];
+};
+
 void ble_gap_conn_set_cb(ble_gap_connect_fn *cb, void *arg);
 int ble_gap_conn_advertise(uint8_t discoverable_mode, uint8_t connectable_mode,
                            uint8_t *peer_addr, uint8_t peer_addr_type);
 int ble_gap_conn_set_adv_fields(struct ble_hs_adv_fields *adv_fields);
 int ble_gap_conn_disc(uint32_t duration_ms, uint8_t discovery_mode);
+int ble_gap_conn_auto_connect(struct ble_gap_white_entry *white_list,
+                              int white_list_count);
 int ble_gap_conn_direct_connect(int addr_type, uint8_t *addr);
 int ble_gap_conn_terminate(uint16_t handle);
 int ble_gap_conn_cancel(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/include/host/ble_hs_test.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_hs_test.h b/net/nimble/host/include/host/ble_hs_test.h
index 39de412..746087f 100644
--- a/net/nimble/host/include/host/ble_hs_test.h
+++ b/net/nimble/host/include/host/ble_hs_test.h
@@ -40,5 +40,6 @@ int ble_hs_adv_test_all(void);
 int ble_gatts_reg_test_all(void);
 int ble_gatts_notify_test_all(void);
 int ble_gatt_find_s_test_all(void);
+int ble_gap_test_all(void);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/ble_gap_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_conn.c b/net/nimble/host/src/ble_gap_conn.c
index e853b5d..5ef9c29 100644
--- a/net/nimble/host/src/ble_gap_conn.c
+++ b/net/nimble/host/src/ble_gap_conn.c
@@ -28,6 +28,11 @@
 #include "ble_gatt_priv.h"
 #include "ble_gap_conn.h"
 
+#define BLE_GAP_CONN_M_PROC_NULL                            0
+#define BLE_GAP_CONN_M_PROC_DISC                            1
+#define BLE_GAP_CONN_M_PROC_CONN_AUTO                       2
+#define BLE_GAP_CONN_M_PROC_CONN_DIR                        3
+
 #define BLE_GAP_CONN_STATE_IDLE                             UINT8_MAX
 
 /** General discovery master states. */
@@ -36,9 +41,15 @@
 #define BLE_GAP_CONN_M_STATE_DISC_ACKED                     2
 
 /** General discovery master states. */
-#define BLE_GAP_CONN_M_STATE_DIRECT_PENDING                 3
-#define BLE_GAP_CONN_M_STATE_DIRECT_UNACKED                 4
-#define BLE_GAP_CONN_M_STATE_DIRECT_ACKED                   5
+#define BLE_GAP_CONN_M_STATE_AUTO_CLEAR_WL                  3
+#define BLE_GAP_CONN_M_STATE_AUTO_ADD_WL                    4
+#define BLE_GAP_CONN_M_STATE_AUTO_CREATE                    5
+#define BLE_GAP_CONN_M_STATE_AUTO_ACKED                     6
+
+/** General discovery master states. */
+#define BLE_GAP_CONN_M_STATE_DIRECT_PENDING                 7
+#define BLE_GAP_CONN_M_STATE_DIRECT_UNACKED                 8
+#define BLE_GAP_CONN_M_STATE_DIRECT_ACKED                   9
 
 /** Undirected slave states. */
 #define BLE_GAP_CONN_S_STATE_UND_PARAMS                     0
@@ -81,8 +92,8 @@
 /** 10.24 seconds. */
 #define BLE_GAP_GEN_DISC_SCAN_MIN           (10.24 * 1000)
 
-#define BLE_GAP_CONN_MODE_MAX                        4
-#define BLE_GAP_DISC_MODE_MAX                        4
+#define BLE_GAP_CONN_MODE_MAX               4
+#define BLE_GAP_DISC_MODE_MAX               4
 
 /**
  * The maximum amount of user data that can be put into the advertising data.
@@ -96,6 +107,7 @@ static int ble_gap_conn_adv_power_tx(void *arg);
 static int ble_gap_conn_adv_data_tx(void *arg);
 static int ble_gap_conn_adv_rsp_data_tx(void *arg);
 static int ble_gap_conn_adv_enable_tx(void *arg);
+static int ble_gap_conn_auto_tx_add_wl(void *arg);
 
 static ble_hci_sched_tx_fn * const
     ble_gap_conn_slave_dispatch[BLE_GAP_CONN_S_STATE_MAX] = {
@@ -111,6 +123,7 @@ static ble_hci_sched_tx_fn * const
 
 static uint8_t ble_gap_conn_s_conn_mode;
 static uint8_t ble_gap_conn_s_disc_mode;
+static uint8_t ble_gap_conn_m_proc;
 static uint8_t ble_gap_conn_m_disc_mode;
 
 static struct hci_adv_params ble_gap_conn_adv_params;
@@ -126,12 +139,13 @@ static uint8_t ble_gap_conn_master_addr[BLE_DEV_ADDR_LEN];
 static uint8_t ble_gap_conn_slave_addr[BLE_DEV_ADDR_LEN];
 static uint8_t ble_gap_conn_adv_data_len;
 static uint8_t ble_gap_conn_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
+static struct ble_gap_white_entry *ble_gap_conn_white_list;
+static int ble_gap_conn_white_list_count;
+static int ble_gap_conn_white_list_cur;
 static int8_t ble_gap_conn_tx_pwr_lvl;
 static struct os_callout_func ble_gap_conn_master_timer;
 static struct os_callout_func ble_gap_conn_slave_timer;
 
-/* XXX: Need to clear slave mode when we join a master. */
-
 /*****************************************************************************
  * $misc                                                                     *
  *****************************************************************************/
@@ -214,6 +228,8 @@ static void
 ble_gap_conn_master_reset_state(void)
 {
     ble_gap_conn_master_state = BLE_GAP_CONN_STATE_IDLE;
+    ble_gap_conn_m_proc = BLE_GAP_CONN_M_PROC_NULL;
+    ble_gap_conn_m_disc_mode = BLE_GAP_DISC_MODE_NULL;
 }
 
 static void
@@ -234,23 +250,21 @@ ble_gap_conn_master_failed(int status)
 {
     struct ble_gap_conn_event event;
 
-    uint8_t old_state;
+    uint8_t old_proc;
 
     os_callout_stop(&ble_gap_conn_master_timer.cf_c);
 
-    old_state = ble_gap_conn_master_state;
+    old_proc = ble_gap_conn_m_proc;
     ble_gap_conn_master_reset_state();
 
-    switch (old_state) {
-    case BLE_GAP_CONN_M_STATE_DISC_PARAMS:
-    case BLE_GAP_CONN_M_STATE_DISC_ACKED:
+    switch (old_proc) {
+    case BLE_GAP_CONN_M_PROC_DISC:
         event.type = BLE_GAP_CONN_EVENT_TYPE_SCAN_DONE;
         ble_gap_conn_call_cb(&event);
         break;
 
-    case BLE_GAP_CONN_M_STATE_DIRECT_PENDING:
-    case BLE_GAP_CONN_M_STATE_DIRECT_UNACKED:
-    case BLE_GAP_CONN_M_STATE_DIRECT_ACKED:
+    case BLE_GAP_CONN_M_PROC_CONN_AUTO:
+    case BLE_GAP_CONN_M_PROC_CONN_DIR:
         ble_gap_conn_notify_connect(status, NULL);
         break;
 
@@ -299,7 +313,7 @@ ble_gap_conn_rx_disconn_complete(struct hci_disconn_complete *evt)
 int
 ble_gap_conn_master_in_progress(void)
 {
-    return ble_gap_conn_master_state != BLE_GAP_CONN_STATE_IDLE;
+    return ble_gap_conn_m_proc != BLE_GAP_CONN_M_PROC_NULL;
 }
 
 /**
@@ -311,6 +325,25 @@ ble_gap_conn_slave_in_progress(void)
     return ble_gap_conn_slave_state != BLE_GAP_CONN_STATE_IDLE;
 }
 
+static int
+ble_gap_conn_master_enqueue(int state, int in_progress,
+                            ble_hci_sched_tx_fn *hci_tx_cb, void *cb_arg)
+{
+    int rc;
+
+    ble_gap_conn_master_state = state;
+    rc = ble_hci_sched_enqueue(hci_tx_cb, cb_arg);
+    if (rc != 0) {
+        if (in_progress) {
+            ble_gap_conn_master_failed(rc);
+        } else {
+            ble_gap_conn_master_reset_state();
+        }
+    }
+
+    return rc;
+}
+
 /**
  * Attempts to complete the master connection process in response to a
  * "connection complete" event from the controller.  If the master connection
@@ -330,6 +363,8 @@ ble_gap_conn_slave_in_progress(void)
 static int
 ble_gap_conn_accept_master_conn(uint8_t addr_type, uint8_t *addr)
 {
+    int i;
+
     switch (ble_gap_conn_master_state) {
     case BLE_GAP_CONN_M_STATE_DIRECT_ACKED:
         /* XXX: Check address type. */
@@ -338,6 +373,27 @@ ble_gap_conn_accept_master_conn(uint8_t addr_type, uint8_t *addr)
             ble_gap_conn_master_reset_state();
             return 0;
         }
+
+    case BLE_GAP_CONN_M_STATE_AUTO_ACKED:
+        for (i = 0; i < ble_gap_conn_white_list_count; i++) {
+            if (addr_type == ble_gap_conn_white_list[i].addr_type &&
+                memcmp(addr, ble_gap_conn_white_list[i].addr,
+                       BLE_DEV_ADDR_LEN) == 0) {
+
+                break;
+            }
+        }
+        if (i == ble_gap_conn_white_list_count) {
+            ble_gap_conn_master_failed(BLE_HS_ECONTROLLER);
+            return BLE_HS_ECONTROLLER;
+        } else {
+            os_callout_stop(&ble_gap_conn_master_timer.cf_c);
+            ble_gap_conn_master_reset_state();
+            return 0;
+        }
+
+    default:
+        break;
     }
 
     return BLE_HS_ENOENT;
@@ -464,7 +520,7 @@ ble_gap_conn_rx_conn_complete(struct hci_le_conn_complete *evt)
         if (rc == 0) {
             ble_gap_conn_master_reset_state();
         } else {
-            return BLE_HS_ENOENT;
+            return rc;
         }
         break;
 
@@ -474,7 +530,7 @@ ble_gap_conn_rx_conn_complete(struct hci_le_conn_complete *evt)
         if (rc == 0) {
             ble_gap_conn_slave_reset_state();
         } else {
-            return BLE_HS_ENOENT;
+            return rc;
         }
         break;
 
@@ -833,8 +889,8 @@ ble_gap_conn_adv_initiate(void)
  *                                  modes, specify 0.  For directed connectable
  *                                  mode, this should be one of the following
  *                                  constants:
- *                                  o BLE_HCI_ADV_PEER_ADDR_PUBLIC
- *                                  o BLE_HCI_ADV_PEER_ADDR_RANDOM
+ *                                      o BLE_HCI_ADV_PEER_ADDR_PUBLIC
+ *                                      o BLE_HCI_ADV_PEER_ADDR_RANDOM
  *
  * @return                      0 on success; nonzero on failure.
  */
@@ -903,7 +959,7 @@ ble_gap_conn_set_adv_fields(struct ble_hs_adv_fields *adv_fields)
 }
 
 /*****************************************************************************
- * $general discovery procedure                                              *
+ * $discovery procedures                                                     *
  *****************************************************************************/
 
 static void
@@ -1002,14 +1058,13 @@ ble_gap_conn_disc(uint32_t duration_ms, uint8_t discovery_mode)
         duration_ms = BLE_GAP_GEN_DISC_SCAN_MIN;
     }
 
-    ble_gap_conn_master_state = BLE_GAP_CONN_M_STATE_DISC_PARAMS;
     memset(ble_gap_conn_master_addr, 0, BLE_DEV_ADDR_LEN);
 
     ble_gap_conn_m_disc_mode = discovery_mode;
-
-    rc = ble_hci_sched_enqueue(ble_gap_conn_disc_tx_params, NULL);
+    ble_gap_conn_m_proc = BLE_GAP_CONN_M_PROC_DISC;
+    rc = ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_DISC_PARAMS, 0,
+                                     ble_gap_conn_disc_tx_params, NULL);
     if (rc != 0) {
-        ble_gap_conn_master_reset_state();
         return rc;
     }
 
@@ -1020,6 +1075,183 @@ ble_gap_conn_disc(uint32_t duration_ms, uint8_t discovery_mode)
 }
 
 /*****************************************************************************
+ * $auto connection establishment procedure                                  *
+ *****************************************************************************/
+
+/**
+ * Processes an HCI acknowledgement (either command status or command complete)
+ * while a master connection is being established.
+ */
+static void
+ble_gap_conn_auto_ack_create(struct ble_hci_ack *ack, void *arg)
+{
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_CREATE);
+
+    if (ack->bha_status != 0) {
+        ble_gap_conn_master_failed(ack->bha_status);
+        return;
+    }
+
+    ble_gap_conn_master_state = BLE_GAP_CONN_M_STATE_AUTO_ACKED;
+}
+
+static int
+ble_gap_conn_auto_tx_create(void *arg)
+{
+    struct hci_create_conn hcc;
+    int rc;
+
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_CREATE);
+
+    hcc.scan_itvl = 0x0010;
+    hcc.scan_window = 0x0010;
+    hcc.filter_policy = BLE_HCI_CONN_FILT_NO_WL;
+    hcc.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC;
+    memcpy(hcc.peer_addr, ble_gap_conn_master_addr, sizeof hcc.peer_addr);
+    hcc.own_addr_type = BLE_HCI_ADV_OWN_ADDR_PUBLIC;
+    hcc.conn_itvl_min = 24;
+    hcc.conn_itvl_max = 40;
+    hcc.conn_latency = 0;
+    hcc.supervision_timeout = 0x0100; // XXX
+    hcc.min_ce_len = 0x0010; // XXX
+    hcc.max_ce_len = 0x0300; // XXX
+
+    ble_hci_ack_set_callback(ble_gap_conn_auto_ack_create, NULL);
+
+    rc = host_hci_cmd_le_create_connection(&hcc);
+    if (rc != 0) {
+        ble_gap_conn_master_failed(rc);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+ble_gap_conn_auto_ack_add_wl(struct ble_hci_ack *ack, void *arg)
+{
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_ADD_WL);
+
+    if (ack->bha_status != 0) {
+        ble_gap_conn_master_failed(ack->bha_status);
+        return;
+    }
+
+    ble_gap_conn_white_list_cur++;
+    if (ble_gap_conn_white_list_cur < ble_gap_conn_white_list_count) {
+        ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_AUTO_ADD_WL, 1,
+                                    ble_gap_conn_auto_tx_add_wl, NULL);
+    } else {
+        ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_AUTO_CREATE, 1,
+                                    ble_gap_conn_auto_tx_create, NULL);
+    }
+}
+
+static int
+ble_gap_conn_auto_tx_add_wl(void *arg)
+{
+    struct ble_gap_white_entry *white_entry;
+    int rc;
+
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_ADD_WL);
+    assert(ble_gap_conn_white_list != NULL);
+    assert(ble_gap_conn_white_list_cur < ble_gap_conn_white_list_count);
+
+    ble_hci_ack_set_callback(ble_gap_conn_auto_ack_add_wl, NULL);
+
+    white_entry = ble_gap_conn_white_list + ble_gap_conn_white_list_cur;
+    rc = host_hci_cmd_le_add_to_whitelist(white_entry->addr,
+                                          white_entry->addr_type);
+    if (rc != 0) {
+        ble_gap_conn_master_failed(rc);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+ble_gap_conn_auto_ack_clear_wl(struct ble_hci_ack *ack, void *arg)
+{
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_CLEAR_WL);
+
+    if (ack->bha_status != 0) {
+        ble_gap_conn_master_failed(ack->bha_status);
+        return;
+    }
+
+    ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_AUTO_ADD_WL, 1,
+                                ble_gap_conn_auto_tx_add_wl, NULL);
+}
+
+static int
+ble_gap_conn_auto_tx_clear_wl(void *arg)
+{
+    int rc;
+
+    assert(ble_gap_conn_master_state == BLE_GAP_CONN_M_STATE_AUTO_CLEAR_WL);
+
+    ble_hci_ack_set_callback(ble_gap_conn_auto_ack_clear_wl, NULL);
+
+    rc = host_hci_cmd_le_clear_whitelist();
+    if (rc != 0) {
+        ble_gap_conn_master_failed(rc);
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Performs the Auto Connection Establishment Procedure, as described in
+ * vol. 3, part C, section 9.3.5.
+ *
+ * @param addr_type             The peer's address type; one of:
+ *                                  o BLE_HCI_ADV_PEER_ADDR_PUBLIC
+ *                                  o BLE_HCI_ADV_PEER_ADDR_RANDOM
+ *                                  o BLE_HCI_ADV_PEER_ADDR_PUBLIC_IDENT
+ *                                  o BLE_HCI_ADV_PEER_ADDR_RANDOM_IDENT
+ * @param addr                  The address of the peer to connect to.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+ble_gap_conn_auto_connect(struct ble_gap_white_entry *white_list,
+                          int white_list_count)
+{
+    int rc;
+    int i;
+
+    /* Make sure no master connection attempt is already in progress. */
+    if (ble_gap_conn_master_in_progress()) {
+        return BLE_HS_EALREADY;
+    }
+
+    if (white_list_count <= 0) {
+        return BLE_HS_EINVAL;
+    }
+
+    /* XXX: Verify white list not too large. */
+
+    for (i = 0; i < white_list_count; i++) {
+        if (white_list[i].addr_type != BLE_ADDR_TYPE_PUBLIC &&
+            white_list[i].addr_type != BLE_ADDR_TYPE_RANDOM) {
+
+            return BLE_HS_EINVAL;
+        }
+    }
+
+    ble_gap_conn_white_list = white_list;
+    ble_gap_conn_white_list_count = white_list_count;
+    ble_gap_conn_white_list_cur = 0;
+
+    ble_gap_conn_m_proc = BLE_GAP_CONN_M_PROC_CONN_AUTO;
+    rc = ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_AUTO_CLEAR_WL, 0,
+                                     ble_gap_conn_auto_tx_clear_wl, NULL);
+    return rc;
+}
+
+/*****************************************************************************
  * $direct connection establishment procedure                                *
  *****************************************************************************/
 
@@ -1097,13 +1329,13 @@ ble_gap_conn_direct_connect(int addr_type, uint8_t *addr)
         return BLE_HS_EALREADY;
     }
 
-    ble_gap_conn_master_state = BLE_GAP_CONN_M_STATE_DIRECT_PENDING;
     ble_gap_conn_master_addr_type = addr_type;
     memcpy(ble_gap_conn_master_addr, addr, BLE_DEV_ADDR_LEN);
 
-    rc = ble_hci_sched_enqueue(ble_gap_conn_direct_connect_tx, NULL);
+    ble_gap_conn_m_proc = BLE_GAP_CONN_M_PROC_CONN_DIR;
+    rc = ble_gap_conn_master_enqueue(BLE_GAP_CONN_M_STATE_DIRECT_PENDING, 0,
+                                     ble_gap_conn_direct_connect_tx, NULL);
     if (rc != 0) {
-        ble_gap_conn_master_reset_state();
         return rc;
     }
 
@@ -1231,6 +1463,8 @@ ble_gap_conn_init(void)
     ble_gap_conn_cb = NULL;
     ble_gap_conn_s_conn_mode = BLE_GAP_CONN_MODE_NULL;
     ble_gap_conn_s_disc_mode = BLE_GAP_DISC_MODE_NULL;
+    ble_gap_conn_m_proc = BLE_GAP_CONN_M_PROC_NULL;
+    ble_gap_conn_m_disc_mode = BLE_GAP_DISC_MODE_NULL;
     ble_gap_conn_master_state = BLE_GAP_CONN_STATE_IDLE;
     ble_gap_conn_slave_state = BLE_GAP_CONN_STATE_IDLE;
     memset(ble_gap_conn_master_addr, 0, sizeof ble_gap_conn_master_addr);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/test/ble_gap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gap_test.c b/net/nimble/host/src/test/ble_gap_test.c
new file mode 100644
index 0000000..4d34d47
--- /dev/null
+++ b/net/nimble/host/src/test/ble_gap_test.c
@@ -0,0 +1,284 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "testutil/testutil.h"
+#include "nimble/ble.h"
+#include "nimble/hci_common.h"
+#include "ble_hs_priv.h"
+#include "host/ble_hs_test.h"
+#include "ble_hs_conn.h"
+#include "ble_hci_sched.h"
+#include "ble_gatt_priv.h"
+#include "ble_gap_conn.h"
+#include "ble_hs_test_util.h"
+
+struct ble_gap_conn_event ble_gap_test_conn_event;
+
+static void
+ble_gap_test_misc_connect_cb(struct ble_gap_conn_event *event, void *arg)
+{
+    ble_gap_test_conn_event = *event;
+}
+
+static void
+ble_gap_test_misc_init(void)
+{
+    ble_hs_test_util_init();
+    ble_gap_conn_set_cb(ble_gap_test_misc_connect_cb, NULL);
+}
+
+static void
+ble_gap_test_misc_verify_tx_clear_wl(void)
+{
+    uint8_t param_len;
+
+    TEST_ASSERT_FATAL(ble_hs_test_util_prev_hci_tx != NULL);
+
+    ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE,
+                                   BLE_HCI_OCF_LE_CLEAR_WHITE_LIST,
+                                   &param_len);
+    TEST_ASSERT(param_len == 0);
+}
+
+static void
+ble_gap_test_misc_verify_tx_add_wl(struct ble_gap_white_entry *entry)
+{
+    uint8_t param_len;
+    uint8_t *param;
+    int i;
+
+    TEST_ASSERT_FATAL(ble_hs_test_util_prev_hci_tx != NULL);
+
+    param = ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE,
+                                           BLE_HCI_OCF_LE_ADD_WHITE_LIST,
+                                           &param_len);
+    TEST_ASSERT(param_len == 7);
+    TEST_ASSERT(param[0] == entry->addr_type);
+    for (i = 0; i < 6; i++) {
+        TEST_ASSERT(param[1 + i] == entry->addr[i]);
+    }
+}
+
+static void
+ble_gap_test_misc_verify_tx_create_conn(void)
+{
+    uint8_t param_len;
+
+    TEST_ASSERT_FATAL(ble_hs_test_util_prev_hci_tx != NULL);
+
+    ble_hs_test_util_verify_tx_hci(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN,
+                                   &param_len);
+    TEST_ASSERT(param_len == BLE_HCI_CREATE_CONN_LEN);
+}
+
+static void
+ble_gap_test_misc_conn_auto_good_once(struct ble_gap_white_entry *white_list,
+                                      int white_list_count, int dev_idx)
+{
+    struct hci_le_conn_complete evt;
+    int rc;
+    int i;
+
+    ble_gap_test_misc_init();
+
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    rc = ble_gap_conn_auto_connect(white_list, white_list_count);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+
+    /* Verify tx of clear white list command. */
+    ble_hci_sched_wakeup();
+    ble_gap_test_misc_verify_tx_clear_wl();
+    ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, 0);
+
+    /* Verify tx of add white list commands. */
+    for (i = 0; i < white_list_count; i++) {
+        ble_hci_sched_wakeup();
+        ble_gap_test_misc_verify_tx_add_wl(white_list + i);
+        ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_ADD_WHITE_LIST, 0);
+    }
+
+    /* Verify tx of create connection command. */
+    ble_hci_sched_wakeup();
+    ble_gap_test_misc_verify_tx_create_conn();
+    ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
+
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+    TEST_ASSERT(ble_hs_conn_find(2) == NULL);
+
+    /* Receive connection complete event. */
+    memset(&evt, 0, sizeof evt);
+    evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
+    evt.status = BLE_ERR_SUCCESS;
+    evt.connection_handle = 2;
+    memcpy(evt.peer_addr, white_list[dev_idx].addr, 6);
+    rc = ble_gap_conn_rx_conn_complete(&evt);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    TEST_ASSERT(ble_gap_test_conn_event.type ==
+                BLE_GAP_CONN_EVENT_TYPE_CONNECT);
+    TEST_ASSERT(ble_gap_test_conn_event.conn.status == 0);
+    TEST_ASSERT(ble_gap_test_conn_event.conn.handle == 2);
+    TEST_ASSERT(memcmp(ble_gap_test_conn_event.conn.peer_addr,
+                       white_list[dev_idx].addr, 6) == 0);
+
+    TEST_ASSERT(ble_hs_conn_find(2) != NULL);
+}
+
+static void
+ble_gap_test_misc_conn_auto_bad_addr(struct ble_gap_white_entry *white_list,
+                                     int white_list_count)
+{
+    struct hci_le_conn_complete evt;
+    int rc;
+    int i;
+
+    ble_gap_test_misc_init();
+
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    rc = ble_gap_conn_auto_connect(white_list, white_list_count);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+
+    /* Verify tx of clear white list command. */
+    ble_hci_sched_wakeup();
+    ble_gap_test_misc_verify_tx_clear_wl();
+    ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_CLEAR_WHITE_LIST, 0);
+
+    /* Verify tx of add white list commands. */
+    for (i = 0; i < white_list_count; i++) {
+        ble_hci_sched_wakeup();
+        ble_gap_test_misc_verify_tx_add_wl(white_list + i);
+        ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_ADD_WHITE_LIST, 0);
+    }
+
+    /* Verify tx of create connection command. */
+    ble_hci_sched_wakeup();
+    ble_gap_test_misc_verify_tx_create_conn();
+    ble_hs_test_util_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
+
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+    TEST_ASSERT(ble_hs_conn_find(2) == NULL);
+
+    /* Receive connection complete event with unknown address. */
+    memset(&evt, 0, sizeof evt);
+    evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
+    evt.status = BLE_ERR_SUCCESS;
+    evt.connection_handle = 2;
+    memcpy(evt.peer_addr, ((uint8_t[]){ 1,1,1,1,1,1 }), 6);
+    rc = ble_gap_conn_rx_conn_complete(&evt);
+    TEST_ASSERT(rc != 0);
+
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    TEST_ASSERT(ble_gap_test_conn_event.type ==
+                BLE_GAP_CONN_EVENT_TYPE_CONNECT);
+    TEST_ASSERT(ble_gap_test_conn_event.conn.status == BLE_HS_ECONTROLLER);
+
+    TEST_ASSERT(ble_hs_conn_find(2) == NULL);
+}
+
+TEST_CASE(ble_gap_test_case_conn_auto_good)
+{
+    struct ble_gap_white_entry white_list[] = { {
+        BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 }
+    }, {
+        BLE_ADDR_TYPE_PUBLIC, { 2, 3, 4, 5, 6, 7 }
+    }, {
+        BLE_ADDR_TYPE_PUBLIC, { 3, 4, 5, 6, 7, 8 }
+    }, {
+        BLE_ADDR_TYPE_PUBLIC, { 4, 5, 6, 7, 8, 9 }
+    } };
+    int white_list_count = sizeof white_list / sizeof white_list[0];
+
+    int i;
+
+    for (i = 0; i < white_list_count; i++) {
+        ble_gap_test_misc_conn_auto_good_once(white_list, white_list_count, i);
+    }
+}
+TEST_CASE(ble_gap_test_case_conn_auto_bad_args)
+{
+    int rc;
+
+    ble_gap_test_misc_init();
+
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    /*** 0 white list entries. */
+    rc = ble_gap_conn_auto_connect(NULL, 0);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    /*** Invalid address type. */
+    rc = ble_gap_conn_auto_connect(
+        ((struct ble_gap_white_entry[]) { {
+            5, { 1, 2, 3, 4, 5, 6 }
+        }, }), 1);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    /*** Connection already in progress. */
+    rc = ble_gap_conn_auto_connect(
+        ((struct ble_gap_white_entry[]) { {
+            BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 }
+        }, }), 1);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+
+    rc = ble_gap_conn_auto_connect(
+        ((struct ble_gap_white_entry[]) { {
+            BLE_ADDR_TYPE_PUBLIC, { 2, 3, 4, 5, 6, 7 }
+        }, }), 1);
+    TEST_ASSERT(rc == BLE_HS_EALREADY);
+}
+
+TEST_CASE(ble_gap_test_case_conn_auto_bad_addr)
+{
+    ble_gap_test_misc_conn_auto_bad_addr(
+        ((struct ble_gap_white_entry[]) { {
+            BLE_ADDR_TYPE_PUBLIC, { 1, 2, 3, 4, 5, 6 }
+        }, {
+            BLE_ADDR_TYPE_PUBLIC, { 2, 3, 4, 5, 6, 7 }
+        }, {
+            BLE_ADDR_TYPE_PUBLIC, { 3, 4, 5, 6, 7, 8 }
+        }, {
+            BLE_ADDR_TYPE_PUBLIC, { 4, 5, 6, 7, 8, 9 }
+        } }), 4);
+}
+
+TEST_SUITE(ble_gap_suite)
+{
+    ble_gap_test_case_conn_auto_good();
+    ble_gap_test_case_conn_auto_bad_args();
+    ble_gap_test_case_conn_auto_bad_addr();
+}
+
+int
+ble_gap_test_all(void)
+{
+    ble_gap_suite();
+
+    return tu_any_failed;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/test/ble_gatt_read_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_read_test.c b/net/nimble/host/src/test/ble_gatt_read_test.c
index 8c0da37..ec4fe91 100644
--- a/net/nimble/host/src/test/ble_gatt_read_test.c
+++ b/net/nimble/host/src/test/ble_gatt_read_test.c
@@ -679,7 +679,7 @@ TEST_CASE(ble_gatt_read_test_by_handle)
     ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { {
         .handle = 0x5432,
         .value = (uint8_t[]){ 0xff },
-        .value_len = 7
+        .value_len = 1
     } });
 
     /* Read a 200-byte attribute. */
@@ -905,14 +905,14 @@ TEST_CASE(ble_gatt_read_test_dsc)
     ble_gatt_read_test_misc_dsc_verify_good((struct ble_gatt_attr[]) { {
         .handle = 43,
         .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
-        .value_len = 7
+        .value_len = 7,
     } });
 
     /* Read a one-byte attribute. */
     ble_gatt_read_test_misc_dsc_verify_good((struct ble_gatt_attr[]) { {
         .handle = 0x5432,
         .value = (uint8_t[]){ 0xff },
-        .value_len = 7
+        .value_len = 1,
     } });
 
     /* Read a 200-byte attribute. */
@@ -927,7 +927,7 @@ TEST_CASE(ble_gatt_read_test_dsc)
         (struct ble_gatt_attr[]) { {
             .handle = 719,
             .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
-            .value_len = 7
+            .value_len = 7,
         } });
 
     /* Fail due to invalid PDU. */
@@ -935,7 +935,7 @@ TEST_CASE(ble_gatt_read_test_dsc)
         (struct ble_gatt_attr[]) { {
             .handle = 65,
             .value = (uint8_t[]){ 0xfa, 0x4c },
-            .value_len = 2
+            .value_len = 2,
         } });
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/test/ble_hs_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test.c b/net/nimble/host/src/test/ble_hs_test.c
index d959f11..0b599cc 100644
--- a/net/nimble/host/src/test/ble_hs_test.c
+++ b/net/nimble/host/src/test/ble_hs_test.c
@@ -66,6 +66,7 @@ main(void)
     ble_gatts_reg_test_all();
     ble_gatts_notify_test_all();
     ble_gatt_find_s_test_all();
+    ble_gap_test_all();
 
     return tu_any_failed;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/test/ble_hs_test_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.c b/net/nimble/host/src/test/ble_hs_test_util.c
index ff7963e..f3c7359 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -80,6 +80,7 @@ ble_hs_test_util_create_conn(uint16_t handle, uint8_t *addr)
     evt.connection_handle = handle;
     memcpy(evt.peer_addr, addr, 6);
     rc = ble_gap_conn_rx_conn_complete(&evt);
+    TEST_ASSERT(rc == 0);
 
     conn = ble_hs_conn_find(handle);
     TEST_ASSERT_FATAL(conn != NULL);
@@ -328,6 +329,25 @@ ble_hs_test_util_rx_dir_adv_acks(void)
     TEST_ASSERT(ble_gap_conn_slave_in_progress());
 }
 
+uint8_t *
+ble_hs_test_util_verify_tx_hci(uint8_t ogf, uint16_t ocf,
+                               uint8_t *out_param_len)
+{
+    uint16_t opcode;
+
+    TEST_ASSERT_FATAL(ble_hs_test_util_prev_hci_tx != NULL);
+
+    opcode = le16toh(ble_hs_test_util_prev_hci_tx);
+    TEST_ASSERT(BLE_HCI_OGF(opcode) == ogf);
+    TEST_ASSERT(BLE_HCI_OCF(opcode) == ocf);
+
+    if (out_param_len != NULL) {
+        *out_param_len = ble_hs_test_util_prev_hci_tx[2];
+    }
+
+    return ble_hs_test_util_prev_hci_tx + 3;
+}
+
 void
 ble_hs_test_util_tx_all(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/ca671d23/net/nimble/host/src/test/ble_hs_test_util.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.h b/net/nimble/host/src/test/ble_hs_test_util.h
index 2adcc60..c748923 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.h
+++ b/net/nimble/host/src/test/ble_hs_test_util.h
@@ -55,6 +55,8 @@ void ble_hs_test_util_rx_num_completed_pkts_event(
 void ble_hs_test_util_rx_und_adv_acks(void);
 void ble_hs_test_util_rx_und_adv_acks_count(int count);
 void ble_hs_test_util_rx_dir_adv_acks(void);
+uint8_t *ble_hs_test_util_verify_tx_hci(uint8_t ogf, uint16_t ocf,
+                                        uint8_t *out_param_len);
 void ble_hs_test_util_tx_all(void);
 void ble_hs_test_util_init(void);