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/08 02:54:48 UTC

incubator-mynewt-larva git commit: Discover All Characteristic Descriptors GATT proc.

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 5089258db -> d5ba6afe5


Discover All Characteristic Descriptors GATT proc.


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

Branch: refs/heads/master
Commit: d5ba6afe57d03f68626d254a22bf6615344083a8
Parents: 5089258
Author: Christopher Collins <cc...@gmail.com>
Authored: Thu Jan 7 16:26:06 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Jan 7 17:54:24 2016 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_gatt.h         |  10 +-
 net/nimble/host/include/host/ble_hs_test.h      |   1 +
 net/nimble/host/src/ble_att_clt.c               |  23 +-
 net/nimble/host/src/ble_att_cmd.h               |   3 +
 net/nimble/host/src/ble_gatt_priv.h             |   3 +
 net/nimble/host/src/ble_gattc.c                 | 165 ++++++++-
 net/nimble/host/src/test/ble_gatt_disc_d_test.c | 356 +++++++++++++++++++
 net/nimble/host/src/test/ble_hs_test.c          |   1 +
 net/nimble/host/src/test/ble_hs_test_util.c     |   7 +
 net/nimble/host/src/test/ble_hs_test_util.h     |   1 +
 10 files changed, 555 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/include/host/ble_gatt.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gatt.h b/net/nimble/host/include/host/ble_gatt.h
index ce6f816..1cc4085 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -52,9 +52,12 @@ typedef int ble_gatt_attr_fn(uint16_t conn_handle, int status,
 typedef int ble_gatt_chr_fn(uint16_t conn_handle, int status,
                             struct ble_gatt_chr *chr, void *arg);
 
+typedef int ble_gatt_dsc_fn(uint16_t conn_handle, int status,
+                            uint16_t chr_val_handle, uint16_t dsc_handle,
+                            uint8_t *dsc_uuid128, void *arg);
+
 int ble_gattc_disc_all_svcs(uint16_t conn_handle,
-                                ble_gatt_disc_svc_fn *cb,
-                                void *cb_arg);
+                            ble_gatt_disc_svc_fn *cb, void *cb_arg);
 int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, void *service_uuid128,
                                ble_gatt_disc_svc_fn *cb, void *cb_arg);
 int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
@@ -66,6 +69,9 @@ int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
 int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
                                uint16_t end_handle, void *uuid128,
                                ble_gatt_chr_fn *cb, void *cb_arg);
+int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_val_handle,
+                            uint16_t chr_end_handle,
+                            ble_gatt_dsc_fn *cb, void *cb_arg);
 int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle,
                    ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/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 cb5d588..39de412 100644
--- a/net/nimble/host/include/host/ble_hs_test.h
+++ b/net/nimble/host/include/host/ble_hs_test.h
@@ -32,6 +32,7 @@ int ble_os_test_all(void);
 int ble_uuid_test_all(void);
 int ble_gatt_disc_s_test_all(void);
 int ble_gatt_disc_c_test_all(void);
+int ble_gatt_disc_d_test_all(void);
 int ble_gatt_read_test_all(void);
 int ble_gatt_write_test_all(void);
 int ble_gatt_conn_test_all(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/src/ble_att_clt.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_clt.c b/net/nimble/host/src/ble_att_clt.c
index 42934e4..5951fd6 100644
--- a/net/nimble/host/src/ble_att_clt.c
+++ b/net/nimble/host/src/ble_att_clt.c
@@ -212,7 +212,8 @@ ble_att_clt_rx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     while (off < OS_MBUF_PKTLEN(rxom)) {
         rc = os_mbuf_copydata(rxom, off, 2, &handle_id);
         if (rc != 0) {
-            return BLE_HS_EINVAL;
+            rc = BLE_HS_EBADDATA;
+            goto done;
         }
         off += 2;
         handle_id = le16toh(&handle_id);
@@ -221,33 +222,41 @@ ble_att_clt_rx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
         case BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT:
             rc = os_mbuf_copydata(rxom, off, 2, &uuid16);
             if (rc != 0) {
-                return BLE_HS_EINVAL;
+                rc = BLE_HS_EBADDATA;
+                goto done;
             }
             off += 2;
             uuid16 = le16toh(&uuid16);
 
             rc = ble_uuid_16_to_128(uuid16, uuid128);
             if (rc != 0) {
-                return BLE_HS_EINVAL;
+                rc = BLE_HS_EBADDATA;
+                goto done;
             }
             break;
 
         case BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT:
             rc = os_mbuf_copydata(rxom, off, 16, &uuid128);
             if (rc != 0) {
-                rc = BLE_HS_EINVAL;
+                rc = BLE_HS_EBADDATA;
+                goto done;
             }
             off += 16;
             break;
 
         default:
-            return BLE_HS_EINVAL;
+            rc = BLE_HS_EBADDATA;
+            goto done;
         }
 
-        /* XXX: Notify GATT of handle-uuid pair. */
+        ble_gattc_rx_find_info_entry(conn, 0, handle_id, uuid128);
     }
 
