http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d98ddc1c/net/nimble/host/test/src/ble_gatt_conn_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_gatt_conn_test.c 
b/net/nimble/host/test/src/ble_gatt_conn_test.c
new file mode 100644
index 0000000..be4a46d
--- /dev/null
+++ b/net/nimble/host/test/src/ble_gatt_conn_test.c
@@ -0,0 +1,533 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "host/ble_hs_test.h"
+#include "ble_hs_test_util.h"
+
+#define BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE        0x9383
+#define BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE       0x1234
+
+static uint8_t ble_gatt_conn_test_write_value[] = { 1, 3, 64, 21, 6 };
+
+struct ble_gatt_conn_test_cb_arg {
+    uint16_t exp_conn_handle;
+    int called;
+};
+
+static int
+ble_gatt_conn_test_attr_cb(uint16_t conn_handle, uint16_t attr_handle,
+                           uint8_t op, uint16_t offset, struct os_mbuf **om,
+                           void *arg)
+{
+    uint8_t *buf;
+
+    switch (op) {
+    case BLE_ATT_ACCESS_OP_READ:
+        buf = os_mbuf_extend(*om, 1);
+        TEST_ASSERT_FATAL(buf != NULL);
+        *buf = 1;
+        return 0;
+
+    default:
+        return -1;
+    }
+}
+
+static int
+ble_gatt_conn_test_mtu_cb(uint16_t conn_handle,
+                          const struct ble_gatt_error *error,
+                          uint16_t mtu, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(mtu == 0);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_disc_all_svcs_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    const struct ble_gatt_svc *service,
+                                    void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(service == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_disc_svc_uuid_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    const struct ble_gatt_svc *service,
+                                    void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(service == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_find_inc_svcs_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    const struct ble_gatt_svc *service,
+                                    void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(service == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_disc_all_chrs_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    const struct ble_gatt_chr *chr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(chr == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_disc_chr_uuid_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    const struct ble_gatt_chr *chr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(chr == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_disc_all_dscs_cb(uint16_t conn_handle,
+                                    const struct ble_gatt_error *error,
+                                    uint16_t chr_def_handle,
+                                    const struct ble_gatt_dsc *dsc,
+                                    void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(dsc == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_read_cb(uint16_t conn_handle,
+                           const struct ble_gatt_error *error,
+                           struct ble_gatt_attr *attr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle,
+                                const struct ble_gatt_error *error,
+                                struct ble_gatt_attr *attr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_read_long_cb(uint16_t conn_handle,
+                                const struct ble_gatt_error *error,
+                                struct ble_gatt_attr *attr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+static int
+ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle,
+                                const struct ble_gatt_error *error,
+                                struct ble_gatt_attr *attr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr->om == NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_write_cb(uint16_t conn_handle,
+                            const struct ble_gatt_error *error,
+                            struct ble_gatt_attr *attr,
+                            void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr != NULL);
+    TEST_ASSERT(attr->handle == BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_write_long_cb(uint16_t conn_handle,
+                                 const struct ble_gatt_error *error,
+                                 struct ble_gatt_attr *attr, void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attr != NULL);
+    TEST_ASSERT(attr->handle == BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+static int
+ble_gatt_conn_test_write_rel_cb(uint16_t conn_handle,
+                                const struct ble_gatt_error *error,
+                                struct ble_gatt_attr *attrs,
+                                uint8_t num_attrs,
+                                void *arg)
+{
+    struct ble_gatt_conn_test_cb_arg *cb_arg;
+
+    cb_arg = arg;
+
+    TEST_ASSERT(cb_arg->exp_conn_handle == conn_handle);
+    TEST_ASSERT(!cb_arg->called);
+    TEST_ASSERT_FATAL(error != NULL);
+    TEST_ASSERT(error->status == BLE_HS_ENOTCONN);
+    TEST_ASSERT(attrs != NULL);
+
+    cb_arg->called++;
+
+    return 0;
+}
+
+TEST_CASE(ble_gatt_conn_test_disconnect)
+{
+    struct ble_gatt_conn_test_cb_arg mtu_arg            = { 0 };
+    struct ble_gatt_conn_test_cb_arg disc_all_svcs_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg disc_svc_uuid_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg find_inc_svcs_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg disc_all_chrs_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg disc_chr_uuid_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg disc_all_dscs_arg  = { 0 };
+    struct ble_gatt_conn_test_cb_arg read_arg           = { 0 };
+    struct ble_gatt_conn_test_cb_arg read_uuid_arg      = { 0 };
+    struct ble_gatt_conn_test_cb_arg read_long_arg      = { 0 };
+    struct ble_gatt_conn_test_cb_arg read_mult_arg      = { 0 };
+    struct ble_gatt_conn_test_cb_arg write_arg          = { 0 };
+    struct ble_gatt_conn_test_cb_arg write_long_arg     = { 0 };
+    struct ble_gatt_conn_test_cb_arg write_rel_arg      = { 0 };
+    struct ble_gatt_attr attr;
+    uint16_t attr_handle;
+    int rc;
+
+    ble_hs_test_util_init();
+
+    /*** Register an attribute to allow indicatations to be sent. */
+    rc = ble_att_svr_register(BLE_UUID16(0x1212), BLE_ATT_F_READ,
+                              &attr_handle,
+                              ble_gatt_conn_test_attr_cb, NULL);
+    TEST_ASSERT(rc == 0);
+
+    /* Create three connections. */
+    ble_hs_test_util_create_conn(1, ((uint8_t[]){1,2,3,4,5,6,7,8}),
+                                 NULL, NULL);
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+    ble_hs_test_util_create_conn(3, ((uint8_t[]){3,4,5,6,7,8,9,10}),
+                                 NULL, NULL);
+
+    /*** Schedule some GATT procedures. */
+    /* Connection 1. */
+    mtu_arg.exp_conn_handle = 1;
+    ble_gattc_exchange_mtu(1, ble_gatt_conn_test_mtu_cb, &mtu_arg);
+
+    disc_all_svcs_arg.exp_conn_handle = 1;
+    rc = ble_gattc_disc_all_svcs(1, ble_gatt_conn_test_disc_all_svcs_cb,
+                                 &disc_all_svcs_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    disc_svc_uuid_arg.exp_conn_handle = 1;
+    rc = ble_gattc_disc_svc_by_uuid(1, BLE_UUID16(0x1111),
+                                    ble_gatt_conn_test_disc_svc_uuid_cb,
+                                    &disc_svc_uuid_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    find_inc_svcs_arg.exp_conn_handle = 1;
+    rc = ble_gattc_find_inc_svcs(1, 1, 0xffff,
+                                 ble_gatt_conn_test_find_inc_svcs_cb,
+                                 &find_inc_svcs_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    disc_all_chrs_arg.exp_conn_handle = 1;
+    rc = ble_gattc_disc_all_chrs(1, 1, 0xffff,
+                                 ble_gatt_conn_test_disc_all_chrs_cb,
+                                 &disc_all_chrs_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    /* Connection 2. */
+    disc_all_dscs_arg.exp_conn_handle = 2;
+    rc = ble_gattc_disc_all_dscs(2, 3, 0xffff,
+                                 ble_gatt_conn_test_disc_all_dscs_cb,
+                                 &disc_all_dscs_arg);
+
+    disc_chr_uuid_arg.exp_conn_handle = 2;
+    rc = ble_gattc_disc_chrs_by_uuid(2, 2, 0xffff, BLE_UUID16(0x2222),
+                                     ble_gatt_conn_test_disc_chr_uuid_cb,
+                                     &disc_chr_uuid_arg);
+
+    read_arg.exp_conn_handle = 2;
+    rc = ble_gattc_read(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE,
+                        ble_gatt_conn_test_read_cb, &read_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    read_uuid_arg.exp_conn_handle = 2;
+    rc = ble_gattc_read_by_uuid(2, 1, 0xffff, BLE_UUID16(0x3333),
+                                ble_gatt_conn_test_read_uuid_cb,
+                                &read_uuid_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    read_long_arg.exp_conn_handle = 2;
+    rc = ble_gattc_read_long(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE,
+                             ble_gatt_conn_test_read_long_cb, &read_long_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    /* Connection 3. */
+    read_mult_arg.exp_conn_handle = 3;
+    rc = ble_gattc_read_mult(3, ((uint16_t[3]){5,6,7}), 3,
+                             ble_gatt_conn_test_read_mult_cb, &read_mult_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    write_arg.exp_conn_handle = 3;
+    rc = ble_hs_test_util_gatt_write_flat(
+        3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE,
+        ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value,
+        ble_gatt_conn_test_write_cb, &write_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    write_long_arg.exp_conn_handle = 3;
+    rc = ble_hs_test_util_gatt_write_long_flat(
+        3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE,
+        ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value,
+        ble_gatt_conn_test_write_long_cb, &write_long_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    attr.handle = 8;
+    attr.offset = 0;
+    attr.om = os_msys_get_pkthdr(0, 0);
+    write_rel_arg.exp_conn_handle = 3;
+    rc = ble_gattc_write_reliable(
+        3, &attr, 1, ble_gatt_conn_test_write_rel_cb, &write_rel_arg);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    /*** Start the procedures. */
+    ble_hs_test_util_tx_all();
+
+    /*** Break the connections; verify proper callbacks got called. */
+    /* Connection 1. */
+    ble_gattc_connection_broken(1);
+    TEST_ASSERT(mtu_arg.called == 1);
+    TEST_ASSERT(disc_all_svcs_arg.called == 1);
+    TEST_ASSERT(disc_svc_uuid_arg.called == 1);
+    TEST_ASSERT(find_inc_svcs_arg.called == 1);
+    TEST_ASSERT(disc_all_chrs_arg.called == 1);
+    TEST_ASSERT(disc_chr_uuid_arg.called == 0);
+    TEST_ASSERT(disc_all_dscs_arg.called == 0);
+    TEST_ASSERT(read_arg.called == 0);
+    TEST_ASSERT(read_uuid_arg.called == 0);
+    TEST_ASSERT(read_long_arg.called == 0);
+    TEST_ASSERT(read_mult_arg.called == 0);
+    TEST_ASSERT(write_arg.called == 0);
+    TEST_ASSERT(write_long_arg.called == 0);
+    TEST_ASSERT(write_rel_arg.called == 0);
+
+    /* Connection 2. */
+    ble_gattc_connection_broken(2);
+    TEST_ASSERT(mtu_arg.called == 1);
+    TEST_ASSERT(disc_all_svcs_arg.called == 1);
+    TEST_ASSERT(disc_svc_uuid_arg.called == 1);
+    TEST_ASSERT(find_inc_svcs_arg.called == 1);
+    TEST_ASSERT(disc_all_chrs_arg.called == 1);
+    TEST_ASSERT(disc_chr_uuid_arg.called == 1);
+    TEST_ASSERT(disc_all_dscs_arg.called == 1);
+    TEST_ASSERT(read_arg.called == 1);
+    TEST_ASSERT(read_uuid_arg.called == 1);
+    TEST_ASSERT(read_long_arg.called == 1);
+    TEST_ASSERT(read_mult_arg.called == 0);
+    TEST_ASSERT(write_arg.called == 0);
+    TEST_ASSERT(write_long_arg.called == 0);
+    TEST_ASSERT(write_rel_arg.called == 0);
+
+    /* Connection 3. */
+    ble_gattc_connection_broken(3);
+    TEST_ASSERT(mtu_arg.called == 1);
+    TEST_ASSERT(disc_all_svcs_arg.called == 1);
+    TEST_ASSERT(disc_svc_uuid_arg.called == 1);
+    TEST_ASSERT(find_inc_svcs_arg.called == 1);
+    TEST_ASSERT(disc_all_chrs_arg.called == 1);
+    TEST_ASSERT(disc_chr_uuid_arg.called == 1);
+    TEST_ASSERT(disc_all_dscs_arg.called == 1);
+    TEST_ASSERT(read_arg.called == 1);
+    TEST_ASSERT(read_uuid_arg.called == 1);
+    TEST_ASSERT(read_long_arg.called == 1);
+    TEST_ASSERT(read_mult_arg.called == 1);
+    TEST_ASSERT(write_arg.called == 1);
+    TEST_ASSERT(write_long_arg.called == 1);
+    TEST_ASSERT(write_rel_arg.called == 1);
+}
+
+TEST_SUITE(ble_gatt_break_suite)
+{
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
+    ble_gatt_conn_test_disconnect();
+}
+
+int
+ble_gatt_conn_test_all(void)
+{
+    ble_gatt_break_suite();
+
+    return tu_any_failed;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d98ddc1c/net/nimble/host/test/src/ble_gatt_disc_c_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_gatt_disc_c_test.c 
b/net/nimble/host/test/src/ble_gatt_disc_c_test.c
new file mode 100644
index 0000000..a4eb67b
--- /dev/null
+++ b/net/nimble/host/test/src/ble_gatt_disc_c_test.c
@@ -0,0 +1,547 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <limits.h>
+#include "testutil/testutil.h"
+#include "nimble/ble.h"
+#include "host/ble_hs_test.h"
+#include "host/ble_gatt.h"
+#include "host/ble_uuid.h"
+#include "ble_hs_test_util.h"
+
+struct ble_gatt_disc_c_test_char {
+    uint16_t def_handle;
+    uint16_t val_handle;
+    uint16_t uuid16; /* 0 if not present. */
+    uint8_t properties;
+    uint8_t uuid128[16];
+};
+
+#define BLE_GATT_DISC_C_TEST_MAX_CHARS  256
+static struct ble_gatt_chr
+    ble_gatt_disc_c_test_chars[BLE_GATT_DISC_C_TEST_MAX_CHARS];
+static int ble_gatt_disc_c_test_num_chars;
+static int ble_gatt_disc_c_test_rx_complete;
+
+static void
+ble_gatt_disc_c_test_init(void)
+{
+    ble_hs_test_util_init();
+
+    ble_gatt_disc_c_test_num_chars = 0;
+    ble_gatt_disc_c_test_rx_complete = 0;
+}
+
+static int
+ble_gatt_disc_c_test_misc_rx_rsp_once(
+    uint16_t conn_handle, struct ble_gatt_disc_c_test_char *chars)
+{
+    struct ble_att_read_type_rsp rsp;
+    uint8_t buf[1024];
+    int off;
+    int rc;
+    int i;
+
+    /* Send the pending ATT Read By Type Request. */
+    ble_hs_test_util_tx_all();
+
+    if (chars[0].uuid16 != 0) {
+       rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ +
+                         BLE_GATT_CHR_DECL_SZ_16;
+    } else {
+       rsp.batp_length = BLE_ATT_READ_TYPE_ADATA_BASE_SZ +
+                         BLE_GATT_CHR_DECL_SZ_128;
+    }
+
+    ble_att_read_type_rsp_write(buf, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp);
+
+    off = BLE_ATT_READ_TYPE_RSP_BASE_SZ;
+    for (i = 0; ; i++) {
+        if (chars[i].def_handle == 0) {
+            /* No more services. */
+            break;
+        }
+
+        /* If the value length is changing, we need a separate response. */
+        if (((chars[i].uuid16 == 0) ^ (chars[0].uuid16 == 0)) != 0) {
+            break;
+        }
+
+        htole16(buf + off, chars[i].def_handle);
+        off += 2;
+
+        buf[off] = chars[i].properties;
+        off++;
+
+        htole16(buf + off, chars[i].val_handle);
+        off += 2;
+
+        if (chars[i].uuid16 != 0) {
+            htole16(buf + off, chars[i].uuid16);
+            off += 2;
+        } else {
+            memcpy(buf + off, chars[i].uuid128, 16);
+            off += 16;
+        }
+    }
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle,
+                                 uint16_t end_handle,
+                                 struct ble_gatt_disc_c_test_char *chars)
+{
+    int count;
+    int idx;
+
+    idx = 0;
+    while (chars[idx].def_handle != 0) {
+        count = ble_gatt_disc_c_test_misc_rx_rsp_once(conn_handle,
+                                                      chars + idx);
+        if (count == 0) {
+            break;
+        }
+        idx += count;
+    }
+
+    if (chars[idx - 1].def_handle != end_handle) {
+        /* Send the pending ATT Request. */
+        ble_hs_test_util_tx_all();
+        ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ,
+                                        BLE_ATT_ERR_ATTR_NOT_FOUND,
+                                        chars[idx - 1].def_handle);
+    }
+}
+
+static void
+ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char *chars,
+                                       int stop_after)
+{
+    uint16_t uuid16;
+    int i;
+
+    if (stop_after == 0) {
+        stop_after = INT_MAX;
+    }
+
+    for (i = 0; i < stop_after && chars[i].def_handle != 0; i++) {
+        TEST_ASSERT(chars[i].def_handle ==
+                    ble_gatt_disc_c_test_chars[i].def_handle);
+        TEST_ASSERT(chars[i].val_handle ==
+                    ble_gatt_disc_c_test_chars[i].val_handle);
+        if (chars[i].uuid16 != 0) {
+            uuid16 = ble_uuid_128_to_16(ble_gatt_disc_c_test_chars[i].uuid128);
+            TEST_ASSERT(chars[i].uuid16 == uuid16);
+        } else {
+            TEST_ASSERT(memcmp(chars[i].uuid128,
+                               ble_gatt_disc_c_test_chars[i].uuid128,
+                               16) == 0);
+        }
+    }
+
+    TEST_ASSERT(i == ble_gatt_disc_c_test_num_chars);
+    TEST_ASSERT(ble_gatt_disc_c_test_rx_complete);
+}
+
+static int
+ble_gatt_disc_c_test_misc_cb(uint16_t conn_handle,
+                             const struct ble_gatt_error *error,
+                             const struct ble_gatt_chr *chr, void *arg)
+{
+    struct ble_gatt_chr *dst;
+    int *stop_after;
+
+    TEST_ASSERT(error != NULL);
+    TEST_ASSERT(!ble_gatt_disc_c_test_rx_complete);
+
+    stop_after = arg;
+
+    switch (error->status) {
+    case 0:
+        TEST_ASSERT_FATAL(ble_gatt_disc_c_test_num_chars <
+                          BLE_GATT_DISC_C_TEST_MAX_CHARS);
+
+        dst = ble_gatt_disc_c_test_chars + ble_gatt_disc_c_test_num_chars++;
+        *dst = *chr;
+        break;
+
+    case BLE_HS_EDONE:
+        ble_gatt_disc_c_test_rx_complete = 1;
+        break;
+
+    default:
+        TEST_ASSERT(0);
+        break;
+    }
+
+    if (*stop_after > 0) {
+        (*stop_after)--;
+        if (*stop_after == 0) {
+            ble_gatt_disc_c_test_rx_complete = 1;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void
+ble_gatt_disc_c_test_misc_all(uint16_t start_handle, uint16_t end_handle,
+                              int stop_after,
+                              struct ble_gatt_disc_c_test_char *chars)
+{
+    int num_left;
+    int rc;
+
+    ble_gatt_disc_c_test_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    num_left = stop_after;
+    rc = ble_gattc_disc_all_chrs(2, start_handle, end_handle,
+                                 ble_gatt_disc_c_test_misc_cb, &num_left);
+    TEST_ASSERT(rc == 0);
+
+    ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, chars);
+    ble_gatt_disc_c_test_misc_verify_chars(chars, stop_after);
+}
+
+static void
+ble_gatt_disc_c_test_misc_uuid(uint16_t start_handle, uint16_t end_handle,
+                               int stop_after, uint8_t *uuid128,
+                               struct ble_gatt_disc_c_test_char *rsp_chars,
+                               struct ble_gatt_disc_c_test_char *ret_chars)
+{
+    int rc;
+
+    ble_gatt_disc_c_test_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    rc = ble_gattc_disc_chrs_by_uuid(2, start_handle, end_handle,
+                                     uuid128,
+                                     ble_gatt_disc_c_test_misc_cb,
+                                     &stop_after);
+    TEST_ASSERT(rc == 0);
+
+    ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, rsp_chars);
+    ble_gatt_disc_c_test_misc_verify_chars(ret_chars, 0);
+}
+
+TEST_CASE(ble_gatt_disc_c_test_disc_all)
+{
+    /*** One 16-bit characteristic. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 0,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, { 0 }
+    });
+
+    /*** Two 16-bit characteristics. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 0,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 57,
+            .val_handle = 58,
+            .uuid16 = 0x64ba,
+        }, { 0 }
+    });
+
+    /*** Five 16-bit characteristics. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 0,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 57,
+            .val_handle = 58,
+            .uuid16 = 0x64ba,
+        }, {
+            .def_handle = 59,
+            .val_handle = 60,
+            .uuid16 = 0x5372,
+        }, {
+            .def_handle = 61,
+            .val_handle = 62,
+            .uuid16 = 0xab93,
+        }, {
+            .def_handle = 63,
+            .val_handle = 64,
+            .uuid16 = 0x0023,
+        }, { 0 }
+    });
+
+    /*** Interleaved 16-bit and 128-bit characteristics. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 0,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 83,
+            .val_handle = 84,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 87,
+            .val_handle = 88,
+            .uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, {
+            .def_handle = 91,
+            .val_handle = 92,
+            .uuid16 = 0x0003,
+        }, {
+            .def_handle = 93,
+            .val_handle = 94,
+            .uuid128 = { 1,0,4,0,6,9,17,7,8,43,7,4,12,43,19,35 },
+        }, {
+            .def_handle = 98,
+            .val_handle = 99,
+            .uuid16 = 0xabfa,
+        }, { 0 }
+    });
+
+    /*** Ends with final handle ID. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 0,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 99,
+            .val_handle = 100,
+            .uuid16 = 0x64ba,
+        }, { 0 }
+    });
+
+    /*** Stop after two characteristics. */
+    ble_gatt_disc_c_test_misc_all(50, 100, 2,
+                                  (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 57,
+            .val_handle = 58,
+            .uuid16 = 0x64ba,
+        }, {
+            .def_handle = 59,
+            .val_handle = 60,
+            .uuid16 = 0x5372,
+        }, {
+            .def_handle = 61,
+            .val_handle = 62,
+            .uuid16 = 0xab93,
+        }, {
+            .def_handle = 63,
+            .val_handle = 64,
+            .uuid16 = 0x0023,
+        }, { 0 }
+    });
+}
+
+TEST_CASE(ble_gatt_disc_c_test_disc_uuid)
+{
+    /*** One 16-bit characteristic. */
+    ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16(0x2010),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, { 0 } }
+    );
+
+    /*** No matching characteristics. */
+    ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16(0x2010),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x1234,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        { 0 } }
+    );
+
+    /*** 2/5 16-bit characteristics. */
+    ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16(0x2010),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 57,
+            .val_handle = 58,
+            .uuid16 = 0x64ba,
+        }, {
+            .def_handle = 59,
+            .val_handle = 60,
+            .uuid16 = 0x5372,
+        }, {
+            .def_handle = 61,
+            .val_handle = 62,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 63,
+            .val_handle = 64,
+            .uuid16 = 0x0023,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 61,
+            .val_handle = 62,
+            .uuid16 = 0x2010,
+        }, { 0 } }
+    );
+
+    /*** Interleaved 16-bit and 128-bit characteristics. */
+    ble_gatt_disc_c_test_misc_uuid(
+        50, 100, 0,
+        ((uint8_t[]){ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 83,
+            .val_handle = 84,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 87,
+            .val_handle = 88,
+            .uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, {
+            .def_handle = 91,
+            .val_handle = 92,
+            .uuid16 = 0x0003,
+        }, {
+            .def_handle = 93,
+            .val_handle = 94,
+            .uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, {
+            .def_handle = 98,
+            .val_handle = 99,
+            .uuid16 = 0xabfa,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 87,
+            .val_handle = 88,
+            .uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, {
+            .def_handle = 93,
+            .val_handle = 94,
+            .uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, { 0 } }
+    );
+
+    /*** Ends with final handle ID. */
+    ble_gatt_disc_c_test_misc_uuid(50, 100, 0, BLE_UUID16(0x64ba),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 99,
+            .val_handle = 100,
+            .uuid16 = 0x64ba,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 99,
+            .val_handle = 100,
+            .uuid16 = 0x64ba,
+        }, { 0 } }
+    );
+
+    /*** Stop after first characteristic. */
+    ble_gatt_disc_c_test_misc_uuid(50, 100, 1, BLE_UUID16(0x2010),
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 57,
+            .val_handle = 58,
+            .uuid16 = 0x64ba,
+        }, {
+            .def_handle = 59,
+            .val_handle = 60,
+            .uuid16 = 0x5372,
+        }, {
+            .def_handle = 61,
+            .val_handle = 62,
+            .uuid16 = 0x2010,
+        }, {
+            .def_handle = 63,
+            .val_handle = 64,
+            .uuid16 = 0x0023,
+        }, { 0 } },
+        (struct ble_gatt_disc_c_test_char[]) {
+        {
+            .def_handle = 55,
+            .val_handle = 56,
+            .uuid16 = 0x2010,
+        }, { 0 } }
+    );
+}
+
+TEST_SUITE(ble_gatt_disc_c_test_suite)
+{
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
+    ble_gatt_disc_c_test_disc_all();
+    ble_gatt_disc_c_test_disc_uuid();
+}
+
+int
+ble_gatt_disc_c_test_all(void)
+{
+    ble_gatt_disc_c_test_suite();
+
+    return tu_any_failed;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d98ddc1c/net/nimble/host/test/src/ble_gatt_disc_d_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_gatt_disc_d_test.c 
b/net/nimble/host/test/src/ble_gatt_disc_d_test.c
new file mode 100644
index 0000000..7e021e2
--- /dev/null
+++ b/net/nimble/host/test/src/ble_gatt_disc_d_test.c
@@ -0,0 +1,363 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <limits.h>
+#include "testutil/testutil.h"
+#include "nimble/ble.h"
+#include "host/ble_hs_test.h"
+#include "host/ble_gatt.h"
+#include "host/ble_uuid.h"
+#include "ble_hs_test_util.h"
+
+struct ble_gatt_disc_d_test_dsc {
+    uint16_t chr_val_handle; /* 0 if last entry. */
+    uint16_t dsc_handle;
+    uint8_t dsc_uuid128[16];
+};
+
+#define BLE_GATT_DISC_D_TEST_MAX_DSCS  256
+static struct ble_gatt_disc_d_test_dsc
+    ble_gatt_disc_d_test_dscs[BLE_GATT_DISC_D_TEST_MAX_DSCS];
+static int ble_gatt_disc_d_test_num_dscs;
+static int ble_gatt_disc_d_test_rx_complete;
+
+static void
+ble_gatt_disc_d_test_init(void)
+{
+    ble_hs_test_util_init();
+
+    ble_gatt_disc_d_test_num_dscs = 0;
+    ble_gatt_disc_d_test_rx_complete = 0;
+}
+
+static int
+ble_gatt_disc_d_test_misc_rx_rsp_once(
+    uint16_t conn_handle, struct ble_gatt_disc_d_test_dsc *dscs)
+{
+    struct ble_att_find_info_rsp rsp;
+    uint8_t buf[1024];
+    uint16_t uuid16_cur;
+    uint16_t uuid16_0;
+    int off;
+    int rc;
+    int i;
+
+    /* Send the pending ATT Read By Type Request. */
+    ble_hs_test_util_tx_all();
+
+    uuid16_0 = ble_uuid_128_to_16(dscs[0].dsc_uuid128);
+    if (uuid16_0 != 0) {
+        rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT;
+    } else {
+        rsp.bafp_format = BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT;
+    }
+
+    ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp);
+
+    off = BLE_ATT_FIND_INFO_RSP_BASE_SZ;
+    for (i = 0; ; i++) {
+        if (dscs[i].chr_val_handle == 0) {
+            /* No more descriptors. */
+            break;
+        }
+
+        /* If the value length is changing, we need a separate response. */
+        uuid16_cur = ble_uuid_128_to_16(dscs[i].dsc_uuid128);
+        if (((uuid16_0 == 0) ^ (uuid16_cur == 0)) != 0) {
+            break;
+        }
+
+        htole16(buf + off, dscs[i].dsc_handle);
+        off += 2;
+
+        if (uuid16_cur != 0) {
+            htole16(buf + off, uuid16_cur);
+            off += 2;
+        } else {
+            memcpy(buf + off, dscs[i].dsc_uuid128, 16);
+            off += 16;
+        }
+    }
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle,
+                                 uint16_t end_handle,
+                                 struct ble_gatt_disc_d_test_dsc *dscs)
+{
+    int count;
+    int idx;
+
+    idx = 0;
+    while (dscs[idx].chr_val_handle != 0) {
+        count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, dscs + idx);
+        if (count == 0) {
+            break;
+        }
+        idx += count;
+    }
+
+    if (dscs[idx - 1].dsc_handle != end_handle) {
+        /* Send the pending ATT Request. */
+        ble_hs_test_util_tx_all();
+        ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_FIND_INFO_REQ,
+                                        BLE_ATT_ERR_ATTR_NOT_FOUND,
+                                        end_handle);
+    }
+}
+
+static void
+ble_gatt_disc_d_test_misc_verify_dscs(struct ble_gatt_disc_d_test_dsc *dscs,
+                                      int stop_after)
+{
+    int i;
+
+    if (stop_after == 0) {
+        stop_after = INT_MAX;
+    }
+
+    for (i = 0; i < stop_after && dscs[i].chr_val_handle != 0; i++) {
+        TEST_ASSERT(dscs[i].chr_val_handle ==
+                    ble_gatt_disc_d_test_dscs[i].chr_val_handle);
+        TEST_ASSERT(dscs[i].dsc_handle ==
+                    ble_gatt_disc_d_test_dscs[i].dsc_handle);
+        TEST_ASSERT(memcmp(dscs[i].dsc_uuid128,
+                           ble_gatt_disc_d_test_dscs[i].dsc_uuid128,
+                           16) == 0);
+    }
+
+    TEST_ASSERT(i == ble_gatt_disc_d_test_num_dscs);
+    TEST_ASSERT(ble_gatt_disc_d_test_rx_complete);
+}
+
+static int
+ble_gatt_disc_d_test_misc_cb(uint16_t conn_handle,
+                             const struct ble_gatt_error *error,
+                             uint16_t chr_val_handle,
+                             const struct ble_gatt_dsc *dsc,
+                             void *arg)
+{
+    struct ble_gatt_disc_d_test_dsc *dst;
+    int *stop_after;
+
+    TEST_ASSERT(error != NULL);
+    TEST_ASSERT(!ble_gatt_disc_d_test_rx_complete);
+
+    stop_after = arg;
+
+    switch (error->status) {
+    case 0:
+        TEST_ASSERT_FATAL(ble_gatt_disc_d_test_num_dscs <
+                          BLE_GATT_DISC_D_TEST_MAX_DSCS);
+
+        dst = ble_gatt_disc_d_test_dscs + ble_gatt_disc_d_test_num_dscs++;
+        dst->chr_val_handle = chr_val_handle;
+        dst->dsc_handle = dsc->handle;
+        memcpy(dst->dsc_uuid128, dsc->uuid128, 16);
+        break;
+
+    case BLE_HS_EDONE:
+        ble_gatt_disc_d_test_rx_complete = 1;
+        break;
+
+    default:
+        TEST_ASSERT(0);
+        break;
+    }
+
+    if (*stop_after > 0) {
+        (*stop_after)--;
+        if (*stop_after == 0) {
+            ble_gatt_disc_d_test_rx_complete = 1;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void
+ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle, uint16_t end_handle,
+                              int stop_after,
+                              struct ble_gatt_disc_d_test_dsc *dscs)
+{
+    int num_left;
+    int rc;
+
+    ble_gatt_disc_d_test_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    num_left = stop_after;
+    rc = ble_gattc_disc_all_dscs(2, chr_val_handle, end_handle,
+                                 ble_gatt_disc_d_test_misc_cb, &num_left);
+    TEST_ASSERT(rc == 0);
+
+    ble_gatt_disc_d_test_misc_rx_rsp(2, end_handle, dscs);
+    ble_gatt_disc_d_test_misc_verify_dscs(dscs, stop_after);
+}
+
+TEST_CASE(ble_gatt_disc_d_test_1)
+{
+    /*** One 16-bit descriptor. */
+    ble_gatt_disc_d_test_misc_all(5, 10, 0,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 5,
+            .dsc_handle = 6,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1234),
+        }, {
+            0
+        } })
+    );
+
+    /*** Two 16-bit descriptors. */
+    ble_gatt_disc_d_test_misc_all(50, 100, 0,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 50,
+            .dsc_handle = 51,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1111),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 52,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x2222),
+        }, {
+            0
+        } })
+    );
+
+    /*** Five 16-bit descriptors. */
+    ble_gatt_disc_d_test_misc_all(50, 100, 0,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 50,
+            .dsc_handle = 51,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1111),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 52,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x2222),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 53,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x3333),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 54,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x4444),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 55,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x5555),
+        }, {
+            0
+        } })
+    );
+
+    /*** Interleaved 16-bit and 128-bit descriptors. */
+    ble_gatt_disc_d_test_misc_all(50, 100, 0,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 50,
+            .dsc_handle = 51,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1111),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 52,
+            .dsc_uuid128 = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 },
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 53,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x3333),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 54,
+            .dsc_uuid128 = { 1,0,4,0,6,9,17,7,8,43,7,4,12,43,19,35 },
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 55,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x5555),
+        }, {
+            0
+        } })
+    );
+
+    /*** Ends with final handle ID. */
+    ble_gatt_disc_d_test_misc_all(50, 52, 0,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 50,
+            .dsc_handle = 51,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1111),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 52,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x2222),
+        }, {
+            0
+        } })
+    );
+
+    /*** Stop after two descriptors. */
+    ble_gatt_disc_d_test_misc_all(50, 100, 2,
+        ((struct ble_gatt_disc_d_test_dsc[]) { {
+            .chr_val_handle = 50,
+            .dsc_handle = 51,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x1111),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 52,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x2222),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 53,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x3333),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 54,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x4444),
+        }, {
+            .chr_val_handle = 50,
+            .dsc_handle = 55,
+            .dsc_uuid128 = BLE_UUID16_ARR(0x5555),
+        }, {
+            0
+        } })
+    );
+}
+
+TEST_SUITE(ble_gatt_disc_d_test_suite)
+{
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
+    ble_gatt_disc_d_test_1();
+}
+
+int
+ble_gatt_disc_d_test_all(void)
+{
+    ble_gatt_disc_d_test_suite();
+
+    return tu_any_failed;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d98ddc1c/net/nimble/host/test/src/ble_gatt_disc_s_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_gatt_disc_s_test.c 
b/net/nimble/host/test/src/ble_gatt_disc_s_test.c
new file mode 100644
index 0000000..2e278d6
--- /dev/null
+++ b/net/nimble/host/test/src/ble_gatt_disc_s_test.c
@@ -0,0 +1,406 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "host/ble_hs_test.h"
+#include "host/ble_uuid.h"
+#include "ble_hs_test_util.h"
+
+struct ble_gatt_disc_s_test_svc {
+    uint16_t start_handle;
+    uint16_t end_handle;
+    uint16_t uuid16;
+    uint8_t uuid128[16];
+};
+
+#define BLE_GATT_DISC_S_TEST_MAX_SERVICES  256
+static struct ble_gatt_svc
+    ble_gatt_disc_s_test_svcs[BLE_GATT_DISC_S_TEST_MAX_SERVICES];
+static int ble_gatt_disc_s_test_num_svcs;
+static int ble_gatt_disc_s_test_rx_complete;
+
+static void
+ble_gatt_disc_s_test_init(void)
+{
+    ble_hs_test_util_init();
+    ble_gatt_disc_s_test_num_svcs = 0;
+    ble_gatt_disc_s_test_rx_complete = 0;
+}
+
+static int
+ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc *service)
+{
+    if (service->uuid16 != 0) {
+        return 6;
+    } else {
+        return 20;
+    }
+}
+
+static int
+ble_gatt_disc_s_test_misc_rx_all_rsp_once(
+    uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
+{
+    struct ble_att_read_group_type_rsp rsp;
+    uint8_t buf[1024];
+    int off;
+    int rc;
+    int i;
+
+    /* Send the pending ATT Read By Group Type Request. */
+    ble_hs_test_util_tx_all();
+
+    rsp.bagp_length = ble_gatt_disc_s_test_misc_svc_length(services);
+    ble_att_read_group_type_rsp_write(buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ,
+                                      &rsp);
+
+    off = BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ;
+    for (i = 0; ; i++) {
+        if (services[i].start_handle == 0) {
+            /* No more services. */
+            break;
+        }
+
+        rc = ble_gatt_disc_s_test_misc_svc_length(services + i);
+        if (rc != rsp.bagp_length) {
+            /* UUID length is changing; Need a separate response. */
+            break;
+        }
+
+        htole16(buf + off, services[i].start_handle);
+        off += 2;
+
+        htole16(buf + off, services[i].end_handle);
+        off += 2;
+
+        if (services[i].uuid16 != 0) {
+            htole16(buf + off, services[i].uuid16);
+            off += 2;
+        } else {
+            memcpy(buf + off, services[i].uuid128, 16);
+            off += 16;
+        }
+    }
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_disc_s_test_misc_rx_all_rsp(
+    uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
+{
+    int count;
+    int idx;
+
+    idx = 0;
+    while (services[idx].start_handle != 0) {
+        count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle,
+                                                          services + idx);
+        idx += count;
+    }
+
+    if (services[idx - 1].end_handle != 0xffff) {
+        /* Send the pending ATT Request. */
+        ble_hs_test_util_tx_all();
+        ble_hs_test_util_rx_att_err_rsp(conn_handle,
+                                        BLE_ATT_OP_READ_GROUP_TYPE_REQ,
+                                        BLE_ATT_ERR_ATTR_NOT_FOUND,
+                                        services[idx - 1].start_handle);
+    }
+}
+
+static int
+ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(
+    uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
+{
+    uint8_t buf[1024];
+    int off;
+    int rc;
+    int i;
+
+    /* Send the pending ATT Find By Type Value Request. */
+    ble_hs_test_util_tx_all();
+
+    buf[0] = BLE_ATT_OP_FIND_TYPE_VALUE_RSP;
+    off = BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
+    for (i = 0; ; i++) {
+        if (services[i].start_handle == 0) {
+            /* No more services. */
+            break;
+        }
+
+        htole16(buf + off, services[i].start_handle);
+        off += 2;
+
+        htole16(buf + off, services[i].end_handle);
+        off += 2;
+    }
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_disc_s_test_misc_rx_uuid_rsp(
+    uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services)
+{
+    int count;
+    int idx;
+
+    idx = 0;
+    while (services[idx].start_handle != 0) {
+        count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle,
+                                                           services + idx);
+        idx += count;
+    }
+
+    if (services[idx - 1].end_handle != 0xffff) {
+        /* Send the pending ATT Request. */
+        ble_hs_test_util_tx_all();
+        ble_hs_test_util_rx_att_err_rsp(conn_handle,
+                                        BLE_ATT_OP_FIND_TYPE_VALUE_REQ,
+                                        BLE_ATT_ERR_ATTR_NOT_FOUND,
+                                        services[idx - 1].start_handle);
+    }
+}
+
+static void
+ble_gatt_disc_s_test_misc_verify_services(
+    struct ble_gatt_disc_s_test_svc *services)
+{
+    uint16_t uuid16;
+    uint8_t *uuid128;
+    int i;
+
+    for (i = 0; services[i].start_handle != 0; i++) {
+        TEST_ASSERT(services[i].start_handle ==
+                    ble_gatt_disc_s_test_svcs[i].start_handle);
+        TEST_ASSERT(services[i].end_handle ==
+                    ble_gatt_disc_s_test_svcs[i].end_handle);
+
+        uuid128 = ble_gatt_disc_s_test_svcs[i].uuid128;
+        uuid16 = ble_uuid_128_to_16(uuid128);
+        if (uuid16 != 0) {
+            TEST_ASSERT(services[i].uuid16 == uuid16);
+        } else {
+            TEST_ASSERT(memcmp(services[i].uuid128, uuid128, 16) == 0);
+        }
+    }
+
+    TEST_ASSERT(i == ble_gatt_disc_s_test_num_svcs);
+    TEST_ASSERT(ble_gatt_disc_s_test_rx_complete);
+}
+
+static int
+ble_gatt_disc_s_test_misc_disc_cb(uint16_t conn_handle,
+                                  const struct ble_gatt_error *error,
+                                  const struct ble_gatt_svc *service,
+                                  void *arg)
+{
+    TEST_ASSERT(error != NULL);
+    TEST_ASSERT(!ble_gatt_disc_s_test_rx_complete);
+
+    switch (error->status) {
+    case 0:
+        TEST_ASSERT(service != NULL);
+        TEST_ASSERT_FATAL(ble_gatt_disc_s_test_num_svcs <
+                          BLE_GATT_DISC_S_TEST_MAX_SERVICES);
+        ble_gatt_disc_s_test_svcs[ble_gatt_disc_s_test_num_svcs++] = *service;
+        break;
+
+    case BLE_HS_EDONE:
+        TEST_ASSERT(service == NULL);
+        ble_gatt_disc_s_test_rx_complete = 1;
+        break;
+
+    default:
+        TEST_ASSERT(0);
+    }
+
+    return 0;
+}
+
+static void
+ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc *services)
+{
+    int rc;
+
+    ble_gatt_disc_s_test_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    rc = ble_gattc_disc_all_svcs(2, ble_gatt_disc_s_test_misc_disc_cb, NULL);
+    TEST_ASSERT(rc == 0);
+
+    ble_gatt_disc_s_test_misc_rx_all_rsp(2, services);
+    ble_gatt_disc_s_test_misc_verify_services(services);
+}
+
+static void
+ble_gatt_disc_s_test_misc_good_uuid(
+    struct ble_gatt_disc_s_test_svc *services)
+{
+    int rc;
+
+    ble_gatt_disc_s_test_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    if (services[0].uuid16 != 0) {
+        rc = ble_uuid_16_to_128(services[0].uuid16, services[0].uuid128);
+        TEST_ASSERT_FATAL(rc == 0);
+    }
+    rc = ble_gattc_disc_svc_by_uuid(2, services[0].uuid128,
+                                    ble_gatt_disc_s_test_misc_disc_cb, NULL);
+    TEST_ASSERT(rc == 0);
+
+    ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, services);
+    ble_gatt_disc_s_test_misc_verify_services(services);
+}
+
+TEST_CASE(ble_gatt_disc_s_test_disc_all)
+{
+    /*** One 128-bit service. */
+    ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 0 }
+    });
+
+    /*** Two 128-bit services. */
+    ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 10, 50, 0,    {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, },
+        { 0 }
+    });
+
+    /*** Five 128-bit services. */
+    ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 10, 50, 0,    {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, },
+        { 80, 120, 0,   {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, },
+        { 123, 678, 0,  {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, },
+        { 751, 999, 0,  {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, },
+        { 0 }
+    });
+
+    /*** One 128-bit service, one 16-bit-service. */
+    ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 6, 7, 0x1234 },
+        { 0 }
+    });
+
+    /*** End with handle 0xffff. */
+    ble_gatt_disc_s_test_misc_good_all((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 7, 0xffff, 0, {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, },
+        { 0 }
+    });
+}
+
+TEST_CASE(ble_gatt_disc_s_test_disc_service_uuid)
+{
+    /*** 128-bit service; one entry. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 0 }
+    });
+
+    /*** 128-bit service; two entries. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 8, 43, 0,     {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 0 }
+    });
+
+    /*** 128-bit service; five entries. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 8, 43, 0,     {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 67, 100, 0,   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 102, 103, 0,  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 262, 900, 0,  {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 0 }
+    });
+
+    /*** 128-bit service; end with handle 0xffff. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0,      {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 7, 0xffff, 0, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, },
+        { 0 }
+    });
+
+    /*** 16-bit service; one entry. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0x1234 },
+        { 0 }
+    });
+
+    /*** 16-bit service; two entries. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0x1234 },
+        { 85, 243, 0x1234 },
+        { 0 }
+    });
+
+    /*** 16-bit service; five entries. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0x1234 },
+        { 85, 243, 0x1234 },
+        { 382, 383, 0x1234 },
+        { 562, 898, 0x1234 },
+        { 902, 984, 0x1234 },
+        { 0 }
+    });
+
+    /*** 16-bit service; end with handle 0xffff. */
+    ble_gatt_disc_s_test_misc_good_uuid((struct ble_gatt_disc_s_test_svc[]) {
+        { 1, 5, 0x1234 },
+        { 9, 0xffff, 0x1234 },
+        { 0 }
+    });
+}
+
+TEST_SUITE(ble_gatt_disc_s_test_suite)
+{
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
+    ble_gatt_disc_s_test_disc_all();
+    ble_gatt_disc_s_test_disc_service_uuid();
+}
+
+int
+ble_gatt_disc_s_test_all(void)
+{
+    ble_gatt_disc_s_test_suite();
+
+    return tu_any_failed;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d98ddc1c/net/nimble/host/test/src/ble_gatt_find_s_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/test/src/ble_gatt_find_s_test.c 
b/net/nimble/host/test/src/ble_gatt_find_s_test.c
new file mode 100644
index 0000000..c3ab93d
--- /dev/null
+++ b/net/nimble/host/test/src/ble_gatt_find_s_test.c
@@ -0,0 +1,342 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "host/ble_hs_test.h"
+#include "host/ble_uuid.h"
+#include "ble_hs_test_util.h"
+
+static struct ble_gatt_svc ble_gatt_find_s_test_svcs[256];
+static int ble_gatt_find_s_test_num_svcs;
+static int ble_gatt_find_s_test_proc_complete;
+
+struct ble_gatt_find_s_test_entry {
+    uint16_t inc_handle; /* 0 indicates no more entries. */
+    uint16_t start_handle;
+    uint16_t end_handle;
+    uint8_t uuid128[16];
+};
+
+static void
+ble_gatt_find_s_test_misc_init(void)
+{
+    ble_hs_test_util_init();
+    ble_gatt_find_s_test_num_svcs = 0;
+    ble_gatt_find_s_test_proc_complete = 0;
+}
+
+static int
+ble_gatt_find_s_test_misc_cb(uint16_t conn_handle,
+                             const struct ble_gatt_error *error,
+                             const struct ble_gatt_svc *service,
+                             void *arg)
+{
+    TEST_ASSERT(!ble_gatt_find_s_test_proc_complete);
+    TEST_ASSERT(error != NULL);
+
+    switch (error->status) {
+    case 0:
+        ble_gatt_find_s_test_svcs[ble_gatt_find_s_test_num_svcs++] = *service;
+        break;
+
+    case BLE_HS_EDONE:
+        ble_gatt_find_s_test_proc_complete = 1;
+        break;
+
+    default:
+        TEST_ASSERT(0);
+        break;
+    }
+
+    return 0;
+}
+static int
+ble_gatt_find_s_test_misc_rx_read_type(
+    uint16_t conn_handle, struct ble_gatt_find_s_test_entry *entries)
+{
+    struct ble_att_read_type_rsp rsp;
+    uint16_t uuid16;
+    uint8_t buf[1024];
+    int off;
+    int rc;
+    int i;
+
+    memset(&rsp, 0, sizeof rsp);
+
+    off = BLE_ATT_READ_TYPE_RSP_BASE_SZ;
+    for (i = 0; entries[i].inc_handle != 0; i++) {
+        if (rsp.batp_length == BLE_GATTS_INC_SVC_LEN_NO_UUID + 2) {
+            break;
+        }
+
+        uuid16 = ble_uuid_128_to_16(entries[i].uuid128);
+        if (uuid16 == 0) {
+            if (rsp.batp_length != 0) {
+                break;
+            }
+            rsp.batp_length = BLE_GATTS_INC_SVC_LEN_NO_UUID + 2;
+        } else {
+            rsp.batp_length = BLE_GATTS_INC_SVC_LEN_UUID + 2;
+        }
+
+        TEST_ASSERT_FATAL(off + rsp.batp_length <= sizeof buf);
+
+        htole16(buf + off, entries[i].inc_handle);
+        off += 2;
+
+        htole16(buf + off, entries[i].start_handle);
+        off += 2;
+
+        htole16(buf + off, entries[i].end_handle);
+        off += 2;
+
+        if (uuid16 != 0) {
+            htole16(buf + off, uuid16);
+            off += 2;
+        }
+    }
+
+    if (i == 0) {
+        ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ,
+                                        BLE_ATT_ERR_ATTR_NOT_FOUND, 0);
+        return 0;
+    }
+
+    ble_att_read_type_rsp_write(buf + 0, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp);
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, uint8_t *uuid128)
+{
+    uint8_t buf[17];
+    int rc;
+
+    buf[0] = BLE_ATT_OP_READ_RSP;
+    memcpy(buf + 1, uuid128, 16);
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, 17);
+    TEST_ASSERT(rc == 0);
+}
+
+static void
+ble_gatt_find_s_test_misc_verify_tx_read_type(uint16_t start_handle,
+                                              uint16_t end_handle)
+{
+    struct ble_att_read_type_req req;
+    struct os_mbuf *om;
+    uint16_t uuid16;
+
+    ble_hs_test_util_tx_all();
+
+    om = ble_hs_test_util_prev_tx_dequeue_pullup();
+    TEST_ASSERT_FATAL(om != NULL);
+
+    ble_att_read_type_req_parse(om->om_data, om->om_len, &req);
+
+    TEST_ASSERT(req.batq_start_handle == start_handle);
+    TEST_ASSERT(req.batq_end_handle == end_handle);
+    TEST_ASSERT(om->om_len == BLE_ATT_READ_TYPE_REQ_BASE_SZ + 2);
+    uuid16 = le16toh(om->om_data + BLE_ATT_READ_TYPE_REQ_BASE_SZ);
+    TEST_ASSERT(uuid16 == BLE_ATT_UUID_INCLUDE);
+}
+
+static void
+ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle)
+{
+    struct ble_att_read_req req;
+    struct os_mbuf *om;
+
+    ble_hs_test_util_tx_all();
+
+    om = ble_hs_test_util_prev_tx_dequeue_pullup();
+    TEST_ASSERT_FATAL(om != NULL);
+
+    ble_att_read_req_parse(om->om_data, om->om_len, &req);
+
+    TEST_ASSERT(req.barq_handle == handle);
+    TEST_ASSERT(om->om_len == BLE_ATT_READ_REQ_SZ);
+}
+
+static void
+ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle,
+                                   uint16_t start_handle, uint16_t end_handle,
+                                   struct ble_gatt_find_s_test_entry *entries)
+{
+    struct ble_gatt_svc service;
+    int cur_start;
+    int num_found;
+    int idx;
+    int rc;
+    int i;
+
+    rc = ble_gattc_find_inc_svcs(conn_handle, start_handle, end_handle,
+                                 ble_gatt_find_s_test_misc_cb, &service);
+    TEST_ASSERT(rc == 0);
+
+    cur_start = start_handle;
+    idx = 0;
+    while (1) {
+        ble_gatt_find_s_test_misc_verify_tx_read_type(cur_start, end_handle);
+        num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle,
+                                                           entries + idx);
+        if (num_found == 0) {
+            break;
+        }
+
+        if (ble_uuid_128_to_16(entries[idx].uuid128) == 0) {
+            TEST_ASSERT(num_found == 1);
+            ble_gatt_find_s_test_misc_verify_tx_read(
+                entries[idx].start_handle);
+            ble_gatt_find_s_test_misc_rx_read(conn_handle,
+                                              entries[idx].uuid128);
+        }
+
+        idx += num_found;
+        cur_start = entries[idx - 1].inc_handle + 1;
+    }
+    TEST_ASSERT(idx == ble_gatt_find_s_test_num_svcs);
+    TEST_ASSERT(ble_gatt_find_s_test_proc_complete);
+
+    for (i = 0; i < ble_gatt_find_s_test_num_svcs; i++) {
+        TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle ==
+                    entries[i].start_handle);
+        TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle ==
+                    entries[i].end_handle);
+        TEST_ASSERT(memcmp(ble_gatt_find_s_test_svcs[i].uuid128,
+                           entries[i].uuid128, 16) == 0);
+    }
+}
+
+TEST_CASE(ble_gatt_find_s_test_1)
+{
+    /* Two 16-bit UUID services; one response. */
+    ble_gatt_find_s_test_misc_init();
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+    ble_gatt_find_s_test_misc_find_inc(2, 5, 10,
+        ((struct ble_gatt_find_s_test_entry[]) { {
+            .inc_handle = 6,
+            .start_handle = 35,
+            .end_handle = 49,
+            .uuid128 = BLE_UUID16_ARR(0x5155),
+        }, {
+            .inc_handle = 9,
+            .start_handle = 543,
+            .end_handle = 870,
+            .uuid128 = BLE_UUID16_ARR(0x1122),
+        }, {
+            0,
+        } })
+    );
+
+    /* One 128-bit UUID service; two responses. */
+    ble_gatt_find_s_test_misc_init();
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+    ble_gatt_find_s_test_misc_find_inc(2, 34, 100,
+        ((struct ble_gatt_find_s_test_entry[]) { {
+            .inc_handle = 36,
+            .start_handle = 403,
+            .end_handle = 859,
+            .uuid128 = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
+        }, {
+            0,
+        } })
+    );
+
+    /* Two 128-bit UUID service; four responses. */
+    ble_gatt_find_s_test_misc_init();
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+    ble_gatt_find_s_test_misc_find_inc(2, 34, 100,
+        ((struct ble_gatt_find_s_test_entry[]) { {
+            .inc_handle = 36,
+            .start_handle = 403,
+            .end_handle = 859,
+            .uuid128 = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
+        }, {
+            .inc_handle = 39,
+            .start_handle = 900,
+            .end_handle = 932,
+            .uuid128 = { 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 },
+        }, {
+            0,
+        } })
+    );
+
+    /* Two 16-bit UUID; three 128-bit UUID; seven responses. */
+    ble_gatt_find_s_test_misc_init();
+    ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+    ble_gatt_find_s_test_misc_find_inc(2, 1, 100,
+        ((struct ble_gatt_find_s_test_entry[]) { {
+            .inc_handle = 36,
+            .start_handle = 403,
+            .end_handle = 859,
+            .uuid128 = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
+        }, {
+            .inc_handle = 37,
+            .start_handle = 35,
+            .end_handle = 49,
+            .uuid128 = BLE_UUID16_ARR(0x5155),
+        }, {
+            .inc_handle = 38,
+            .start_handle = 543,
+            .end_handle = 870,
+            .uuid128 = BLE_UUID16_ARR(0x1122),
+        }, {
+            .inc_handle = 39,
+            .start_handle = 900,
+            .end_handle = 932,
+            .uuid128 = { 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 },
+        }, {
+            .inc_handle = 40,
+            .start_handle = 940,
+            .end_handle = 950,
+            .uuid128 = { 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 },
+        }, {
+            0,
+        } })
+    );
+}
+
+TEST_SUITE(ble_gatt_find_s_test_suite)
+{
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
+    ble_gatt_find_s_test_1();
+}
+
+int
+ble_gatt_find_s_test_all(void)
+{
+    ble_gatt_find_s_test_suite();
+
+    return tu_any_failed;
+}

Reply via email to