-    return 0;
+    rc = 0;
+
+done:
+    ble_gattc_rx_find_info_complete(conn, rc);
+    return rc;
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/src/ble_att_cmd.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_cmd.h b/net/nimble/host/src/ble_att_cmd.h
index 73c8ea2..5de82f9 100644
--- a/net/nimble/host/src/ble_att_cmd.h
+++ b/net/nimble/host/src/ble_att_cmd.h
@@ -75,6 +75,9 @@ struct ble_att_find_info_rsp {
 #define BLE_ATT_FIND_INFO_RSP_FORMAT_16BIT   1
 #define BLE_ATT_FIND_INFO_RSP_FORMAT_128BIT  2
 
+#define BLE_ATT_FIND_INFO_IDATA_16_SZ           4
+#define BLE_ATT_FIND_INFO_IDATA_128_SZ          18
+
 /**
  * | Parameter                          | Size (octets)     |
  * +------------------------------------+-------------------+

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/src/ble_gatt_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h
index 7deacd2..5b6e344 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -57,6 +57,9 @@ void ble_gattc_rx_find_type_value_hinfo(struct ble_hs_conn *conn,
 void ble_gattc_rx_find_type_value_complete(struct ble_hs_conn *conn, int rc);
 void ble_gattc_rx_write_rsp(struct ble_hs_conn *conn);
 void ble_gattc_rx_indicate_rsp(struct ble_hs_conn *conn);
+void ble_gattc_rx_find_info_entry(struct ble_hs_conn *conn, int status,
+                                  uint16_t handle, uint8_t *uuid128);
+void ble_gattc_rx_find_info_complete(struct ble_hs_conn *conn, int status);
 void ble_gattc_connection_txable(uint16_t conn_handle);
 void ble_gattc_connection_broken(uint16_t conn_handle);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/src/ble_gattc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c
index 37452e7..77e9284 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -83,6 +83,14 @@ struct ble_gattc_entry {
         } disc_chr_uuid;
 
         struct {
+            uint16_t chr_val_handle;
+            uint16_t prev_handle;
+            uint16_t end_handle;
+            ble_gatt_dsc_fn *cb;
+            void *cb_arg;
+        } disc_all_dscs;
+
+        struct {
             uint16_t handle;
             ble_gatt_attr_fn *cb;
             void *cb_arg;
@@ -112,11 +120,12 @@ struct ble_gattc_entry {
 #define BLE_GATT_OP_FIND_INC_SVCS               3
 #define BLE_GATT_OP_DISC_ALL_CHRS               4
 #define BLE_GATT_OP_DISC_CHRS_UUID              5
-#define BLE_GATT_OP_READ                        6
-#define BLE_GATT_OP_WRITE_NO_RSP                7
-#define BLE_GATT_OP_WRITE                       8
-#define BLE_GATT_OP_INDICATE                    9
-#define BLE_GATT_OP_MAX                         10
+#define BLE_GATT_OP_DISC_ALL_DSCS               6
+#define BLE_GATT_OP_READ                        7
+#define BLE_GATT_OP_WRITE_NO_RSP                8
+#define BLE_GATT_OP_WRITE                       9
+#define BLE_GATT_OP_INDICATE                    10
+#define BLE_GATT_OP_MAX                         11
 
 static struct os_callout_func ble_gattc_heartbeat_timer;
 
@@ -129,6 +138,7 @@ static int ble_gattc_kick_disc_svc_uuid(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_find_inc_svcs(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_disc_all_chrs(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_disc_chr_uuid(struct ble_gattc_entry *entry);
+static int ble_gattc_kick_disc_all_dscs(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_read(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_write_no_rsp(struct ble_gattc_entry *entry);
 static int ble_gattc_kick_write(struct ble_gattc_entry *entry);
@@ -145,6 +155,8 @@ static void ble_gattc_err_disc_all_chrs(struct ble_gattc_entry *entry,
                                         int status);
 static void ble_gattc_err_disc_chr_uuid(struct ble_gattc_entry *entry,
                                         int status);
+static void ble_gattc_err_disc_all_dscs(struct ble_gattc_entry *entry,
+                                        int status);
 static void ble_gattc_err_read(struct ble_gattc_entry *entry, int status);
 static void ble_gattc_err_write(struct ble_gattc_entry *entry, int status);
 static void ble_gattc_err_indicate(struct ble_gattc_entry *entry, int status);
@@ -206,6 +218,10 @@ static const struct ble_gattc_dispatch_entry
         .kick_cb = ble_gattc_kick_disc_chr_uuid,
         .err_cb = ble_gattc_err_disc_chr_uuid,
     },
+    [BLE_GATT_OP_DISC_ALL_DSCS] = {
+        .kick_cb = ble_gattc_kick_disc_all_dscs,
+        .err_cb = ble_gattc_err_disc_all_dscs,
+    },
     [BLE_GATT_OP_READ] = {
         .kick_cb = ble_gattc_kick_read,
         .err_cb = ble_gattc_err_read,
@@ -1393,7 +1409,144 @@ ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
 }
 
 /*****************************************************************************
- * @read                                                                     *
+ * $discover all characteristic descriptors                                  *
+ *****************************************************************************/
+
+static int
+ble_gattc_disc_all_dscs_cb(struct ble_gattc_entry *entry, int status,
+                           uint16_t dsc_handle, uint8_t *dsc_uuid128)
+{
+    int rc;
+
+    if (entry->disc_all_dscs.cb == NULL) {
+        rc = 0;
+    } else {
+        rc = entry->disc_all_dscs.cb(entry->conn_handle, status,
+                                     entry->disc_all_dscs.chr_val_handle,
+                                     dsc_handle, dsc_uuid128,
+                                     entry->disc_all_dscs.cb_arg);
+    }
+
+    return rc;
+}
+
+static int
+ble_gattc_kick_disc_all_dscs(struct ble_gattc_entry *entry)
+{
+    struct ble_att_find_info_req req;
+    struct ble_hs_conn *conn;
+    int rc;
+
+    conn = ble_hs_conn_find(entry->conn_handle);
+    if (conn == NULL) {
+        rc = BLE_HS_ENOTCONN;
+        goto err;
+    }
+
+    req.bafq_start_handle = entry->disc_all_dscs.prev_handle + 1;
+    req.bafq_end_handle = entry->disc_all_dscs.end_handle;
+
+    rc = ble_att_clt_tx_find_info(conn, &req);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    if (ble_gattc_tx_postpone_chk(entry, rc)) {
+        return BLE_HS_EAGAIN;
+    }
+
+    ble_gattc_disc_all_dscs_cb(entry, rc, 0, NULL);
+    return rc;
+}
+
+static void
+ble_gattc_err_disc_all_dscs(struct ble_gattc_entry *entry, int status)
+{
+    if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND)) {
+        /* Discovery is complete. */
+        status = 0;
+    }
+
+    ble_gattc_disc_all_dscs_cb(entry, status, 0, NULL);
+}
+
+void
+ble_gattc_rx_find_info_entry(struct ble_hs_conn *conn, int status,
+                             uint16_t handle, uint8_t *uuid128)
+{
+    struct ble_gattc_entry *entry;
+    struct ble_gattc_entry *prev;
+    int rc;
+
+    entry = ble_gattc_find(conn->bhc_handle, BLE_GATT_OP_DISC_ALL_DSCS, 1,
+                           &prev);
+    if (entry == NULL) {
+        /* Not expecting a response from this device. */
+        return;
+    }
+
+    rc = ble_gattc_disc_all_dscs_cb(entry, status, handle, uuid128);
+    if (rc != 0) {
+        ble_gattc_entry_remove_free(entry, prev);
+    } else if (status != 0) {
+        /* Error. */
+        ble_gattc_disc_all_dscs_cb(entry, status, 0, NULL);
+        ble_gattc_entry_remove_free(entry, prev);
+    } else {
+        entry->disc_all_dscs.prev_handle = handle;
+    }
+}
+
+void
+ble_gattc_rx_find_info_complete(struct ble_hs_conn *conn, int status)
+{
+    struct ble_gattc_entry *entry;
+    struct ble_gattc_entry *prev;
+
+    entry = ble_gattc_find(conn->bhc_handle, BLE_GATT_OP_DISC_ALL_DSCS, 1,
+                           &prev);
+    if (entry == NULL) {
+        /* Not expecting a response from this device. */
+        return;
+    }
+
+    if (status != 0 || entry->disc_all_dscs.prev_handle ==
+                       entry->disc_all_dscs.end_handle) {
+        /* Error or all descriptors discovered. */
+        ble_gattc_disc_all_dscs_cb(entry, status, 0, NULL);
+        ble_gattc_entry_remove_free(entry, prev);
+    } else {
+        /* Send follow-up request. */
+        ble_gattc_entry_set_pending(entry);
+    }
+}
+
+int
+ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t chr_val_handle,
+                        uint16_t chr_end_handle,
+                        ble_gatt_dsc_fn *cb, void *cb_arg)
+{
+    struct ble_gattc_entry *entry;
+    int rc;
+
+    rc = ble_gattc_new_entry(conn_handle, BLE_GATT_OP_DISC_ALL_DSCS, &entry);
+    if (rc != 0) {
+        return rc;
+    }
+    entry->disc_all_dscs.chr_val_handle = chr_val_handle;
+    entry->disc_all_dscs.prev_handle = chr_val_handle;
+    entry->disc_all_dscs.end_handle = chr_end_handle;
+    entry->disc_all_dscs.cb = cb;
+    entry->disc_all_dscs.cb_arg = cb_arg;
+
+    return 0;
+}
+
+/*****************************************************************************
+ * $read                                                                     *
  *****************************************************************************/
 
 static int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/net/nimble/host/src/test/ble_gatt_disc_d_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_disc_d_test.c b/net/nimble/host/src/test/ble_gatt_disc_d_test.c
new file mode 100644
index 0000000..5add73d
--- /dev/null
+++ b/net/nimble/host/src/test/ble_gatt_disc_d_test.c
@@ -0,0 +1,356 @@
+/**
+ * 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 <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_priv.h"
+#include "ble_att_cmd.h"
+#include "ble_gatt_priv.h"
+#include "ble_hs_conn.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(
+    struct ble_hs_conn *conn, struct ble_gatt_disc_d_test_dsc *dscs)
+{
+    struct ble_att_find_info_rsp rsp;
+    struct ble_l2cap_chan *chan;
+    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;
+    }
+
+    rc = ble_att_find_info_rsp_write(buf, BLE_ATT_FIND_INFO_RSP_BASE_SZ, &rsp);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    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;
+        }
+    }
+
+    chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT);
+    TEST_ASSERT_FATAL(chan != NULL);
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn, chan, buf, off);
+    TEST_ASSERT(rc == 0);
+
+    return i;
+}
+
+static void
+ble_gatt_disc_d_test_misc_rx_rsp(struct ble_hs_conn *conn,
+                                 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, 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, 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, int status,
+                             uint16_t chr_val_handle, uint16_t dsc_handle,
+                             uint8_t *dsc_uuid128, void *arg)
+{
+    struct ble_gatt_disc_d_test_dsc *dsc;
+    int *stop_after;
+
+    TEST_ASSERT(status == 0);
+    TEST_ASSERT(!ble_gatt_disc_d_test_rx_complete);
+
+    stop_after = arg;
+
+    if (dsc_handle == 0) {
+        ble_gatt_disc_d_test_rx_complete = 1;
+    } else {
+        TEST_ASSERT_FATAL(ble_gatt_disc_d_test_num_dscs <
+                          BLE_GATT_DISC_D_TEST_MAX_DSCS);
+
+        dsc = ble_gatt_disc_d_test_dscs + ble_gatt_disc_d_test_num_dscs++;
+        dsc->chr_val_handle = chr_val_handle;
+        dsc->dsc_handle = dsc_handle;
+        memcpy(dsc->dsc_uuid128, dsc_uuid128, 16);
+    }
+
+    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)
+{
+    struct ble_hs_conn *conn;
+    int num_left;
+    int rc;
+
+    ble_gatt_disc_d_test_init();
+
+    conn = ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}));
+
+    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(conn, 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)
+{
+    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-larva/blob/d5ba6afe/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 d7cfa60..d959f11 100644
--- a/net/nimble/host/src/test/ble_hs_test.c
+++ b/net/nimble/host/src/test/ble_hs_test.c
@@ -58,6 +58,7 @@ main(void)
     ble_uuid_test_all();
     ble_gatt_disc_s_test_all();
     ble_gatt_disc_c_test_all();
+    ble_gatt_disc_d_test_all();
     ble_gatt_read_test_all();
     ble_gatt_write_test_all();
     ble_gatt_conn_test_all();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/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 4f4f49d..ff7963e 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -329,6 +329,13 @@ ble_hs_test_util_rx_dir_adv_acks(void)
 }
 
 void
+ble_hs_test_util_tx_all(void)
+{
+    ble_gattc_wakeup();
+    ble_hs_process_tx_data_queue();
+}
+
+void
 ble_hs_test_util_init(void)
 {
     int rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d5ba6afe/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 1a8cf4a..335dc75 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,7 @@ 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);
+void ble_hs_test_util_tx_all(void);
 void ble_hs_test_util_init(void);
 
 #endif