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/07/23 02:47:28 UTC

[01/11] incubator-mynewt-core git commit: os - Add mbuf fuction: os_mbuf_cmpm()

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop 24deb8d92 -> beab6f23b


os - Add mbuf fuction: os_mbuf_cmpm()

/**
 * Compares the contents of two mbuf chains.  The ranges of the two
 * chains to be compared are specified via the two offset parameters and
 * the len parameter.  Neither mbuf chain is required to contain a
 * packet header.
 *
 * @param om1                   The first mbuf chain to compare.
 * @param offset1               The absolute offset within om1 at which
 *                                  to start the comparison.
 * @param om2                   The second mbuf chain to compare.
 * @param offset2               The absolute offset within om2 at which
 *                                  to start the comparison.
 * @param len                   The number of bytes to compare.
 *
 * @return                      0 if both mbuf segments are identical;
 *                              A memcmp() return code if the segment
 *                                  contents differ;
 *                              INT_MAX if a specified range extends
 *                                  beyond the end of its corresponding
 *                                  mbuf chain.
 */


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/010602f5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/010602f5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/010602f5

Branch: refs/heads/develop
Commit: 010602f5ba1b485fe9d4c0e2ee475ae4d2173518
Parents: 24deb8d
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Jul 21 12:20:59 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:00 2016 -0700

----------------------------------------------------------------------
 libs/os/include/os/os_mbuf.h |  3 ++
 libs/os/src/os_mbuf.c        | 73 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/010602f5/libs/os/include/os/os_mbuf.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
index 82aef4d..785cafe 100644
--- a/libs/os/include/os/os_mbuf.h
+++ b/libs/os/include/os/os_mbuf.h
@@ -279,6 +279,9 @@ int os_mbuf_free_chain(struct os_mbuf *om);
 void os_mbuf_adj(struct os_mbuf *mp, int req_len);
 int os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data,
                    int len);
+int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
+                 const struct os_mbuf *om2, uint16_t offset2,
+                 uint16_t len);
 
 struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len);
 int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/010602f5/libs/os/src/os_mbuf.c
----------------------------------------------------------------------
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
index 92c8bcc..2703caf 100644
--- a/libs/os/src/os_mbuf.c
+++ b/libs/os/src/os_mbuf.c
@@ -37,6 +37,7 @@
 
 #include <assert.h>
 #include <string.h>
+#include <limits.h>
 
 STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list =
     STAILQ_HEAD_INITIALIZER(g_msys_pool_list);
@@ -826,6 +827,78 @@ os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
 }
 
 /**
+ * Compares the contents of two mbuf chains.  The ranges of the two chains to
+ * be compared are specified via the two offset parameters and the len
+ * parameter.  Neither mbuf chain is required to contain a packet header.
+ *
+ * @param om1                   The first mbuf chain to compare.
+ * @param offset1               The absolute offset within om1 at which to
+ *                                  start the comparison.
+ * @param om2                   The second mbuf chain to compare.
+ * @param offset2               The absolute offset within om2 at which to
+ *                                  start the comparison.
+ * @param len                   The number of bytes to compare.
+ *
+ * @return                      0 if both mbuf segments are identical;
+ *                              A memcmp() return code if the segment contents
+ *                                  differ;
+ *                              INT_MAX if a specified range extends beyond the
+ *                                  end of its corresponding mbuf chain.
+ */
+int
+os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
+             const struct os_mbuf *om2, uint16_t offset2,
+             uint16_t len)
+{
+    const struct os_mbuf *cur1;
+    const struct os_mbuf *cur2;
+    uint16_t bytes_remaining;
+    uint16_t chunk_sz;
+    uint16_t om1_left;
+    uint16_t om2_left;
+    uint16_t om1_off;
+    uint16_t om2_off;
+    int rc;
+
+    cur1 = os_mbuf_off(om1, offset1, &om1_off);
+    cur2 = os_mbuf_off(om2, offset2, &om2_off);
+
+    bytes_remaining = len;
+    while (1) {
+        if (bytes_remaining == 0) {
+            return 0;
+        }
+
+        while (cur1 != NULL && om1_off >= cur1->om_len) {
+            cur1 = SLIST_NEXT(cur1, om_next);
+            om1_off = 0;
+        }
+        while (cur2 != NULL && om2_off >= cur2->om_len) {
+            cur2 = SLIST_NEXT(cur2, om_next);
+            om2_off = 0;
+        }
+
+        if (cur1 == NULL || cur2 == NULL) {
+            return INT_MAX;
+        }
+
+        om1_left = cur1->om_len - om1_off;
+        om2_left = cur2->om_len - om2_off;
+        chunk_sz = min(min(om1_left, om2_left), bytes_remaining);
+
+        rc = memcmp(cur1->om_data + om1_off, cur2->om_data + om2_off,
+                    chunk_sz);
+        if (rc != 0) {
+            return rc;
+        }
+
+        om1_off += chunk_sz;
+        om2_off += chunk_sz;
+        bytes_remaining -= chunk_sz;
+    }
+}
+
+/**
  * Increases the length of an mbuf chain by adding data to the front.  If there
  * is insufficient room in the leading mbuf, additional mbufs are allocated and
  * prepended as necessary.  If this function fails to allocate an mbuf, the


[09/11] incubator-mynewt-core git commit: BLE Host - Use mbufs instead of flat bufs.

Posted by cc...@apache.org.
BLE Host - Use mbufs instead of flat bufs.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/ef7abf7d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/ef7abf7d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/ef7abf7d

Branch: refs/heads/develop
Commit: ef7abf7d06e4cbf90f0e11c0762ee83d7b5a5add
Parents: 6c457ca
Author: Christopher Collins <cc...@apache.org>
Authored: Fri Jul 22 12:02:37 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:01 2016 -0700

----------------------------------------------------------------------
 net/nimble/controller/src/ble_ll_conn.c         |   4 +-
 net/nimble/host/include/host/ble_att.h          |   8 +-
 net/nimble/host/include/host/ble_gap.h          |  14 +-
 net/nimble/host/include/host/ble_gatt.h         |  53 +-
 net/nimble/host/include/host/ble_hs.h           |   3 +
 net/nimble/host/include/host/ble_hs_mbuf.h      |  31 +
 net/nimble/host/include/host/host_hci.h         |   2 +-
 .../host/services/mandatory/src/ble_svc_gap.c   |  37 +-
 .../host/services/mandatory/src/ble_svc_gatt.c  |  10 +-
 net/nimble/host/src/ble_att.c                   |  50 +-
 net/nimble/host/src/ble_att_clt.c               | 741 +++++--------------
 net/nimble/host/src/ble_att_priv.h              |  22 +-
 net/nimble/host/src/ble_att_svr.c               | 642 +++++++---------
 net/nimble/host/src/ble_gap.c                   |   7 +-
 net/nimble/host/src/ble_gap_priv.h              |   3 +-
 net/nimble/host/src/ble_gatt_priv.h             |  12 +-
 net/nimble/host/src/ble_gattc.c                 | 541 ++++++++++----
 net/nimble/host/src/ble_gatts.c                 | 190 +++--
 net/nimble/host/src/ble_hs.c                    |  13 +-
 net/nimble/host/src/ble_hs_mbuf.c               | 171 +++++
 net/nimble/host/src/ble_hs_mbuf_priv.h          |  11 +
 net/nimble/host/src/ble_hs_misc.c               |  41 -
 net/nimble/host/src/ble_hs_priv.h               |   7 +-
 net/nimble/host/src/ble_l2cap.c                 |  18 +-
 net/nimble/host/src/ble_l2cap_priv.h            |   4 +-
 net/nimble/host/src/ble_l2cap_sig.c             |   6 +-
 net/nimble/host/src/ble_l2cap_sig_cmd.c         |  28 +-
 net/nimble/host/src/ble_sm.c                    |  22 +-
 net/nimble/host/src/ble_sm_cmd.c                |  84 ++-
 net/nimble/host/src/ble_sm_sc.c                 |   4 +-
 net/nimble/host/src/host_hci.c                  |  18 +-
 net/nimble/host/src/test/ble_att_clt_test.c     |  21 +-
 net/nimble/host/src/test/ble_att_svr_test.c     | 230 +++---
 net/nimble/host/src/test/ble_gap_test.c         |  20 +
 net/nimble/host/src/test/ble_gatt_conn_test.c   |  55 +-
 net/nimble/host/src/test/ble_gatt_disc_c_test.c |   2 +
 net/nimble/host/src/test/ble_gatt_disc_d_test.c |   2 +
 net/nimble/host/src/test/ble_gatt_disc_s_test.c |   2 +
 net/nimble/host/src/test/ble_gatt_find_s_test.c |   2 +
 net/nimble/host/src/test/ble_gatt_read_test.c   | 208 +++---
 net/nimble/host/src/test/ble_gatt_write_test.c  |  75 +-
 .../host/src/test/ble_gatts_notify_test.c       |  16 +-
 net/nimble/host/src/test/ble_gatts_read_test.c  |  31 +-
 net/nimble/host/src/test/ble_gatts_reg_test.c   |   2 +
 net/nimble/host/src/test/ble_host_hci_test.c    |   2 +
 net/nimble/host/src/test/ble_hs_adv_test.c      |   2 +
 net/nimble/host/src/test/ble_hs_conn_test.c     |   2 +
 net/nimble/host/src/test/ble_hs_test_util.c     | 204 ++++-
 net/nimble/host/src/test/ble_hs_test_util.h     |  33 +
 net/nimble/host/src/test/ble_l2cap_test.c       |   8 +-
 net/nimble/host/src/test/ble_os_test.c          |   2 +
 net/nimble/host/src/test/ble_sm_lgcy_test.c     |   2 +
 net/nimble/host/src/test/ble_sm_sc_test.c       |   2 +
 net/nimble/host/src/test/ble_sm_test.c          |   2 +
 net/nimble/host/src/test/ble_sm_test_util.c     |  22 +-
 net/nimble/host/src/test/ble_uuid_test.c        |   5 +-
 net/nimble/include/nimble/nimble_opt.h          |   8 +
 57 files changed, 2096 insertions(+), 1661 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index ca94310..811b51f 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -104,7 +104,7 @@ extern void bletest_completed_pkt(uint16_t handle);
  */
 
 /* XXX: this does not belong here! Move to transport? */
-extern int ble_hs_rx_data(struct os_mbuf *om);
+extern int ble_hs_rx_data(struct os_mbuf **om);
 
 /*
  * The amount of time that we will wait to hear the start of a receive
@@ -2569,7 +2569,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
                     acl_hdr = (acl_hdr << 12) | connsm->conn_handle;
                     htole16(rxbuf, acl_hdr);
                     htole16(rxbuf + 2, acl_len);
-                    ble_hs_rx_data(rxpdu);
+                    ble_hs_rx_data(&rxpdu);
                 }
 
                 /* NOTE: we dont free the mbuf since we handed it off! */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/include/host/ble_att.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_att.h b/net/nimble/host/include/host/ble_att.h
index 5ce4123..3bccea5 100644
--- a/net/nimble/host/include/host/ble_att.h
+++ b/net/nimble/host/include/host/ble_att.h
@@ -21,6 +21,7 @@
 #define H_BLE_ATT_
 
 #include "os/queue.h"
+struct os_mbuf;
 
 #define BLE_ATT_UUID_PRIMARY_SERVICE        0x2800
 #define BLE_ATT_UUID_SECONDARY_SERVICE      0x2801
@@ -167,11 +168,10 @@ struct ble_att_svr_access_ctxt {
     };
 };
 
-int ble_att_svr_read_local(uint16_t attr_handle, const void **out_data,
-                           uint16_t *out_attr_len);
-int ble_att_svr_write_local(uint16_t attr_handle, const void *data,
-                            uint16_t data_len);
+int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om);
+int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf **om);
 
+uint16_t ble_att_mtu(uint16_t conn_handle);
 int ble_att_set_preferred_mtu(uint16_t mtu);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/include/host/ble_gap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h
index 8cd4402..46854e0 100644
--- a/net/nimble/host/include/host/ble_gap.h
+++ b/net/nimble/host/include/host/ble_gap.h
@@ -315,6 +315,9 @@ struct ble_gap_event {
          *     o L2CAP Connection Parameter Update Procedure
          *     o Link-Layer Connection Parameters Request Procedure
          *
+         * To reject the request, return a non-zero HCI error code.  The value
+         * returned is the reject reason given to the controller.
+         *
          * Valid for the following event types:
          *     o BLE_GAP_EVENT_L2CAP_UPDATE_REQ
          *     o BLE_GAP_EVENT_CONN_UPDATE_REQ
@@ -395,15 +398,16 @@ struct ble_gap_event {
          *     o BLE_GAP_EVENT_NOTIFY_RX
          */
         struct {
-            /** The contents of the notification or indication. */
-            void *attr_data;
+            /**
+             * The contents of the notification or indication.  If the
+             * application wishes to retain this mbuf for later use, it must
+             * set this pointer to NULL to prevent the stack from freeing it.
+             */
+            struct os_mbuf *om;
 
             /** The handle of the relevant ATT attribute. */
             uint16_t attr_handle;
 
-            /** The number of data bytes contained in the message. */
-            uint16_t attr_len;
-
             /** The handle of the relevant connection. */
             uint16_t conn_handle;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 0f1310c..3695401 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -82,8 +82,7 @@ struct ble_gatt_svc {
 struct ble_gatt_attr {
     uint16_t handle;
     uint16_t offset;
-    uint16_t value_len;
-    const void *value;
+    struct os_mbuf *om;
 };
 
 struct ble_gatt_chr {
@@ -107,11 +106,11 @@ typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle,
                                  void *arg);
 typedef int ble_gatt_attr_fn(uint16_t conn_handle,
                              const struct ble_gatt_error *error,
-                             const struct ble_gatt_attr *attr,
+                             struct ble_gatt_attr *attr,
                              void *arg);
 typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle,
                                       const struct ble_gatt_error *error,
-                                      const struct ble_gatt_attr *attrs,
+                                      struct ble_gatt_attr *attrs,
                                       uint8_t num_attrs, void *arg);
 
 typedef int ble_gatt_chr_fn(uint16_t conn_handle,
@@ -153,29 +152,26 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
                         uint8_t num_handles, ble_gatt_attr_fn *cb,
                         void *cb_arg);
 int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
-                           const void *value, uint16_t value_len);
+                           struct os_mbuf **om);
+int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
+                                const void *data, uint16_t data_len);
 int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
-                    const void *value, uint16_t value_len,
+                    struct os_mbuf **om,
                     ble_gatt_attr_fn *cb, void *cb_arg);
+int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
+                         const void *data, uint16_t data_len,
+                         ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
-                         const void *value, uint16_t value_len,
+                         struct os_mbuf **om,
                          ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_write_reliable(uint16_t conn_handle,
-                             const struct ble_gatt_attr *attrs,
+                             struct ble_gatt_attr *attrs,
                              int num_attrs, ble_gatt_reliable_attr_fn *cb,
                              void *cb_arg);
-int ble_gattc_read_dsc(uint16_t conn_handle, uint16_t attr_handle,
-                       ble_gatt_attr_fn *cb, void *cb_arg);
-int ble_gattc_read_long_dsc(uint16_t conn_handle, uint16_t attr_handle,
-                            ble_gatt_attr_fn *cb, void *cb_arg);
-int ble_gattc_write_dsc(uint16_t conn_handle, uint16_t attr_handle,
-                        const void *value, uint16_t value_len,
-                        ble_gatt_attr_fn *cb, void *cb_arg);
-int ble_gattc_write_long_dsc(uint16_t conn_handle, uint16_t attr_handle,
-                             const void *value, uint16_t value_len,
-                             ble_gatt_attr_fn *cb, void *cb_arg);
 int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
-                            const void *attr_data, uint16_t attr_data_len);
+                            struct os_mbuf **om);
+int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
+int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle);
 
 int ble_gattc_init(void);
 
@@ -266,9 +262,20 @@ struct ble_gatt_access_ctxt {
     uint8_t op;
 
     /**
+     * A container for the GATT access data.
+     *     o For reads: The application populates this with the value of the
+     *       characteristic or descriptor being read.
+     *     o For writes: This is already populated with the value being written
+     *       by the peer.  If the application wishes to retain this mbuf for
+     *       later use, it must set this pointer to NULL to prevent the stack
+     *       from freeing it.
+     */
+    struct os_mbuf *om;
+
+    /**
      * The GATT operation being performed dictates which field in this union is
      * valid.  If a characteristic is being accessed, the chr field is valid.
-     * Otherwise, a descriptor is being accessed, in which case the dsc field
+     * Otherwise a descriptor is being accessed, in which case the dsc field
      * is valid.
      */
     union {
@@ -284,12 +291,6 @@ struct ble_gatt_access_ctxt {
          */
         const struct ble_gatt_dsc_def *dsc;
     };
-
-    /**
-     * Context describing the underlying ATT access.  Specifies additional
-     * details about the read or write being performed.
-     */
-    struct ble_att_svr_access_ctxt *att;
 };
 
 struct ble_gatt_dsc_def {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/include/host/ble_hs.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_hs.h b/net/nimble/host/include/host/ble_hs.h
index dbc8a5b..ec1b3d8 100644
--- a/net/nimble/host/include/host/ble_hs.h
+++ b/net/nimble/host/include/host/ble_hs.h
@@ -26,8 +26,10 @@
 #include "host/ble_gatt.h"
 #include "host/ble_hs.h"
 #include "host/ble_hs_adv.h"
+#include "host/ble_hs_id.h"
 #include "host/ble_hs_log.h"
 #include "host/ble_hs_test.h"
+#include "host/ble_hs_mbuf.h"
 #include "host/ble_sm.h"
 #include "host/ble_store.h"
 #include "host/ble_uuid.h"
@@ -216,6 +218,7 @@ struct ble_hs_cfg {
 
 extern const struct ble_hs_cfg ble_hs_cfg_dflt;
 
+int ble_hs_rx_data(struct os_mbuf **om);
 int ble_hs_start(void);
 void ble_hs_event_enqueue(struct os_event *ev);
 int ble_hs_init(struct os_eventq *app_evq, struct ble_hs_cfg *cfg);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/include/host/ble_hs_mbuf.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_hs_mbuf.h b/net/nimble/host/include/host/ble_hs_mbuf.h
new file mode 100644
index 0000000..d3606f2
--- /dev/null
+++ b/net/nimble/host/include/host/ble_hs_mbuf.h
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+#ifndef H_BLE_HS_MBUF_
+#define H_BLE_HS_MBUF_
+
+#include <inttypes.h>
+struct os_mbuf;
+
+struct os_mbuf *ble_hs_mbuf_att_pkt(void);
+struct os_mbuf *ble_hs_mbuf_from_flat(const void *buf, uint16_t len);
+int ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
+                        uint16_t *out_copy_len);
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index 1bf3c06..bcec2ef 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -104,7 +104,7 @@ int host_hci_set_buf_size(uint16_t pktlen, uint8_t max_pkts);
 uint16_t host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc);
 
 int host_hci_data_rx(struct os_mbuf *om);
-int host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om);
+int host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf **txom);
 
 int host_hci_cmd_build_set_data_len(uint16_t connection_handle,
                                     uint16_t tx_octets, uint16_t tx_time,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/services/mandatory/src/ble_svc_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/services/mandatory/src/ble_svc_gap.c b/net/nimble/host/services/mandatory/src/ble_svc_gap.c
index 0afc5fc..d5d50f3 100644
--- a/net/nimble/host/services/mandatory/src/ble_svc_gap.c
+++ b/net/nimble/host/services/mandatory/src/ble_svc_gap.c
@@ -81,6 +81,7 @@ ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
                    struct ble_gatt_access_ctxt *ctxt, void *arg)
 {
     uint16_t uuid16;
+    int rc;
 
     uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128);
     assert(uuid16 != 0);
@@ -88,43 +89,41 @@ ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
     switch (uuid16) {
     case BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = ble_svc_gap_name;
-        ctxt->att->read.len = strlen(ble_svc_gap_name);
-        break;
+        rc = os_mbuf_append(ctxt->om, ble_svc_gap_name,
+                            strlen(ble_svc_gap_name));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case BLE_SVC_GAP_CHR_UUID16_APPEARANCE:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &ble_svc_gap_appearance;
-        ctxt->att->read.len = sizeof ble_svc_gap_appearance;
-        break;
+        rc = os_mbuf_append(ctxt->om, &ble_svc_gap_appearance,
+                            sizeof ble_svc_gap_appearance);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case BLE_SVC_GAP_CHR_UUID16_PERIPH_PRIV_FLAG:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &ble_svc_gap_privacy_flag;
-        ctxt->att->read.len = sizeof ble_svc_gap_privacy_flag;
-        break;
+        rc = os_mbuf_append(ctxt->om, &ble_svc_gap_privacy_flag,
+                            sizeof ble_svc_gap_privacy_flag);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-        if (ctxt->att->write.len != sizeof ble_svc_gap_reconnect_addr) {
+        if (OS_MBUF_PKTLEN(ctxt->om) != sizeof ble_svc_gap_reconnect_addr) {
             return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
         }
-        memcpy(ble_svc_gap_reconnect_addr, ctxt->att->write.data,
-               sizeof ble_svc_gap_reconnect_addr);
-        break;
+        ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_reconnect_addr,
+                            sizeof ble_svc_gap_reconnect_addr, NULL);
+        return 0;
 
     case BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &ble_svc_gap_pref_conn_params;
-        ctxt->att->read.len = sizeof ble_svc_gap_pref_conn_params;
-        break;
+        rc = os_mbuf_append(ctxt->om, &ble_svc_gap_pref_conn_params,
+                            sizeof ble_svc_gap_pref_conn_params);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     default:
         assert(0);
-        break;
+        return BLE_ATT_ERR_UNLIKELY;
     }
-
-    return 0;
 }
 
 const char *

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/services/mandatory/src/ble_svc_gatt.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/services/mandatory/src/ble_svc_gatt.c b/net/nimble/host/services/mandatory/src/ble_svc_gatt.c
index 566efd8..704f849 100644
--- a/net/nimble/host/services/mandatory/src/ble_svc_gatt.c
+++ b/net/nimble/host/services/mandatory/src/ble_svc_gatt.c
@@ -49,6 +49,8 @@ static int
 ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
                     struct ble_gatt_access_ctxt *ctxt, void *arg)
 {
+    uint8_t *u8;
+
     /* The only operation allowed for this characteristic is indicate.  This
      * access callback gets called by the stack when it needs to read the
      * characteristic value to populate the outgoing indication command.
@@ -59,8 +61,12 @@ ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
     assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[0]);
 
     /* XXX: For now, always respond with 0 (unchanged). */
-    ctxt->att->read.buf[0] = 0;
-    ctxt->att->read.len = 1;
+    u8 = os_mbuf_extend(ctxt->om, 1);
+    if (u8 == NULL) {
+        return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    *u8 = 0;
 
     return 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_att.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att.c b/net/nimble/host/src/ble_att.c
index 6866bc1..1743a4f 100644
--- a/net/nimble/host/src/ble_att.c
+++ b/net/nimble/host/src/ble_att.c
@@ -22,8 +22,6 @@
 #include "bsp/bsp.h"
 #include "ble_hs_priv.h"
 
-static bssnz_t uint8_t ble_att_flat_buf[BLE_ATT_ATTR_MAX_LEN];
-
 static uint16_t ble_att_preferred_mtu;
 
 /** Dispatch table for incoming ATT requests.  Sorted by op code. */
@@ -390,17 +388,29 @@ ble_att_inc_rx_stat(uint8_t att_op)
     }
 }
 
-/**
- * Retrieves a pointer to the global ATT flat buffer.  This buffer is only used
- * by the host parent task, so users can assume exclusive access.
- */
-uint8_t *
-ble_att_get_flat_buf(void)
+void
+ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan,
+                        struct os_mbuf *txom)
 {
-    BLE_HS_DBG_ASSERT(ble_hs_is_parent_task());
-    return ble_att_flat_buf;
+    int32_t extra_len;
+    uint16_t mtu;
+
+    mtu = ble_l2cap_chan_mtu(att_chan);
+    extra_len = OS_MBUF_PKTLEN(txom) - mtu;
+    if (extra_len > 0) {
+        os_mbuf_adj(txom, -extra_len);
+    }
 }
 
+/**
+ * Retrieves the ATT MTU of the specified connection.  If an MTU exchange for
+ * this connection has occurred, the MTU is the lower of the two peers'
+ * preferred values.  Otherwise, the MTU is the default value of 23.
+ *
+ * @param conn_handle           The handle of the connection to query.
+ *
+ * @return                      The specified connection's ATT MTU.
+ */
 uint16_t
 ble_att_mtu(uint16_t conn_handle)
 {
@@ -422,6 +432,16 @@ ble_att_mtu(uint16_t conn_handle)
     return mtu;
 }
 
+void
+ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu)
+{
+    if (peer_mtu < BLE_ATT_MTU_DFLT) {
+        peer_mtu = BLE_ATT_MTU_DFLT;
+    }
+
+    chan->blc_peer_mtu = peer_mtu;
+}
+
 static int
 ble_att_rx(uint16_t conn_handle, struct os_mbuf **om)
 {
@@ -449,16 +469,6 @@ ble_att_rx(uint16_t conn_handle, struct os_mbuf **om)
     return 0;
 }
 
-void
-ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu)
-{
-    if (peer_mtu < BLE_ATT_MTU_DFLT) {
-        peer_mtu = BLE_ATT_MTU_DFLT;
-    }
-
-    chan->blc_peer_mtu = peer_mtu;
-}
-
 /**
  * Sets the preferred ATT MTU; the device will indicate this value in all
  * subseqeunt ATT MTU exchanges.  The ATT MTU of a connection is equal to the

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 cb5acc7..5687a99 100644
--- a/net/nimble/host/src/ble_att_clt.c
+++ b/net/nimble/host/src/ble_att_clt.c
@@ -29,110 +29,61 @@
 static int
 ble_att_clt_init_req(uint16_t initial_sz, struct os_mbuf **out_txom)
 {
+    struct os_mbuf *om;
     void *buf;
     int rc;
 
-    *out_txom = ble_hs_misc_pkthdr();
-    if (*out_txom == NULL) {
+    *out_txom = NULL;
+
+    om = ble_hs_mbuf_l2cap_pkt();
+    if (om == NULL) {
         rc = BLE_HS_ENOMEM;
         goto err;
     }
 
-    buf = os_mbuf_extend(*out_txom, initial_sz);
+    buf = os_mbuf_extend(om, initial_sz);
     if (buf == NULL) {
         rc = BLE_HS_ENOMEM;
         goto err;
     }
 
     /* The caller expects the initial buffer to be at the start of the mbuf. */
-    BLE_HS_DBG_ASSERT(buf == (*out_txom)->om_data);
+    BLE_HS_DBG_ASSERT(buf == om->om_data);
 
+    *out_txom = om;
     return 0;
 
 err:
-    os_mbuf_free_chain(*out_txom);
-    *out_txom = NULL;
+    os_mbuf_free_chain(om);
     return rc;
 }
 
 static int
-ble_att_clt_append_blob(uint16_t conn_handle, struct os_mbuf *txom,
-                        const void *blob, int blob_len)
-{
-    int rc;
-
-    if (blob_len < 0) {
-        return BLE_HS_EINVAL;
-    }
-    if (blob_len == 0) {
-        return 0;
-    }
-
-    rc = os_mbuf_append(txom, blob, blob_len);
-    if (rc != 0) {
-        return rc;
-    }
-
-    return 0;
-}
-
-static int
-ble_att_clt_copy_attr_to_flatbuf(const struct os_mbuf *om, void **out_attr_val,
-                                 uint16_t *out_attr_len)
-{
-    uint8_t *flat_buf;
-    uint16_t attr_len;
-
-    /* Make sure the attribute value isn't too big. */
-    attr_len = OS_MBUF_PKTLEN(om);
-    if (attr_len > BLE_ATT_ATTR_MAX_LEN) {
-        *out_attr_len = 0;
-        *out_attr_val = NULL;
-        return BLE_HS_EBADDATA;
-    }
-
-    /* Copy the attribute data into the global ATT flat buffer. */
-    flat_buf = ble_att_get_flat_buf();
-    os_mbuf_copydata(om, 0, attr_len, flat_buf);
-    *out_attr_val = flat_buf;
-    *out_attr_len = attr_len;
-    return 0;
-}
-
-static int
-ble_att_clt_tx_req(uint16_t conn_handle, struct os_mbuf *txom)
+ble_att_clt_tx_req(uint16_t conn_handle, struct os_mbuf **txom)
 {
     struct ble_l2cap_chan *chan;
     struct ble_hs_conn *conn;
-    uint16_t total_len;
-    uint16_t mtu;
-    int extra_len;
+    struct os_mbuf *om;
     int rc;
 
-    BLE_HS_DBG_ASSERT_EVAL(txom->om_len >= 1);
-    ble_att_inc_tx_stat(txom->om_data[0]);
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
+    BLE_HS_DBG_ASSERT_EVAL(om->om_len >= 1);
+    ble_att_inc_tx_stat(om->om_data[0]);
 
     ble_hs_lock();
 
     rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
     if (rc == 0) {
-        /* Reduce the size of the transmission to fit the connection's ATT
-         * MTU.
-         */
-        total_len = OS_MBUF_PKTLEN(txom);
-        mtu = ble_l2cap_chan_mtu(chan);
-        extra_len = total_len - mtu;
-        if (extra_len > 0) {
-            os_mbuf_adj(txom, -extra_len);
-        }
-
-        rc = ble_l2cap_tx(conn, chan, txom);
-        txom = NULL;
+        ble_att_truncate_to_mtu(chan, om);
+        rc = ble_l2cap_tx(conn, chan, &om);
     }
 
     ble_hs_unlock();
 
-    os_mbuf_free_chain(txom);
+    os_mbuf_free_chain(om);
     return rc;
 }
 
@@ -146,7 +97,7 @@ ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom)
     struct ble_att_error_rsp rsp;
     int rc;
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_ERROR_RSP_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_ERROR_RSP_SZ);
     if (rc != 0) {
         return rc;
     }
@@ -163,32 +114,6 @@ ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom)
  * $mtu exchange                                                             *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_mtu_req(const struct ble_att_mtu_cmd *req,
-                          struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_MTU_CMD_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_mtu_req_write(txom->om_data, txom->om_len, req);
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_mtu(uint16_t conn_handle, const struct ble_att_mtu_cmd *req)
 {
@@ -203,12 +128,13 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, const struct ble_att_mtu_cmd *req)
         return BLE_HS_EINVAL;
     }
 
-    rc = ble_att_clt_build_mtu_req(req, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_MTU_CMD_SZ, &txom);
     if (rc != 0) {
         return rc;
     }
+    ble_att_mtu_req_write(txom->om_data, txom->om_len, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -235,7 +161,7 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
 
     mtu = 0;
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_MTU_CMD_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_MTU_CMD_SZ);
     if (rc == 0) {
         ble_att_mtu_cmd_parse((*rxom)->om_data, (*rxom)->om_len, &cmd);
         BLE_ATT_LOG_CMD(0, "mtu rsp", conn_handle, ble_att_mtu_cmd_log, &cmd);
@@ -259,24 +185,6 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
  * $find information                                                         *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_find_info_req(const struct ble_att_find_info_req *req,
-                                struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    rc = ble_att_clt_init_req(BLE_ATT_FIND_INFO_REQ_SZ, &txom);
-    if (rc != 0) {
-        return rc;
-    }
-
-    ble_att_find_info_req_write(txom->om_data, txom->om_len, req);
-    *out_txom = txom;
-
-    return 0;
-}
-
 int
 ble_att_clt_tx_find_info(uint16_t conn_handle,
                          const struct ble_att_find_info_req *req)
@@ -297,12 +205,13 @@ ble_att_clt_tx_find_info(uint16_t conn_handle,
         return BLE_HS_EINVAL;
     }
 
-    rc = ble_att_clt_build_find_info_req(req, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_FIND_INFO_REQ_SZ, &txom);
     if (rc != 0) {
         return rc;
     }
+    ble_att_find_info_req_write(txom->om_data, txom->om_len, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -331,7 +240,7 @@ ble_att_clt_parse_find_info_entry(struct os_mbuf **rxom, uint8_t rsp_format,
         return BLE_HS_EBADDATA;
     }
 
-    rc = ble_hs_misc_pullup_base(rxom, entry_len);
+    rc = ble_hs_mbuf_pullup_base(rxom, entry_len);
     if (rc != 0) {
         return rc;
     }
@@ -374,7 +283,7 @@ ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om)
     struct ble_att_find_info_rsp rsp;
     int rc;
 
-    rc = ble_hs_misc_pullup_base(om, BLE_ATT_FIND_INFO_RSP_BASE_SZ);
+    rc = ble_hs_mbuf_pullup_base(om, BLE_ATT_FIND_INFO_RSP_BASE_SZ);
     if (rc != 0) {
         goto done;
     }
@@ -408,31 +317,6 @@ done:
  * $find by type value                                                       *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_find_type_value_req(
-    const struct ble_att_find_type_value_req *req,
-    const void *attribute_value, int value_len,
-    struct os_mbuf **out_txom)
-{
-    int rc;
-
-    rc = ble_att_clt_init_req(BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, out_txom);
-    if (rc != 0) {
-        return rc;
-    }
-
-    ble_att_find_type_value_req_write((*out_txom)->om_data,
-                                      (*out_txom)->om_len,
-                                      req);
-    rc = os_mbuf_append(*out_txom, attribute_value, value_len);
-    if (rc != 0) {
-        os_mbuf_free_chain(*out_txom);
-        return BLE_HS_ENOMEM;
-    }
-
-    return 0;
-}
-
 int
 ble_att_clt_tx_find_type_value(uint16_t conn_handle,
                                const struct ble_att_find_type_value_req *req,
@@ -448,24 +332,35 @@ ble_att_clt_tx_find_type_value(uint16_t conn_handle,
     struct os_mbuf *txom;
     int rc;
 
+    txom = NULL;
+
     if (req->bavq_start_handle == 0 ||
         req->bavq_start_handle > req->bavq_end_handle) {
 
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    rc = ble_att_clt_build_find_type_value_req(req, attribute_value, value_len,
-                                               &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, &txom);
     if (rc != 0) {
-        return rc;
+        goto done;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    ble_att_find_type_value_req_write(txom->om_data, txom->om_len, req);
+    rc = os_mbuf_append(txom, attribute_value, value_len);
     if (rc != 0) {
-        return rc;
+        rc = BLE_HS_ENOMEM;
+        goto done;
     }
 
-    return 0;
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
+
+done:
+    os_mbuf_free_chain(txom);
+    return rc;
 }
 
 static int
@@ -525,38 +420,6 @@ ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
  * $read by type                                                             *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_read_type_req(const struct ble_att_read_type_req *req,
-                                const void *uuid128, struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_READ_TYPE_REQ_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_read_type_req_write(txom->om_data, txom->om_len, req);
-
-    rc = ble_uuid_append(txom, uuid128);
-    if (rc != 0) {
-        rc = BLE_HS_ENOMEM;
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_read_type(uint16_t conn_handle,
                          const struct ble_att_read_type_req *req,
@@ -569,25 +432,37 @@ ble_att_clt_tx_read_type(uint16_t conn_handle,
     struct os_mbuf *txom;
     int rc;
 
+    txom = NULL;
+
     BLE_ATT_LOG_CMD(1, "read type req", conn_handle,
                     ble_att_read_type_req_log, req);
 
     if (req->batq_start_handle == 0 ||
         req->batq_start_handle > req->batq_end_handle) {
 
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    rc = ble_att_clt_build_read_type_req(req, uuid128, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_READ_TYPE_REQ_BASE_SZ, &txom);
     if (rc != 0) {
-        return rc;
+        goto done;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    ble_att_read_type_req_write(txom->om_data, txom->om_len, req);
+    rc = ble_uuid_append(txom, uuid128);
     if (rc != 0) {
-        return rc;
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
     }
 
+done:
+    os_mbuf_free_chain(txom);
     return 0;
 }
 
@@ -597,7 +472,7 @@ ble_att_clt_parse_read_type_adata(struct os_mbuf **om, int data_len,
 {
     int rc;
 
-    rc = ble_hs_misc_pullup_base(om, data_len);
+    rc = ble_hs_mbuf_pullup_base(om, data_len);
     if (rc != 0) {
         return rc;
     }
@@ -620,7 +495,7 @@ ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
     struct ble_att_read_type_rsp rsp;
     int rc;
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_READ_TYPE_RSP_BASE_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_READ_TYPE_RSP_BASE_SZ);
     if (rc != 0) {
         goto done;
     }
@@ -654,32 +529,6 @@ done:
  * $read                                                                     *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_read_req(const struct ble_att_read_req *req,
-                           struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_READ_REQ_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_read_req_write(txom->om_data, txom->om_len, req);
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_read(uint16_t conn_handle, const struct ble_att_read_req *req)
 {
@@ -690,19 +539,19 @@ ble_att_clt_tx_read(uint16_t conn_handle, const struct ble_att_read_req *req)
     struct os_mbuf *txom;
     int rc;
 
-    BLE_ATT_LOG_CMD(1, "read req", conn_handle,
-                    ble_att_read_req_log, req);
+    BLE_ATT_LOG_CMD(1, "read req", conn_handle, ble_att_read_req_log, req);
 
     if (req->barq_handle == 0) {
         return BLE_HS_EINVAL;
     }
 
-    rc = ble_att_clt_build_read_req(req, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_READ_REQ_SZ, &txom);
     if (rc != 0) {
         return rc;
     }
+    ble_att_read_req_write(txom->om_data, txom->om_len, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -717,10 +566,6 @@ ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    uint16_t value_len;
-    void *value;
-    int rc;
-
     BLE_ATT_LOG_EMPTY_CMD(0, "read rsp", conn_handle);
 
     /* Reponse consists of a one-byte opcode (already verified) and a variable
@@ -728,44 +573,15 @@ ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
      */
     os_mbuf_adj(*rxom, BLE_ATT_READ_RSP_BASE_SZ);
 
-    /* Copy the attribute data into the global ATT flat buffer. */
-    rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len);
-
     /* Pass the Attribute Value field to GATT. */
-    ble_gattc_rx_read_rsp(conn_handle, rc, value, value_len);
-    return rc;
+    ble_gattc_rx_read_rsp(conn_handle, 0, rxom);
+    return 0;
 }
 
 /*****************************************************************************
  * $read blob                                                                *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_read_blob_req(const struct ble_att_read_blob_req *req,
-                                struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_READ_BLOB_REQ_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_read_blob_req_write(txom->om_data, txom->om_len, req);
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_read_blob(uint16_t conn_handle,
                          const struct ble_att_read_blob_req *req)
@@ -784,12 +600,13 @@ ble_att_clt_tx_read_blob(uint16_t conn_handle,
         return BLE_HS_EINVAL;
     }
 
-    rc = ble_att_clt_build_read_blob_req(req, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_READ_BLOB_REQ_SZ, &txom);
     if (rc != 0) {
         return rc;
     }
+    ble_att_read_blob_req_write(txom->om_data, txom->om_len, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -804,10 +621,6 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    uint16_t value_len;
-    void *value;
-    int rc;
-
     BLE_ATT_LOG_EMPTY_CMD(0, "read blob rsp", conn_handle);
 
     /* Reponse consists of a one-byte opcode (already verified) and a variable
@@ -815,12 +628,9 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
      */
     os_mbuf_adj(*rxom, BLE_ATT_READ_BLOB_RSP_BASE_SZ);
 
-    /* Copy the attribute data into the global ATT flat buffer. */
-    rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len);
-
     /* Pass the Attribute Value field to GATT. */
-    ble_gattc_rx_read_blob_rsp(conn_handle, rc, value, value_len);
-    return rc;
+    ble_gattc_rx_read_blob_rsp(conn_handle, 0, rxom);
+    return 0;
 }
 
 /*****************************************************************************
@@ -837,34 +647,29 @@ ble_att_clt_build_read_mult_req(const uint16_t *att_handles,
     int rc;
     int i;
 
-    txom = NULL;
+    *out_txom = NULL;
 
     rc = ble_att_clt_init_req(BLE_ATT_READ_MULT_REQ_BASE_SZ, &txom);
     if (rc != 0) {
-        goto done;
+        goto err;
     }
-
     ble_att_read_mult_req_write(txom->om_data, txom->om_len);
 
     for (i = 0; i < num_att_handles; i++) {
         buf = os_mbuf_extend(txom, 2);
         if (buf == NULL) {
             rc = BLE_HS_ENOMEM;
-            goto done;
+            goto err;
         }
 
         htole16(buf, att_handles[i]);
     }
 
-    rc = 0;
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
     *out_txom = txom;
+    return 0;
+
+err:
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -890,7 +695,7 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *att_handles,
         return rc;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -905,10 +710,6 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    uint16_t value_len;
-    void *value;
-    int rc;
-
     BLE_ATT_LOG_EMPTY_CMD(0, "read mult rsp", conn_handle);
 
     /* Reponse consists of a one-byte opcode (already verified) and a variable
@@ -916,50 +717,15 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
      */
     os_mbuf_adj(*rxom, BLE_ATT_READ_MULT_RSP_BASE_SZ);
 
-    /* Copy the attribute data into the global ATT flat buffer. */
-    rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len);
-
     /* Pass the Attribute Value field to GATT. */
-    ble_gattc_rx_read_mult_rsp(conn_handle, rc, value, value_len);
-    return rc;
+    ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom);
+    return 0;
 }
 
 /*****************************************************************************
  * $read by group type                                                       *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_read_group_type_req(
-    const struct ble_att_read_group_type_req *req, const void *uuid128,
-    struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_read_group_type_req_write(txom->om_data, txom->om_len, req);
-
-    rc = ble_uuid_append(txom, uuid128);
-    if (rc != 0) {
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_read_group_type(uint16_t conn_handle,
                                const struct ble_att_read_group_type_req *req,
@@ -980,20 +746,29 @@ ble_att_clt_tx_read_group_type(uint16_t conn_handle,
     if (req->bagq_start_handle == 0 ||
         req->bagq_start_handle > req->bagq_end_handle) {
 
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    rc = ble_att_clt_build_read_group_type_req(req, uuid128, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, &txom);
     if (rc != 0) {
-        return rc;
+        goto done;
+    }
+    ble_att_read_group_type_req_write(txom->om_data, txom->om_len, req);
+
+    rc = ble_uuid_append(txom, uuid128);
+    if (rc != 0) {
+        goto done;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
-        return rc;
+        goto done;
     }
 
-    return 0;
+done:
+    os_mbuf_free_chain(txom);
+    return rc;
 }
 
 static int
@@ -1007,7 +782,7 @@ ble_att_clt_parse_read_group_type_adata(
         return BLE_HS_EMSGSIZE;
     }
 
-    rc = ble_hs_misc_pullup_base(om, data_len);
+    rc = ble_hs_mbuf_pullup_base(om, data_len);
     if (rc != 0) {
         return rc;
     }
@@ -1031,7 +806,7 @@ ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
     struct ble_att_read_group_type_rsp rsp;
     int rc;
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ);
     if (rc != 0) {
         goto done;
     }
@@ -1066,59 +841,29 @@ done:
  *****************************************************************************/
 
 static int
-ble_att_clt_build_write_req_or_cmd(uint16_t conn_handle,
-                                   const struct ble_att_write_req *req,
-                                   const void *value, uint16_t value_len,
-                                   int is_req,
-                                   struct os_mbuf **out_txom)
+ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle,
+                                const struct ble_att_write_req *req,
+                                struct os_mbuf **txom, int is_req)
 {
-    struct os_mbuf *txom;
+    struct os_mbuf *om;
     int rc;
 
-    txom = NULL;
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
 
-    rc = ble_att_clt_init_req(BLE_ATT_WRITE_REQ_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
+    om = os_mbuf_prepend_pullup(om, BLE_ATT_WRITE_REQ_BASE_SZ);
+    if (om == NULL) {
+        return BLE_HS_ENOMEM;
     }
 
     if (is_req) {
-        ble_att_write_req_write(txom->om_data, txom->om_len, req);
+        ble_att_write_req_write(om->om_data, BLE_ATT_WRITE_REQ_BASE_SZ, req);
     } else {
-        ble_att_write_cmd_write(txom->om_data, txom->om_len, req);
-    }
-
-    rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len);
-    if (rc != 0) {
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
-static int
-ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle,
-                                const struct ble_att_write_req *req,
-                                const void *value, uint16_t value_len,
-                                int is_req)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    rc = ble_att_clt_build_write_req_or_cmd(conn_handle, req, value, value_len,
-                                            is_req, &txom);
-    if (rc != 0) {
-        return rc;
+        ble_att_write_cmd_write(om->om_data, BLE_ATT_WRITE_REQ_BASE_SZ, req);
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &om);
     if (rc != 0) {
         return rc;
     }
@@ -1129,7 +874,7 @@ ble_att_clt_tx_write_req_or_cmd(uint16_t conn_handle,
 int
 ble_att_clt_tx_write_req(uint16_t conn_handle,
                          const struct ble_att_write_req *req,
-                         const void *value, uint16_t value_len)
+                         struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(ATT_CLT_WRITE)
     return BLE_HS_ENOTSUP;
@@ -1139,15 +884,14 @@ ble_att_clt_tx_write_req(uint16_t conn_handle,
 
     BLE_ATT_LOG_CMD(1, "write req", conn_handle, ble_att_write_cmd_log, req);
 
-    rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, value, value_len,
-                                         1);
+    rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, txom, 1);
     return rc;
 }
 
 int
 ble_att_clt_tx_write_cmd(uint16_t conn_handle,
                          const struct ble_att_write_req *req,
-                         const void *value, uint16_t value_len)
+                         struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(ATT_CLT_WRITE_NO_RSP)
     return BLE_HS_ENOTSUP;
@@ -1157,8 +901,7 @@ ble_att_clt_tx_write_cmd(uint16_t conn_handle,
 
     BLE_ATT_LOG_CMD(1, "write cmd", conn_handle, ble_att_write_cmd_log, req);
 
-    rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, value, value_len,
-                                         0);
+    rc = ble_att_clt_tx_write_req_or_cmd(conn_handle, req, txom, 0);
     return rc;
 }
 
@@ -1180,80 +923,59 @@ ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
  * $prepare write request                                                    *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_prep_write_req(uint16_t conn_handle,
-                                 const struct ble_att_prep_write_cmd *req,
-                                 const void *value, uint16_t value_len,
-                                 struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_PREP_WRITE_CMD_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_prep_write_req_write(txom->om_data, txom->om_len, req);
-
-    rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len);
-    if (rc != 0) {
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_prep_write(uint16_t conn_handle,
                           const struct ble_att_prep_write_cmd *req,
-                          const void *value, uint16_t value_len)
+                          struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(ATT_CLT_PREP_WRITE)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct os_mbuf *txom;
+    struct os_mbuf *om;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     BLE_ATT_LOG_CMD(1, "prep write req", conn_handle,
                     ble_att_prep_write_cmd_log, req);
 
     if (req->bapc_handle == 0) {
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    if (req->bapc_offset + value_len > BLE_ATT_ATTR_MAX_LEN) {
-        return BLE_HS_EINVAL;
+    if (req->bapc_offset + OS_MBUF_PKTLEN(om) > BLE_ATT_ATTR_MAX_LEN) {
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    if (value_len >
+    if (OS_MBUF_PKTLEN(om) >
         ble_att_mtu(conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) {
 
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto done;
     }
 
-    rc = ble_att_clt_build_prep_write_req(conn_handle, req, value, value_len,
-                                          &txom);
-    if (rc != 0) {
-        return rc;
+    om = os_mbuf_prepend_pullup(om, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    ble_att_prep_write_req_write(om->om_data, BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
+                                 req);
+
+    rc = ble_att_clt_tx_req(conn_handle, &om);
     if (rc != 0) {
-        return rc;
+        goto done;
     }
 
-    return 0;
+done:
+    os_mbuf_free_chain(om);
+    return rc;
 }
 
 int
@@ -1264,16 +986,12 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
 #endif
 
     struct ble_att_prep_write_cmd rsp;
-    uint16_t value_len;
-    void *value;
     int rc;
 
     /* Initialize some values in case of early error. */
     memset(&rsp, 0, sizeof rsp);
-    value = NULL;
-    value_len = 0;
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
     if (rc != 0) {
         goto done;
     }
@@ -1285,12 +1003,9 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
     /* Strip the base from the front of the response. */
     os_mbuf_adj(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
 
-    /* Copy the attribute data into the global ATT flat buffer. */
-    rc = ble_att_clt_copy_attr_to_flatbuf(*rxom, &value, &value_len);
-
 done:
     /* Notify GATT client that the full response has been parsed. */
-    ble_gattc_rx_prep_write_rsp(conn_handle, rc, &rsp, value, value_len);
+    ble_gattc_rx_prep_write_rsp(conn_handle, rc, &rsp, rxom);
     return rc;
 }
 
@@ -1298,32 +1013,6 @@ done:
  * $execute write request                                                    *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_exec_write_req(const struct ble_att_exec_write_req *req,
-                                 struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_EXEC_WRITE_REQ_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_exec_write_req_write(txom->om_data, txom->om_len, req);
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_exec_write(uint16_t conn_handle,
                           const struct ble_att_exec_write_req *req)
@@ -1342,12 +1031,13 @@ ble_att_clt_tx_exec_write(uint16_t conn_handle,
         return BLE_HS_EINVAL;
     }
 
-    rc = ble_att_clt_build_exec_write_req(req, &txom);
+    rc = ble_att_clt_init_req(BLE_ATT_EXEC_WRITE_REQ_SZ, &txom);
     if (rc != 0) {
         return rc;
     }
+    ble_att_exec_write_req_write(txom->om_data, txom->om_len, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -1366,7 +1056,7 @@ ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
 
     BLE_ATT_LOG_EMPTY_CMD(0, "exec write rsp", conn_handle);
 
-    rc = ble_hs_misc_pullup_base(rxom, BLE_ATT_EXEC_WRITE_RSP_SZ);
+    rc = ble_hs_mbuf_pullup_base(rxom, BLE_ATT_EXEC_WRITE_RSP_SZ);
     if (rc == 0) {
         ble_att_exec_write_rsp_parse((*rxom)->om_data, (*rxom)->om_len);
     }
@@ -1379,139 +1069,94 @@ ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
  * $handle value notification                                                *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_notify_req(uint16_t conn_handle,
-                             const struct ble_att_notify_req *req,
-                             const void *value, uint16_t value_len,
-                             struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_NOTIFY_REQ_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_notify_req_write(txom->om_data, txom->om_len, req);
-
-    rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len);
-    if (rc != 0) {
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_notify(uint16_t conn_handle,
                       const struct ble_att_notify_req *req,
-                      const void *value, uint16_t value_len)
+                      struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(ATT_CLT_NOTIFY)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct os_mbuf *txom;
+    struct os_mbuf *om;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     BLE_ATT_LOG_CMD(1, "notify req", conn_handle, ble_att_notify_req_log, req);
 
     if (req->banq_handle == 0) {
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto err;
     }
 
-    rc = ble_att_clt_build_notify_req(conn_handle, req, value, value_len,
-                                      &txom);
-    if (rc != 0) {
-        return rc;
+    om = os_mbuf_prepend_pullup(om, BLE_ATT_NOTIFY_REQ_BASE_SZ);
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto err;
     }
+    ble_att_notify_req_write(om->om_data, BLE_ATT_NOTIFY_REQ_BASE_SZ, req);
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    rc = ble_att_clt_tx_req(conn_handle, &om);
     if (rc != 0) {
-        return rc;
+        goto err;
     }
 
     return 0;
+
+err:
+    os_mbuf_free_chain(om);
+    return rc;
 }
 
 /*****************************************************************************
  * $handle value indication                                                  *
  *****************************************************************************/
 
-static int
-ble_att_clt_build_indicate_req(uint16_t conn_handle,
-                               const struct ble_att_indicate_req *req,
-                               const void *value, uint16_t value_len,
-                               struct os_mbuf **out_txom)
-{
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    rc = ble_att_clt_init_req(BLE_ATT_INDICATE_REQ_BASE_SZ, &txom);
-    if (rc != 0) {
-        goto done;
-    }
-
-    ble_att_indicate_req_write(txom->om_data, txom->om_len, req);
-
-    rc = ble_att_clt_append_blob(conn_handle, txom, value, value_len);
-    if (rc != 0) {
-        goto done;
-    }
-
-done:
-    if (rc != 0) {
-        os_mbuf_free_chain(txom);
-        txom = NULL;
-    }
-
-    *out_txom = txom;
-    return rc;
-}
-
 int
 ble_att_clt_tx_indicate(uint16_t conn_handle,
                         const struct ble_att_indicate_req *req,
-                        const void *value, uint16_t value_len)
+                        struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(ATT_CLT_INDICATE)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct os_mbuf *txom;
+    struct os_mbuf *om;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     BLE_ATT_LOG_CMD(1, "indicate req", conn_handle, ble_att_indicate_req_log,
                     req);
 
     if (req->baiq_handle == 0) {
-        return BLE_HS_EINVAL;
+        rc = BLE_HS_EINVAL;
+        goto err;
     }
 
-    rc = ble_att_clt_build_indicate_req(conn_handle, req, value, value_len,
-                                        &txom);
-    if (rc != 0) {
-        return rc;
+    om = os_mbuf_prepend_pullup(om, BLE_ATT_INDICATE_REQ_BASE_SZ);
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto err;
     }
 
-    rc = ble_att_clt_tx_req(conn_handle, txom);
+    ble_att_indicate_req_write(om->om_data, BLE_ATT_INDICATE_REQ_BASE_SZ, req);
+
+    rc = ble_att_clt_tx_req(conn_handle, &om);
     if (rc != 0) {
-        return rc;
+        goto err;
     }
 
     return 0;
+
+err:
+    os_mbuf_free_chain(om);
+    return rc;
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_att_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_priv.h b/net/nimble/host/src/ble_att_priv.h
index 4c50a49..f20817c 100644
--- a/net/nimble/host/src/ble_att_priv.h
+++ b/net/nimble/host/src/ble_att_priv.h
@@ -132,9 +132,8 @@ struct ble_att_svr_conn {
  *                                  failure.
  */
 typedef int ble_att_svr_access_fn(uint16_t conn_handle, uint16_t attr_handle,
-                                  uint8_t *uuid128, uint8_t op,
-                                  struct ble_att_svr_access_ctxt *ctxt,
-                                  void *arg);
+                                  uint8_t op, uint16_t offset,
+                                  struct os_mbuf **om, void *arg);
 
 int ble_att_svr_register(const uint8_t *uuid, uint8_t flags,
                          uint16_t *handle_id,
@@ -162,8 +161,8 @@ struct ble_l2cap_chan *ble_att_create_chan(void);
 int ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn,
                            struct ble_l2cap_chan **out_chan);
 void ble_att_inc_tx_stat(uint8_t att_op);
-uint8_t *ble_att_get_flat_buf(void);
-uint16_t ble_att_mtu(uint16_t conn_handle);
+void ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan,
+                             struct os_mbuf *txom);
 void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
 int ble_att_init(void);
 
@@ -208,7 +207,7 @@ int ble_att_svr_rx_indicate(uint16_t conn_handle,
                             struct os_mbuf **rxom);
 void ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list);
 int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
-                            struct ble_att_svr_access_ctxt *ctxt,
+                            uint16_t offset, struct os_mbuf *om,
                             uint8_t *out_att_err);
 int ble_att_svr_init(void);
 
@@ -232,6 +231,7 @@ struct ble_att_read_type_adata {
     uint16_t att_handle;
     int value_len;
     uint8_t *value;
+
 };
 
 /** An attribute-data entry in a read by group type response. */
@@ -274,13 +274,13 @@ int ble_att_clt_rx_find_type_value(uint16_t conn_handle,
                                    struct os_mbuf **rxom);
 int ble_att_clt_tx_write_req(uint16_t conn_handle,
                              const struct ble_att_write_req *req,
-                             const void *value, uint16_t value_len);
+                             struct os_mbuf **txom);
 int ble_att_clt_tx_write_cmd(uint16_t conn_handle,
                              const struct ble_att_write_req *req,
-                             const void *value, uint16_t value_len);
+                             struct os_mbuf **txom);
 int ble_att_clt_tx_prep_write(uint16_t conn_handle,
                               const struct ble_att_prep_write_cmd *req,
-                              const void *value, uint16_t value_len);
+                              struct os_mbuf **om);
 int ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom);
 int ble_att_clt_tx_exec_write(uint16_t conn_handle,
                               const struct ble_att_exec_write_req *req);
@@ -288,10 +288,10 @@ int ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom);
 int ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom);
 int ble_att_clt_tx_notify(uint16_t conn_handle,
                           const struct ble_att_notify_req *req,
-                          const void *value, uint16_t value_len);
+                          struct os_mbuf **txom);
 int ble_att_clt_tx_indicate(uint16_t conn_handle,
                             const struct ble_att_indicate_req *req,
-                            const void *value, uint16_t value_len);
+                            struct os_mbuf **txom);
 int ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom);
 
 #endif


[06/11] incubator-mynewt-core git commit: BLE Host - Use mbufs instead of flat bufs.

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_read_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_read_test.c b/net/nimble/host/src/test/ble_gatt_read_test.c
index 606a554..0c9f1cb 100644
--- a/net/nimble/host/src/test/ble_gatt_read_test.c
+++ b/net/nimble/host/src/test/ble_gatt_read_test.c
@@ -58,7 +58,7 @@ ble_gatt_read_test_misc_init(void)
 
 static int
 ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error,
-                      const struct ble_gatt_attr *attr, void *arg)
+                      struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_read_test_attr *dst;
     int *stop_after;
@@ -83,12 +83,12 @@ ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error,
                       BLE_GATT_READ_TEST_MAX_ATTRS);
     dst = ble_gatt_read_test_attrs + ble_gatt_read_test_num_attrs++;
 
-    TEST_ASSERT_FATAL(attr->value_len <= sizeof dst->value);
+    TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <= sizeof dst->value);
 
     dst->conn_handle = conn_handle;
     dst->handle = attr->handle;
-    dst->value_len = attr->value_len;
-    memcpy(dst->value, attr->value, attr->value_len);
+    dst->value_len = OS_MBUF_PKTLEN(attr->om);
+    os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), dst->value);
 
     if (stop_after != NULL && *stop_after > 0) {
         (*stop_after)--;
@@ -106,7 +106,7 @@ ble_gatt_read_test_cb(uint16_t conn_handle, const struct ble_gatt_error *error,
 static int
 ble_gatt_read_test_long_cb(uint16_t conn_handle,
                            const struct ble_gatt_error *error,
-                           const struct ble_gatt_attr *attr, void *arg)
+                           struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_read_test_attr *dst;
     int *reads_left;
@@ -129,7 +129,8 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle,
 
     dst = ble_gatt_read_test_attrs + 0;
 
-    TEST_ASSERT_FATAL(attr->value_len <= dst->value_len + sizeof dst->value);
+    TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(attr->om) <=
+        dst->value_len + sizeof dst->value);
     TEST_ASSERT(attr->offset == dst->value_len);
 
     if (attr->offset == 0) {
@@ -139,8 +140,9 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle,
         TEST_ASSERT(conn_handle == dst->conn_handle);
         TEST_ASSERT(attr->handle == dst->handle);
     }
-    memcpy(dst->value + dst->value_len, attr->value, attr->value_len);
-    dst->value_len += attr->value_len;
+    os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om),
+                     dst->value + dst->value_len);
+    dst->value_len += OS_MBUF_PKTLEN(attr->om);
 
     if (reads_left != NULL && *reads_left > 0) {
         (*reads_left)--;
@@ -176,7 +178,7 @@ ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle,
 
 static void
 ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle,
-                                    struct ble_gatt_attr *attr)
+                                    struct ble_hs_test_util_flat_attr *attr)
 {
     ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, BLE_ATT_OP_READ_RSP,
                                             attr->value,
@@ -195,8 +197,8 @@ ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle,
 }
 
 static int
-ble_gatt_read_test_misc_uuid_rx_rsp_good(uint16_t conn_handle,
-                                         struct ble_gatt_attr *attrs)
+ble_gatt_read_test_misc_uuid_rx_rsp_good(
+    uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs)
 {
     struct ble_att_read_type_rsp rsp;
     uint8_t buf[1024];
@@ -238,7 +240,7 @@ ble_gatt_read_test_misc_uuid_rx_rsp_good(uint16_t conn_handle,
 }
 
 static void
-ble_gatt_read_test_misc_verify_good(struct ble_gatt_attr *attr)
+ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr *attr)
 {
     int rc;
 
@@ -261,7 +263,7 @@ ble_gatt_read_test_misc_verify_good(struct ble_gatt_attr *attr)
 
 static void
 ble_gatt_read_test_misc_verify_bad(uint8_t att_status,
-                                   struct ble_gatt_attr *attr)
+                                   struct ble_hs_test_util_flat_attr *attr)
 {
     int rc;
 
@@ -282,10 +284,9 @@ ble_gatt_read_test_misc_verify_bad(uint8_t att_status,
 }
 
 static void
-ble_gatt_read_test_misc_uuid_verify_good(uint16_t start_handle,
-                                         uint16_t end_handle, void *uuid128,
-                                         int stop_after,
-                                         struct ble_gatt_attr *attrs)
+ble_gatt_read_test_misc_uuid_verify_good(
+    uint16_t start_handle, uint16_t end_handle, void *uuid128,
+    int stop_after, struct ble_hs_test_util_flat_attr *attrs)
 {
     int num_read;
     int idx;
@@ -329,8 +330,8 @@ ble_gatt_read_test_misc_uuid_verify_good(uint16_t start_handle,
 }
 
 static void
-ble_gatt_read_test_misc_long_verify_good(int max_reads,
-                                         struct ble_gatt_attr *attr)
+ble_gatt_read_test_misc_long_verify_good(
+    int max_reads, struct ble_hs_test_util_flat_attr *attr)
 {
     int reads_left;
     int chunk_sz;
@@ -382,8 +383,8 @@ ble_gatt_read_test_misc_long_verify_good(int max_reads,
 }
 
 static void
-ble_gatt_read_test_misc_long_verify_bad(uint8_t att_status,
-                                        struct ble_gatt_attr *attr)
+ble_gatt_read_test_misc_long_verify_bad(
+    uint8_t att_status, struct ble_hs_test_util_flat_attr *attr)
 {
     int rc;
 
@@ -405,8 +406,8 @@ ble_gatt_read_test_misc_long_verify_bad(uint8_t att_status,
 }
 
 static int
-ble_gatt_read_test_misc_extract_handles(struct ble_gatt_attr *attrs,
-                                        uint16_t *handles)
+ble_gatt_read_test_misc_extract_handles(
+    struct ble_hs_test_util_flat_attr *attrs, uint16_t *handles)
 {
     int i;
 
@@ -417,7 +418,8 @@ ble_gatt_read_test_misc_extract_handles(struct ble_gatt_attr *attrs,
 }
 
 static void
-ble_gatt_read_test_misc_mult_verify_good(struct ble_gatt_attr *attrs)
+ble_gatt_read_test_misc_mult_verify_good(
+    struct ble_hs_test_util_flat_attr *attrs)
 {
     uint8_t expected_value[512];
     uint16_t handles[256];
@@ -463,9 +465,9 @@ ble_gatt_read_test_misc_mult_verify_good(struct ble_gatt_attr *attrs)
 }
 
 static void
-ble_gatt_read_test_misc_mult_verify_bad(uint8_t att_status,
-                                        uint16_t err_handle,
-                                        struct ble_gatt_attr *attrs)
+ble_gatt_read_test_misc_mult_verify_bad(
+    uint8_t att_status, uint16_t err_handle,
+    struct ble_hs_test_util_flat_attr *attrs)
 {
     uint16_t handles[256];
     int num_attrs;
@@ -493,39 +495,39 @@ ble_gatt_read_test_misc_mult_verify_bad(uint8_t att_status,
 TEST_CASE(ble_gatt_read_test_by_handle)
 {
     /* Read a seven-byte attribute. */
-    ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+        .value = { 1,2,3,4,5,6,7 },
         .value_len = 7
     } });
 
     /* Read a one-byte attribute. */
-    ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 0x5432,
-        .value = (uint8_t[]){ 0xff },
+        .value = { 0xff },
         .value_len = 1
     } });
 
     /* Read a 200-byte attribute. */
-    ble_gatt_read_test_misc_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 815,
-        .value = (uint8_t[200]){ 0 },
+        .value = { 0 },
         .value_len = 200,
     } });
 
     /* Fail due to attribute not found. */
     ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 719,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         } });
 
     /* Fail due to invalid PDU. */
     ble_gatt_read_test_misc_verify_bad(BLE_ATT_ERR_INVALID_PDU,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 65,
-            .value = (uint8_t[]){ 0xfa, 0x4c },
+            .value = { 0xfa, 0x4c },
             .value_len = 2
         } });
 }
@@ -534,9 +536,9 @@ TEST_CASE(ble_gatt_read_test_by_uuid)
 {
     /* Read a single seven-byte attribute. */
     ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 43,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         }, {
             0,
@@ -544,13 +546,13 @@ TEST_CASE(ble_gatt_read_test_by_uuid)
 
     /* Read two seven-byte attributes; one response. */
     ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 43,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         }, {
             .handle = 44,
-            .value = (uint8_t[]){ 2,3,4,5,6,7,8 },
+            .value = { 2,3,4,5,6,7,8 },
             .value_len = 7
         }, {
             0,
@@ -558,13 +560,13 @@ TEST_CASE(ble_gatt_read_test_by_uuid)
 
     /* Read two attributes; two responses. */
     ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 0,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 43,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         }, {
             .handle = 44,
-            .value = (uint8_t[]){ 2,3,4 },
+            .value = { 2,3,4 },
             .value_len = 3
         }, {
             0,
@@ -572,25 +574,25 @@ TEST_CASE(ble_gatt_read_test_by_uuid)
 
     /* Stop after three reads. */
     ble_gatt_read_test_misc_uuid_verify_good(1, 100, BLE_UUID16(0x1234), 3,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 43,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         }, {
             .handle = 44,
-            .value = (uint8_t[]){ 2,3,4 },
+            .value = { 2,3,4 },
             .value_len = 3
         }, {
             .handle = 45,
-            .value = (uint8_t[]){ 2,3,4 },
+            .value = { 2,3,4 },
             .value_len = 3
         }, {
             .handle = 46,
-            .value = (uint8_t[]){ 3,4,5,6 },
+            .value = { 3,4,5,6 },
             .value_len = 4
         }, {
             .handle = 47,
-            .value = (uint8_t[]){ 2,3,4 },
+            .value = { 2,3,4 },
             .value_len = 3
         }, {
             0,
@@ -607,38 +609,52 @@ TEST_CASE(ble_gatt_read_test_long)
     }
 
     /* Read a seven-byte attribute. */
-    ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_long_verify_good(0,
+        (struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = data512,
+        .value = { 1,2,3,4,5,6,7 },
         .value_len = 7
     } });
 
     /* Read a zero-byte attribute. */
-    ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_long_verify_good(0,
+        (struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = NULL,
+        .value = { 0 },
         .value_len = 0
     } });
 
     /* Read a 60-byte attribute; three requests. */
-    ble_gatt_read_test_misc_long_verify_good(0, (struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_long_verify_good(0,
+        (struct ble_hs_test_util_flat_attr[]) { {
         .handle = 34,
-        .value = data512,
+        .value = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+            33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+            49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
+        },
         .value_len = 60
     } });
 
     /* Stop after two reads. */
-    ble_gatt_read_test_misc_long_verify_good(2, (struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_long_verify_good(2,
+        (struct ble_hs_test_util_flat_attr[]) { {
         .handle = 34,
-        .value = data512,
+        .value = {
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+            33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+            49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
+        },
         .value_len = 60
     } });
 
     /* Fail due to attribute not found. */
     ble_gatt_read_test_misc_long_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 719,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1, 2, 3, 4, 5, 6, 7 }, 
             .value_len = 7
         } });
 }
@@ -653,60 +669,60 @@ TEST_CASE(ble_gatt_read_test_mult)
     }
 
     /* Read one attribute. */
-    ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_mult_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = data512,
+        .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
         .value_len = 7
     }, {
         0
     } });
 
     /* Read two attributes. */
-    ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_mult_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = data512,
+        .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
         .value_len = 7,
     }, {
         .handle = 44,
-        .value = data512 + 7,
+        .value = { 8, 9, 10, 11 },
         .value_len = 4,
     }, {
         0
     } });
 
     /* Read two attributes (swap order). */
-    ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_mult_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 44,
-        .value = data512 + 7,
+        .value = { 8, 9, 10, 11 },
         .value_len = 4,
     }, {
         .handle = 43,
-        .value = data512,
+        .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
         .value_len = 7,
     }, {
         0
     } });
 
     /* Read five attributes. */
-    ble_gatt_read_test_misc_mult_verify_good((struct ble_gatt_attr[]) { {
+    ble_gatt_read_test_misc_mult_verify_good((struct ble_hs_test_util_flat_attr[]) { {
         .handle = 43,
-        .value = data512,
+        .value = { 0, 1, 2, 3, 4, 5, 6, 7 },
         .value_len = 7,
     }, {
         .handle = 44,
-        .value = data512 + 7,
+        .value = { 8, 9, 10, 11 },
         .value_len = 4,
     }, {
         .handle = 145,
-        .value = data512 + 11,
+        .value = { 12, 13 },
         .value_len = 2,
     }, {
         .handle = 191,
-        .value = data512 + 13,
+        .value = { 14, 15, 16 },
         .value_len = 3,
     }, {
         .handle = 352,
-        .value = data512 + 16,
+        .value = { 17, 18, 19, 20 },
         .value_len = 4,
     }, {
         0
@@ -714,9 +730,9 @@ TEST_CASE(ble_gatt_read_test_mult)
 
     /* Fail due to attribute not found. */
     ble_gatt_read_test_misc_mult_verify_bad(BLE_ATT_ERR_ATTR_NOT_FOUND, 719,
-        (struct ble_gatt_attr[]) { {
+        (struct ble_hs_test_util_flat_attr[]) { {
             .handle = 719,
-            .value = (uint8_t[]){ 1,2,3,4,5,6,7 },
+            .value = { 1,2,3,4,5,6,7 },
             .value_len = 7
         }, {
             0
@@ -725,7 +741,6 @@ TEST_CASE(ble_gatt_read_test_mult)
 
 TEST_CASE(ble_gatt_read_test_concurrent)
 {
-    struct ble_gatt_attr attrs[3];
     int rc;
     int i;
 
@@ -738,24 +753,31 @@ TEST_CASE(ble_gatt_read_test_concurrent)
      * matched up with its corresponding GATT procedure.
      */
 
-    attrs[0].handle = 1;
-    attrs[0].offset = 0;
-    attrs[0].value_len = 3;
-    attrs[0].value = (uint8_t[3]){ 1, 2, 3 };
+    struct ble_hs_test_util_flat_attr attrs[3] = {
+        {
+            .handle = 1,
+            .offset = 0,
+            .value_len = 3,
+            .value = { 1, 2, 3 },
+        },
+        {
+            .handle = 2,
+            .offset = 0,
+            .value_len = 4,
+            .value = { 2, 3, 4, 5 },
+        },
+        {
+            .handle = 3,
+            .offset = 0,
+            .value_len = 5,
+            .value = { 3, 4, 5, 6, 7 },
+        },
+    };
+
     rc = ble_gattc_read(2, attrs[0].handle, ble_gatt_read_test_cb, NULL);
     TEST_ASSERT_FATAL(rc == 0);
-
-    attrs[1].handle = 2;
-    attrs[1].offset = 0;
-    attrs[1].value_len = 4;
-    attrs[1].value = (uint8_t[4]){ 2, 3, 4, 5 };
     rc = ble_gattc_read(2, attrs[1].handle, ble_gatt_read_test_cb, NULL);
     TEST_ASSERT_FATAL(rc == 0);
-
-    attrs[2].handle = 3;
-    attrs[2].offset = 0;
-    attrs[2].value_len = 5;
-    attrs[2].value = (uint8_t[5]){ 3, 4, 5, 6, 7 };
     rc = ble_gattc_read(2, attrs[2].handle, ble_gatt_read_test_cb, NULL);
     TEST_ASSERT_FATAL(rc == 0);
 
@@ -776,6 +798,8 @@ TEST_CASE(ble_gatt_read_test_concurrent)
 
 TEST_SUITE(ble_gatt_read_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatt_read_test_by_handle();
     ble_gatt_read_test_by_uuid();
     ble_gatt_read_test_long();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_write_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_write_test.c b/net/nimble/host/src/test/ble_gatt_write_test.c
index 0581524..f145ea8 100644
--- a/net/nimble/host/src/test/ble_gatt_write_test.c
+++ b/net/nimble/host/src/test/ble_gatt_write_test.c
@@ -33,7 +33,7 @@ static int ble_gatt_write_test_cb_called;
 static uint8_t ble_gatt_write_test_attr_value[BLE_ATT_ATTR_MAX_LEN];
 static struct ble_gatt_error ble_gatt_write_test_error;
 
-static const struct ble_gatt_attr *
+static struct ble_hs_test_util_flat_attr
 ble_gatt_write_test_attrs[BLE_GATT_WRITE_TEST_MAX_ATTRS];
 static int ble_gatt_write_test_num_attrs;
 
@@ -54,7 +54,7 @@ ble_gatt_write_test_init(void)
 static int
 ble_gatt_write_test_cb_good(uint16_t conn_handle,
                             const struct ble_gatt_error *error,
-                            const struct ble_gatt_attr *attr, void *arg)
+                            struct ble_gatt_attr *attr, void *arg)
 {
     int *attr_len;
 
@@ -132,9 +132,9 @@ ble_gatt_write_test_misc_long_good(int attr_len)
     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
                                  NULL, NULL);
 
-    rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value,
-                              attr_len, ble_gatt_write_test_cb_good,
-                              &attr_len);
+    rc = ble_hs_test_util_gatt_write_long_flat(
+        2, 100, ble_gatt_write_test_attr_value, attr_len,
+        ble_gatt_write_test_cb_good, &attr_len);
     TEST_ASSERT(rc == 0);
 
     off = 0;
@@ -182,8 +182,9 @@ ble_gatt_write_test_misc_long_bad(int attr_len,
     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
                                  NULL, NULL);
 
-    rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value,
-                              attr_len, ble_gatt_write_test_cb_good, NULL);
+    rc = ble_hs_test_util_gatt_write_long_flat(
+        2, 100, ble_gatt_write_test_attr_value, attr_len,
+        ble_gatt_write_test_cb_good, NULL);
     TEST_ASSERT(rc == 0);
 
     fail_now = 0;
@@ -258,7 +259,7 @@ ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle,
 static int
 ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle,
                                      const struct ble_gatt_error *error,
-                                     const struct ble_gatt_attr *attrs,
+                                     struct ble_gatt_attr *attrs,
                                      uint8_t num_attrs, void *arg)
 {
     int i;
@@ -269,7 +270,8 @@ ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle,
 
     ble_gatt_write_test_num_attrs = num_attrs;
     for (i = 0; i < num_attrs; i++) {
-        ble_gatt_write_test_attrs[i] = attrs + i;
+        ble_hs_test_util_attr_to_flat(ble_gatt_write_test_attrs + i,
+                                      attrs + i);
     }
 
     ble_gatt_write_test_cb_called = 1;
@@ -278,8 +280,10 @@ ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle,
 }
 
 static void
-ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs)
+ble_gatt_write_test_misc_reliable_good(
+    struct ble_hs_test_util_flat_attr *flat_attrs)
 {
+    struct ble_gatt_attr attrs[16];
     int num_attrs;
     int attr_idx;
     int rc;
@@ -287,8 +291,11 @@ ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs)
 
     ble_gatt_write_test_init();
 
-    for (num_attrs = 0; attrs[num_attrs].handle != 0; num_attrs++)
-        ;
+    for (num_attrs = 0; flat_attrs[num_attrs].handle != 0; num_attrs++) {
+        TEST_ASSERT_FATAL(num_attrs < sizeof attrs / sizeof attrs[0]);
+        ble_hs_test_util_attr_from_flat(attrs + num_attrs,
+                                        flat_attrs + num_attrs);
+    }
 
     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
                                  NULL, NULL);
@@ -302,9 +309,9 @@ ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs)
         ble_hs_test_util_tx_all();
 
         /* Receive Prep Write response. */
-        ble_gatt_write_test_rx_prep_rsp(2, attrs[attr_idx].handle, 0,
-                                        attrs[attr_idx].value,
-                                        attrs[attr_idx].value_len);
+        ble_gatt_write_test_rx_prep_rsp(2, flat_attrs[attr_idx].handle, 0,
+                                        flat_attrs[attr_idx].value,
+                                        flat_attrs[attr_idx].value_len);
 
         /* Verify callback hasn't gotten called. */
         TEST_ASSERT(!ble_gatt_write_test_cb_called);
@@ -318,7 +325,9 @@ ble_gatt_write_test_misc_reliable_good(struct ble_gatt_attr *attrs)
     TEST_ASSERT(ble_gatt_write_test_cb_called);
     TEST_ASSERT(ble_gatt_write_test_num_attrs == num_attrs);
     for (i = 0; i < num_attrs; i++) {
-        TEST_ASSERT(ble_gatt_write_test_attrs[i] == attrs + i);
+        rc = ble_hs_test_util_flat_attr_cmp(
+            ble_gatt_write_test_attrs + i, flat_attrs + i);
+        TEST_ASSERT(rc == 0);
     }
 }
 
@@ -333,8 +342,8 @@ TEST_CASE(ble_gatt_write_test_no_rsp)
                                  NULL, NULL);
 
     attr_len = 4;
-    rc = ble_gattc_write_no_rsp(2, 100, ble_gatt_write_test_attr_value,
-                                attr_len);
+    rc = ble_hs_test_util_gatt_write_no_rsp_flat(
+        2, 100, ble_gatt_write_test_attr_value, attr_len);
     TEST_ASSERT(rc == 0);
 
     /* Send the pending ATT Write Command. */
@@ -354,8 +363,9 @@ TEST_CASE(ble_gatt_write_test_rsp)
                                  NULL, NULL);
 
     attr_len = 4;
-    ble_gattc_write(2, 100, ble_gatt_write_test_attr_value, attr_len,
-                    ble_gatt_write_test_cb_good, &attr_len);
+    ble_hs_test_util_gatt_write_flat(2, 100, ble_gatt_write_test_attr_value,
+                                     attr_len, ble_gatt_write_test_cb_good,
+                                     &attr_len);
 
     /* Send the pending ATT Write Command. */
     ble_hs_test_util_tx_all();
@@ -460,42 +470,42 @@ TEST_CASE(ble_gatt_write_test_reliable_good)
 {
     /*** 1 attribute. */
     ble_gatt_write_test_misc_reliable_good(
-        ((struct ble_gatt_attr[]) { {
+        ((struct ble_hs_test_util_flat_attr[]) { {
             .handle = 100,
             .value_len = 2,
-            .value = (uint8_t[]){ 1, 2 },
+            .value = { 1, 2 },
         }, {
             0
         } }));
 
     /*** 2 attributes. */
     ble_gatt_write_test_misc_reliable_good(
-        ((struct ble_gatt_attr[]) { {
+        ((struct ble_hs_test_util_flat_attr[]) { {
             .handle = 100,
             .value_len = 2,
-            .value = (uint8_t[]){ 1,2 },
+            .value = { 1,2 },
         }, {
             .handle = 113,
             .value_len = 6,
-            .value = (uint8_t[]){ 5,6,7,8,9,10 },
+            .value = { 5,6,7,8,9,10 },
         }, {
             0
         } }));
 
     /*** 3 attributes. */
     ble_gatt_write_test_misc_reliable_good(
-        ((struct ble_gatt_attr[]) { {
+        ((struct ble_hs_test_util_flat_attr[]) { {
             .handle = 100,
             .value_len = 2,
-            .value = (uint8_t[]){ 1,2 },
+            .value = { 1,2 },
         }, {
             .handle = 113,
             .value_len = 6,
-            .value = (uint8_t[]){ 5,6,7,8,9,10 },
+            .value = { 5,6,7,8,9,10 },
         }, {
             .handle = 144,
             .value_len = 1,
-            .value = (uint8_t[]){ 0xff },
+            .value = { 0xff },
         }, {
             0
         } }));
@@ -513,8 +523,9 @@ TEST_CASE(ble_gatt_write_test_long_queue_full)
     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
                                  NULL, NULL);
 
-    rc = ble_gattc_write_long(2, 100, ble_gatt_write_test_attr_value,
-                              128, ble_gatt_write_test_cb_good, NULL);
+    rc = ble_hs_test_util_gatt_write_long_flat(
+        2, 100, ble_gatt_write_test_attr_value, 128,
+        ble_gatt_write_test_cb_good, NULL);
     TEST_ASSERT(rc == 0);
 
     off = 0;
@@ -554,6 +565,8 @@ TEST_CASE(ble_gatt_write_test_long_queue_full)
 
 TEST_SUITE(ble_gatt_write_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatt_write_test_no_rsp();
     ble_gatt_write_test_rsp();
     ble_gatt_write_test_long_good();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatts_notify_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatts_notify_test.c b/net/nimble/host/src/test/ble_gatts_notify_test.c
index b859132..4516e66 100644
--- a/net/nimble/host/src/test/ble_gatts_notify_test.c
+++ b/net/nimble/host/src/test/ble_gatts_notify_test.c
@@ -378,21 +378,25 @@ ble_gatts_notify_test_misc_access(uint16_t conn_handle,
                                   struct ble_gatt_access_ctxt *ctxt,
                                   void *arg)
 {
+    int rc;
+
     TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
     TEST_ASSERT(conn_handle == 0xffff);
 
     if (attr_handle == ble_gatts_notify_test_chr_1_def_handle + 1) {
         TEST_ASSERT(ctxt->chr ==
                     &ble_gatts_notify_test_svcs[0].characteristics[0]);
-        ctxt->att->read.data = ble_gatts_notify_test_chr_1_val;
-        ctxt->att->read.len = ble_gatts_notify_test_chr_1_len;
+        rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_1_val,
+                              ble_gatts_notify_test_chr_1_len);
+        TEST_ASSERT_FATAL(rc == 0);
     } else if (attr_handle == ble_gatts_notify_test_chr_2_def_handle + 1) {
         TEST_ASSERT(ctxt->chr ==
                     &ble_gatts_notify_test_svcs[0].characteristics[1]);
-        ctxt->att->read.data = ble_gatts_notify_test_chr_2_val;
-        ctxt->att->read.len = ble_gatts_notify_test_chr_2_len;
+        rc = os_mbuf_copyinto(ctxt->om, 0, ble_gatts_notify_test_chr_2_val,
+                              ble_gatts_notify_test_chr_2_len);
+        TEST_ASSERT_FATAL(rc == 0);
     } else {
-        TEST_ASSERT(0);
+        TEST_ASSERT_FATAL(0);
     }
 
     return 0;
@@ -954,6 +958,8 @@ TEST_CASE(ble_gatts_notify_test_bonded_i_no_ack)
 
 TEST_SUITE(ble_gatts_notify_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatts_notify_test_n();
     ble_gatts_notify_test_i();
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatts_read_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatts_read_test.c b/net/nimble/host/src/test/ble_gatts_read_test.c
index 0f889f9..cef9f92 100644
--- a/net/nimble/host/src/test/ble_gatts_read_test.c
+++ b/net/nimble/host/src/test/ble_gatts_read_test.c
@@ -128,15 +128,17 @@ ble_gatts_read_test_util_access_1(uint16_t conn_handle,
                                   struct ble_gatt_access_ctxt *ctxt,
                                   void *arg)
 {
+    int rc;
+
     TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
     TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_1_val_handle);
 
     TEST_ASSERT(ctxt->chr ==
                 &ble_gatts_read_test_svcs[0].characteristics[0]);
-    ctxt->att->read.data = ble_gatts_read_test_chr_1_val +
-                           ctxt->att->read.offset;
-    ctxt->att->read.len = ble_gatts_read_test_chr_1_len -
-                          ctxt->att->read.offset;
+
+    rc = os_mbuf_append(ctxt->om, ble_gatts_read_test_chr_1_val,
+                        ble_gatts_read_test_chr_1_len);
+    TEST_ASSERT(rc == 0);
 
     return 0;
 }
@@ -147,22 +149,23 @@ ble_gatts_read_test_util_access_2(uint16_t conn_handle,
                                   struct ble_gatt_access_ctxt *ctxt,
                                   void *arg)
 {
+    uint8_t *buf;
+
     TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
     TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_2_def_handle + 1);
 
     TEST_ASSERT(ctxt->chr ==
                 &ble_gatts_read_test_svcs[0].characteristics[1]);
 
-    TEST_ASSERT_FATAL(ctxt->att->read.data == ctxt->att->read.buf);
-    TEST_ASSERT(ctxt->att->read.max_data_len == BLE_ATT_MTU_DFLT - 1);
+    buf = os_mbuf_extend(ctxt->om, 6);
+    TEST_ASSERT_FATAL(buf != NULL);
 
-    ctxt->att->read.buf[0] = 0;
-    ctxt->att->read.buf[1] = 10;
-    ctxt->att->read.buf[2] = 20;
-    ctxt->att->read.buf[3] = 30;
-    ctxt->att->read.buf[4] = 40;
-    ctxt->att->read.buf[5] = 50;
-    ctxt->att->read.len = 6;
+    buf[0] = 0;
+    buf[1] = 10;
+    buf[2] = 20;
+    buf[3] = 30;
+    buf[4] = 40;
+    buf[5] = 50;
 
     return 0;
 }
@@ -251,6 +254,8 @@ TEST_CASE(ble_gatts_read_test_case_long)
 
 TEST_SUITE(ble_gatts_read_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatts_read_test_case_basic();
     ble_gatts_read_test_case_long();
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatts_reg_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatts_reg_test.c b/net/nimble/host/src/test/ble_gatts_reg_test.c
index f15dfef..963800a 100644
--- a/net/nimble/host/src/test/ble_gatts_reg_test.c
+++ b/net/nimble/host/src/test/ble_gatts_reg_test.c
@@ -697,6 +697,8 @@ TEST_CASE(ble_gatts_reg_test_dsc_cb)
 
 TEST_SUITE(ble_gatts_reg_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatts_reg_test_svc_return();
     ble_gatts_reg_test_chr_return();
     ble_gatts_reg_test_dsc_return();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_host_hci_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_host_hci_test.c b/net/nimble/host/src/test/ble_host_hci_test.c
index 52837bd..a8e8d82 100644
--- a/net/nimble/host/src/test/ble_host_hci_test.c
+++ b/net/nimble/host/src/test/ble_host_hci_test.c
@@ -82,6 +82,8 @@ TEST_CASE(ble_host_hci_test_rssi)
 
 TEST_SUITE(ble_host_hci_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_host_hci_test_event_bad();
     ble_host_hci_test_rssi();
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_hs_adv_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_adv_test.c b/net/nimble/host/src/test/ble_hs_adv_test.c
index dec9736..89c61a2 100644
--- a/net/nimble/host/src/test/ble_hs_adv_test.c
+++ b/net/nimble/host/src/test/ble_hs_adv_test.c
@@ -1469,6 +1469,8 @@ TEST_CASE(ble_hs_adv_test_case_user_full_payload)
 
 TEST_SUITE(ble_hs_adv_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_hs_adv_test_case_flags();
     ble_hs_adv_test_case_user();
     ble_hs_adv_test_case_user_rsp();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_hs_conn_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_conn_test.c b/net/nimble/host/src/test/ble_hs_conn_test.c
index 87df5b1..0e896f4 100644
--- a/net/nimble/host/src/test/ble_hs_conn_test.c
+++ b/net/nimble/host/src/test/ble_hs_conn_test.c
@@ -204,6 +204,8 @@ TEST_CASE(ble_hs_conn_test_undirect_connectable_success)
 
 TEST_SUITE(conn_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_hs_conn_test_direct_connect_success();
     ble_hs_conn_test_direct_connectable_success();
     ble_hs_conn_test_undirect_connectable_success();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 65b428a..d517f86 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -719,6 +719,8 @@ ble_hs_test_util_l2cap_rx(uint16_t conn_handle,
     conn = ble_hs_conn_find(conn_handle);
     if (conn != NULL) {
         rc = ble_l2cap_rx(conn, hci_hdr, om, &rx_cb, &rx_buf);
+    } else {
+        os_mbuf_free_chain(om);
     }
 
     ble_hs_unlock();
@@ -746,7 +748,7 @@ ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid,
     struct os_mbuf *om;
     int rc;
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     rc = os_mbuf_append(om, data, len);
@@ -982,6 +984,206 @@ ble_hs_test_util_set_static_rnd_addr(void)
     ble_hs_test_util_get_first_hci_tx();
 }
 
+struct os_mbuf *
+ble_hs_test_util_om_from_flat(const void *buf, uint16_t len)
+{
+    struct os_mbuf *om;
+
+    om = ble_hs_mbuf_from_flat(buf, len);
+    TEST_ASSERT_FATAL(om != NULL);
+
+    return om;
+}
+
+int
+ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a,
+                               const struct ble_hs_test_util_flat_attr *b)
+{
+    if (a->handle != b->handle) {
+        return -1;
+    }
+    if (a->offset != b->offset) {
+        return -1;
+    }
+    if (a->value_len != b->value_len) {
+        return -1;
+    }
+    return memcmp(a->value, b->value, a->value_len);
+}
+
+void
+ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat,
+                              const struct ble_gatt_attr *attr)
+{
+    int rc;
+
+    flat->handle = attr->handle;
+    flat->offset = attr->offset;
+    rc = ble_hs_mbuf_to_flat(attr->om, flat->value, sizeof flat->value,
+                           &flat->value_len);
+    TEST_ASSERT_FATAL(rc == 0);
+}
+
+void
+ble_hs_test_util_attr_from_flat(struct ble_gatt_attr *attr,
+                                const struct ble_hs_test_util_flat_attr *flat)
+{
+    attr->handle = flat->handle;
+    attr->offset = flat->offset;
+    attr->om = ble_hs_test_util_om_from_flat(flat->value, flat->value_len);
+}
+
+int
+ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len,
+                                 void *buf, uint16_t *out_len)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    rc = ble_att_svr_read_local(attr_handle, &om);
+    if (rc != 0) {
+        return rc;
+    }
+
+    TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(om) <= max_len);
+
+    rc = os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), buf);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    *out_len = OS_MBUF_PKTLEN(om);
+
+    os_mbuf_free_chain(om);
+    return 0;
+}
+
+int
+ble_hs_test_util_write_local_flat(uint16_t attr_handle,
+                                  const void *buf, uint16_t buf_len)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_test_util_om_from_flat(buf, buf_len);
+    rc = ble_att_svr_write_local(attr_handle, &om);
+    TEST_ASSERT(om == NULL);
+    return rc;
+}
+
+int
+ble_hs_test_util_gatt_write_flat(uint16_t conn_handle, uint16_t attr_handle,
+                                 const void *data, uint16_t data_len,
+                                 ble_gatt_attr_fn *cb, void *cb_arg)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_test_util_om_from_flat(data, data_len);
+    rc = ble_gattc_write(conn_handle, attr_handle, &om, cb, cb_arg);
+    TEST_ASSERT(om == NULL);
+
+    return rc;
+}
+
+int
+ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle,
+                                        uint16_t attr_handle,
+                                        const void *data, uint16_t data_len)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_test_util_om_from_flat(data, data_len);
+    rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, &om);
+    TEST_ASSERT(om == NULL);
+
+    return rc;
+}
+
+int
+ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle,
+                                      uint16_t attr_handle,
+                                      const void *data, uint16_t data_len,
+                                      ble_gatt_attr_fn *cb, void *cb_arg)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_test_util_om_from_flat(data, data_len);
+    rc = ble_gattc_write_long(conn_handle, attr_handle, &om, cb, cb_arg);
+    TEST_ASSERT(om == NULL);
+    return rc;
+}
+
+static int
+ble_hs_test_util_mbuf_chain_len(const struct os_mbuf *om)
+{
+    int count;
+
+    count = 0;
+    while (om != NULL) {
+        count++;
+        om = SLIST_NEXT(om, om_next);
+    }
+
+    return count;
+}
+
+int
+ble_hs_test_util_mbuf_count(void)
+{
+    const struct ble_att_prep_entry *prep;
+    const struct os_mbuf_pkthdr *omp;
+    const struct ble_l2cap_chan *chan;
+    const struct ble_hs_conn *conn;
+    const struct os_mbuf *om;
+    int count;
+    int i;
+
+    count = ble_hs_test_util_mbuf_mpool.mp_num_free;
+    count += ble_hs_test_util_mbuf_chain_len(ble_hs_test_util_prev_tx_cur);
+
+    ble_hs_process_tx_data_queue();
+    ble_hs_process_rx_data_queue();
+    STAILQ_FOREACH(omp, &ble_hs_test_util_prev_tx_queue, omp_next) {
+        om = OS_MBUF_PKTHDR_TO_MBUF(omp);
+        count += ble_hs_test_util_mbuf_chain_len(om);
+    }
+
+    ble_hs_lock();
+    for (i = 0; ; i++) {
+        conn = ble_hs_conn_find_by_idx(i);
+        if (conn == NULL) {
+            break;
+        }
+
+        SLIST_FOREACH(chan, &conn->bhc_channels, blc_next) {
+            count += ble_hs_test_util_mbuf_chain_len(chan->blc_rx_buf);
+        }
+
+        SLIST_FOREACH(prep, &conn->bhc_att_svr.basc_prep_list, bape_next) {
+            count += ble_hs_test_util_mbuf_chain_len(prep->bape_value);
+        }
+    }
+    ble_hs_unlock();
+
+    return count;
+}
+
+void
+ble_hs_test_util_assert_mbufs_freed(void)
+{
+    int count;
+
+    count = ble_hs_test_util_mbuf_count();
+    TEST_ASSERT(count == ble_hs_test_util_mbuf_mpool.mp_num_blocks);
+}
+
+void
+ble_hs_test_util_post_test(void *arg)
+{
+    ble_hs_test_util_assert_mbufs_freed();
+}
+
 void
 ble_hs_test_util_init(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 3b4fe94..b663ce2 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.h
+++ b/net/nimble/host/src/test/ble_hs_test_util.h
@@ -36,6 +36,13 @@ struct ble_hs_test_util_num_completed_pkts_entry {
     uint16_t num_pkts;
 };
 
+struct ble_hs_test_util_flat_attr {
+    uint16_t handle;
+    uint16_t offset;
+    uint8_t value[BLE_ATT_ATTR_MAX_LEN];
+    uint16_t value_len;
+};
+
 void ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om);
 struct os_mbuf *ble_hs_test_util_prev_tx_dequeue(void);
 struct os_mbuf *ble_hs_test_util_prev_tx_dequeue_pullup(void);
@@ -122,6 +129,32 @@ void ble_hs_test_util_verify_tx_read_rsp(uint8_t *attr_data, int attr_len);
 void ble_hs_test_util_verify_tx_read_blob_rsp(uint8_t *attr_data,
                                               int attr_len);
 void ble_hs_test_util_set_static_rnd_addr(void);
+struct os_mbuf *ble_hs_test_util_om_from_flat(const void *buf, uint16_t len);
+int ble_hs_test_util_flat_attr_cmp(const struct ble_hs_test_util_flat_attr *a,
+                                   const struct ble_hs_test_util_flat_attr *b);
+void ble_hs_test_util_attr_to_flat(struct ble_hs_test_util_flat_attr *flat,
+                                   const struct ble_gatt_attr *attr);
+void ble_hs_test_util_attr_from_flat(
+    struct ble_gatt_attr *attr, const struct ble_hs_test_util_flat_attr *flat);
+int ble_hs_test_util_read_local_flat(uint16_t attr_handle, uint16_t max_len,
+                                     void *buf, uint16_t *out_len);
+int ble_hs_test_util_write_local_flat(uint16_t attr_handle,
+                                      const void *buf, uint16_t buf_len);
+int ble_hs_test_util_gatt_write_flat(uint16_t conn_handle,
+                                     uint16_t attr_handle,
+                                     const void *data, uint16_t data_len,
+                                     ble_gatt_attr_fn *cb, void *cb_arg);
+int ble_hs_test_util_gatt_write_no_rsp_flat(uint16_t conn_handle,
+                                            uint16_t attr_handle,
+                                            const void *data,
+                                            uint16_t data_len);
+int ble_hs_test_util_gatt_write_long_flat(uint16_t conn_handle,
+                                          uint16_t attr_handle,
+                                          const void *data, uint16_t data_len,
+                                          ble_gatt_attr_fn *cb, void *cb_arg);
+int ble_hs_test_util_mbuf_count(void);
+void ble_hs_test_util_assert_mbufs_freed(void);
+void ble_hs_test_util_post_test(void *arg);
 void ble_hs_test_util_init(void);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_l2cap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_l2cap_test.c b/net/nimble/host/src/test/ble_l2cap_test.c
index b651325..118d04f 100644
--- a/net/nimble/host/src/test/ble_l2cap_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_test.c
@@ -242,7 +242,7 @@ ble_l2cap_test_util_rx_first_frag(uint16_t conn_handle,
     void *v;
     int rc;
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     v = os_mbuf_extend(om, l2cap_frag_len);
@@ -266,7 +266,7 @@ ble_l2cap_test_util_rx_next_frag(uint16_t conn_handle, uint16_t hci_len)
     void *v;
     int rc;
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     v = os_mbuf_extend(om, hci_len);
@@ -374,7 +374,7 @@ TEST_CASE(ble_l2cap_test_case_frag_single)
     /*** HCI header specifies middle fragment without start. */
     hci_hdr = BLE_L2CAP_TEST_UTIL_HCI_HDR(2, BLE_HCI_PB_MIDDLE, 10);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     om = ble_l2cap_prepend_hdr(om, 0, 5);
@@ -666,6 +666,8 @@ TEST_CASE(ble_l2cap_test_case_sig_update_init_fail_bad_id)
 
 TEST_SUITE(ble_l2cap_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_l2cap_test_case_bad_header();
     ble_l2cap_test_case_frag_single();
     ble_l2cap_test_case_frag_multiple();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_os_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_os_test.c b/net/nimble/host/src/test/ble_os_test.c
index 193cab1..1ab8e0a 100644
--- a/net/nimble/host/src/test/ble_os_test.c
+++ b/net/nimble/host/src/test/ble_os_test.c
@@ -385,6 +385,8 @@ TEST_CASE(ble_gap_terminate_test_case)
 
 TEST_SUITE(ble_os_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_os_disc_test_case();
     ble_gap_direct_connect_test_case();
     ble_gap_terminate_test_case();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_sm_lgcy_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_sm_lgcy_test.c b/net/nimble/host/src/test/ble_sm_lgcy_test.c
index 59dceab..9a61087 100644
--- a/net/nimble/host/src/test/ble_sm_lgcy_test.c
+++ b/net/nimble/host/src/test/ble_sm_lgcy_test.c
@@ -822,6 +822,8 @@ TEST_CASE(ble_sm_lgcy_peer_pk_iio4_rio4_b1_iat0_rat0_ik7_rk7)
 
 TEST_SUITE(ble_sm_lgcy_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     /*** No privacy. */
 
     /* Peer as initiator. */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_sm_sc_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_sm_sc_test.c b/net/nimble/host/src/test/ble_sm_sc_test.c
index 4d60f0c..f69c60e 100644
--- a/net/nimble/host/src/test/ble_sm_sc_test.c
+++ b/net/nimble/host/src/test/ble_sm_sc_test.c
@@ -4879,6 +4879,8 @@ TEST_CASE(ble_sm_sc_us_pk_iio2_rio0_b1_iat2_rat2_ik7_rk3)
 
 TEST_SUITE(ble_sm_sc_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     /*** No privacy. */
 
     /* Peer as initiator. */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_sm_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_sm_test.c b/net/nimble/host/src/test/ble_sm_test.c
index d890996..26efea9 100644
--- a/net/nimble/host/src/test/ble_sm_test.c
+++ b/net/nimble/host/src/test/ble_sm_test.c
@@ -648,6 +648,8 @@ TEST_CASE(ble_sm_test_case_us_fail_inval)
 
 TEST_SUITE(ble_sm_gen_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_sm_test_case_f4();
     ble_sm_test_case_f5();
     ble_sm_test_case_f6();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_sm_test_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_sm_test_util.c b/net/nimble/host/src/test/ble_sm_test_util.c
index 29c2aa5..1c052fb 100644
--- a/net/nimble/host/src/test/ble_sm_test_util.c
+++ b/net/nimble/host/src/test/ble_sm_test_util.c
@@ -307,7 +307,7 @@ ble_sm_test_util_rx_pair_cmd(uint16_t conn_handle, uint8_t op,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_CMD_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_CMD_SZ;
@@ -354,7 +354,7 @@ ble_sm_test_util_rx_confirm(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_CONFIRM_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_CONFIRM_SZ;
@@ -384,7 +384,7 @@ ble_sm_test_util_rx_random(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PAIR_RANDOM_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_PAIR_RANDOM_SZ;
@@ -413,7 +413,7 @@ ble_sm_test_util_rx_sec_req(uint16_t conn_handle, struct ble_sm_sec_req *cmd,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_SEC_REQ_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_SEC_REQ_SZ;
@@ -442,7 +442,7 @@ ble_sm_test_util_rx_public_key(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_PUBLIC_KEY_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_PUBLIC_KEY_SZ;
@@ -472,7 +472,7 @@ ble_sm_test_util_rx_dhkey_check(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_DHKEY_CHECK_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_DHKEY_CHECK_SZ;
@@ -502,7 +502,7 @@ ble_sm_test_util_rx_enc_info(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ENC_INFO_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_ENC_INFO_SZ;
@@ -532,7 +532,7 @@ ble_sm_test_util_rx_master_id(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_MASTER_ID_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_MASTER_ID_SZ;
@@ -562,7 +562,7 @@ ble_sm_test_util_rx_id_info(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ID_INFO_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_ID_INFO_SZ;
@@ -592,7 +592,7 @@ ble_sm_test_util_rx_id_addr_info(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_ID_ADDR_INFO_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_ID_ADDR_INFO_SZ;
@@ -622,7 +622,7 @@ ble_sm_test_util_rx_sign_info(uint16_t conn_handle,
         2, BLE_HCI_PB_FIRST_FLUSH,
         BLE_L2CAP_HDR_SZ + BLE_SM_HDR_SZ + BLE_SM_SIGN_INFO_SZ);
 
-    om = ble_hs_misc_pkthdr();
+    om = ble_hs_mbuf_l2cap_pkt();
     TEST_ASSERT_FATAL(om != NULL);
 
     payload_len = BLE_SM_HDR_SZ + BLE_SM_SIGN_INFO_SZ;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_uuid_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_uuid_test.c b/net/nimble/host/src/test/ble_uuid_test.c
index ecb3505..1011303 100644
--- a/net/nimble/host/src/test/ble_uuid_test.c
+++ b/net/nimble/host/src/test/ble_uuid_test.c
@@ -19,9 +19,10 @@
 
 #include <stddef.h>
 #include <string.h>
-#include "host/ble_hs_test.h"
 #include "testutil/testutil.h"
+#include "host/ble_hs_test.h"
 #include "host/ble_uuid.h"
+#include "ble_hs_test_util.h"
 
 TEST_CASE(ble_uuid_test_128_to_16)
 {
@@ -78,6 +79,8 @@ TEST_CASE(ble_uuid_test_128_to_16)
 
 TEST_SUITE(ble_uuid_test_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_uuid_test_128_to_16();
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/include/nimble/nimble_opt.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/nimble_opt.h b/net/nimble/include/nimble/nimble_opt.h
index dd007e2..319c08d 100644
--- a/net/nimble/include/nimble/nimble_opt.h
+++ b/net/nimble/include/nimble/nimble_opt.h
@@ -138,6 +138,14 @@
 #define NIMBLE_OPT_GATT_INDICATE                1
 #endif
 
+/** HOST: GATT options. */
+
+/* The maximum number of attributes that can be written with a single GATT
+ * Reliable Write procedure.
+ */
+#ifndef NIMBLE_OPT_GATT_WRITE_MAX_ATTRS
+#define NIMBLE_OPT_GATT_WRITE_MAX_ATTRS         4
+#endif
 
 /** HOST: Supported server ATT commands. */
 


[07/11] incubator-mynewt-core git commit: BLE Host - Use mbufs instead of flat bufs.

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gatts.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatts.c b/net/nimble/host/src/ble_gatts.c
index 8edc5e3..9c645a9 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -66,11 +66,13 @@ STATS_NAME_END(ble_gatts_stats)
 
 static int
 ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle,
-                     uint8_t *uuid128, uint8_t op,
-                     struct ble_att_svr_access_ctxt *ctxt, void *arg)
+                     uint8_t op, uint16_t offset, struct os_mbuf **om,
+                     void *arg)
 {
     const struct ble_gatt_svc_def *svc;
     uint16_t uuid16;
+    uint8_t *buf;
+    int rc;
 
     STATS_INC(ble_gatts_stats, svc_def_reads);
 
@@ -80,11 +82,16 @@ ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle,
 
     uuid16 = ble_uuid_128_to_16(svc->uuid128);
     if (uuid16 != 0) {
-        htole16(ctxt->read.buf, uuid16);
-        ctxt->read.len = 2;
+        buf = os_mbuf_extend(*om, 2);
+        if (buf == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        htole16(buf, uuid16);
     } else {
-        ctxt->read.data = svc->uuid128;
-        ctxt->read.len = 16;
+        rc = os_mbuf_append(*om, svc->uuid128, 16);
+        if (rc != 0) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
     }
 
     return 0;
@@ -92,11 +99,12 @@ ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle,
 
 static int
 ble_gatts_inc_access(uint16_t conn_handle, uint16_t attr_handle,
-                     uint8_t *uuid128, uint8_t op,
-                     struct ble_att_svr_access_ctxt *ctxt, void *arg)
+                     uint8_t op, uint16_t offset, struct os_mbuf **om,
+                     void *arg)
 {
     const struct ble_gatts_svc_entry *entry;
     uint16_t uuid16;
+    uint8_t *buf;
 
     STATS_INC(ble_gatts_stats, svc_inc_reads);
 
@@ -104,16 +112,21 @@ ble_gatts_inc_access(uint16_t conn_handle, uint16_t attr_handle,
 
     entry = arg;
 
-    htole16(ctxt->read.buf + 0, entry->handle);
-    htole16(ctxt->read.buf + 2, entry->end_group_handle);
+    buf = os_mbuf_extend(*om, 4);
+    if (buf == NULL) {
+        return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+    htole16(buf + 0, entry->handle);
+    htole16(buf + 2, entry->end_group_handle);
 
     /* Only include the service UUID if it has a 16-bit representation. */
     uuid16 = ble_uuid_128_to_16(entry->svc->uuid128);
     if (uuid16 != 0) {
-        htole16(ctxt->read.buf + 4, uuid16);
-        ctxt->read.len = 6;
-    } else {
-        ctxt->read.len = 4;
+        buf = os_mbuf_extend(*om, 2);
+        if (buf == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        htole16(buf, uuid16);
     }
 
     return 0;
@@ -208,11 +221,12 @@ ble_gatts_chr_properties(const struct ble_gatt_chr_def *chr)
 
 static int
 ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle,
-                         uint8_t *uuid128, uint8_t op,
-                         struct ble_att_svr_access_ctxt *ctxt, void *arg)
+                         uint8_t op, uint16_t offset, struct os_mbuf **om,
+                         void *arg)
 {
     const struct ble_gatt_chr_def *chr;
     uint16_t uuid16;
+    uint8_t *buf;
 
     STATS_INC(ble_gatts_stats, chr_def_reads);
 
@@ -220,18 +234,29 @@ ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle,
 
     chr = arg;
 
-    ctxt->read.buf[0] = ble_gatts_chr_properties(chr);
+    buf = os_mbuf_extend(*om, 3);
+    if (buf == NULL) {
+        return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    buf[0] = ble_gatts_chr_properties(chr);
 
     /* The value attribute is always immediately after the declaration. */
-    htole16(ctxt->read.buf + 1, attr_handle + 1);
+    htole16(buf + 1, attr_handle + 1);
 
     uuid16 = ble_uuid_128_to_16(chr->uuid128);
     if (uuid16 != 0) {
-        htole16(ctxt->read.buf + 3, uuid16);
-        ctxt->read.len = 5;
+        buf = os_mbuf_extend(*om, 2);
+        if (buf == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        htole16(buf, uuid16);
     } else {
-        memcpy(ctxt->read.buf + 3, chr->uuid128, 16);
-        ctxt->read.len = 19;
+        buf = os_mbuf_extend(*om, 16);
+        if (buf == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        memcpy(buf, chr->uuid128, 16);
     }
 
     return 0;
@@ -287,9 +312,50 @@ ble_gatts_chr_inc_val_stat(uint8_t gatt_op)
 }
 
 static int
+ble_gatts_val_access(uint16_t conn_handle, uint16_t attr_handle,
+                     uint16_t offset, struct ble_gatt_access_ctxt *gatt_ctxt,
+                     struct os_mbuf **om, ble_gatt_access_fn *access_cb,
+                     void *cb_arg)
+{
+    int attr_len;
+    int rc;
+
+    switch (gatt_ctxt->op) {
+    case BLE_GATT_ACCESS_OP_READ_CHR:
+    case BLE_GATT_ACCESS_OP_READ_DSC:
+        gatt_ctxt->om = os_msys_get_pkthdr(0, 0);
+        if (gatt_ctxt->om == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+
+        rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg);
+        if (rc == 0) {
+            attr_len = OS_MBUF_PKTLEN(gatt_ctxt->om) - offset;
+            if (attr_len > 0) {
+                os_mbuf_appendfrom(*om, gatt_ctxt->om, offset, attr_len);
+            }
+        }
+
+        os_mbuf_free_chain(gatt_ctxt->om);
+        return rc;
+
+    case BLE_GATT_ACCESS_OP_WRITE_CHR:
+    case BLE_GATT_ACCESS_OP_WRITE_DSC:
+        gatt_ctxt->om = *om;
+        rc = access_cb(conn_handle, attr_handle, gatt_ctxt, cb_arg);
+        *om = gatt_ctxt->om;
+        return rc;
+
+    default:
+        BLE_HS_DBG_ASSERT(0);
+        return BLE_ATT_ERR_UNLIKELY;
+    }
+}
+
+static int
 ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle,
-                         uint8_t *uuid128, uint8_t att_op,
-                         struct ble_att_svr_access_ctxt *att_ctxt, void *arg)
+                         uint8_t att_op, uint16_t offset,
+                         struct os_mbuf **om, void *arg)
 {
     const struct ble_gatt_chr_def *chr_def;
     struct ble_gatt_access_ctxt gatt_ctxt;
@@ -299,23 +365,13 @@ ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle,
     BLE_HS_DBG_ASSERT(chr_def != NULL && chr_def->access_cb != NULL);
 
     gatt_ctxt.op = ble_gatts_chr_op(att_op);
-    ble_gatts_chr_inc_val_stat(gatt_ctxt.op);
-
     gatt_ctxt.chr = chr_def;
-    gatt_ctxt.att = att_ctxt;
-    rc = chr_def->access_cb(conn_handle, attr_handle, &gatt_ctxt,
-                            chr_def->arg);
-    if (rc != 0) {
-        return rc;
-    }
-
-    if (gatt_ctxt.op == BLE_GATT_ACCESS_OP_WRITE_CHR &&
-        ble_gatts_chr_clt_cfg_allowed(chr_def)) {
 
-        ble_gatts_chr_updated(attr_handle - 1);
-    }
+    ble_gatts_chr_inc_val_stat(gatt_ctxt.op);
+    rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om,
+                              chr_def->access_cb, chr_def->arg);
 
-    return 0;
+    return rc;
 }
 
 static int
@@ -406,40 +462,24 @@ ble_gatts_dsc_inc_stat(uint8_t gatt_op)
 
 static int
 ble_gatts_dsc_access(uint16_t conn_handle, uint16_t attr_handle,
-                     uint8_t *uuid128, uint8_t att_op,
-                     struct ble_att_svr_access_ctxt *att_ctxt, void *arg)
+                     uint8_t att_op, uint16_t offset, struct os_mbuf **om,
+                     void *arg)
 {
-    struct ble_gatt_access_ctxt gatt_ctxt;
     const struct ble_gatt_dsc_def *dsc_def;
+    struct ble_gatt_access_ctxt gatt_ctxt;
     int rc;
 
     dsc_def = arg;
     BLE_HS_DBG_ASSERT(dsc_def != NULL && dsc_def->access_cb != NULL);
 
     gatt_ctxt.op = ble_gatts_dsc_op(att_op);
-    switch (gatt_ctxt.op) {
-    case BLE_GATT_ACCESS_OP_READ_DSC:
-        break;
-
-    case BLE_GATT_ACCESS_OP_WRITE_DSC:
-        break;
-
-    default:
-        BLE_HS_DBG_ASSERT(0);
-        return BLE_HS_EUNKNOWN;
-    }
+    gatt_ctxt.dsc = dsc_def;
 
     ble_gatts_dsc_inc_stat(gatt_ctxt.op);
+    rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om,
+                              dsc_def->access_cb, dsc_def->arg);
 
-    gatt_ctxt.dsc = dsc_def;
-    gatt_ctxt.att = att_ctxt;
-    rc = dsc_def->access_cb(conn_handle, attr_handle, &gatt_ctxt,
-                            dsc_def->arg);
-    if (rc != 0) {
-        return rc;
-    }
-
-    return 0;
+    return rc;
 }
 
 static int
@@ -561,8 +601,8 @@ ble_gatts_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,
  */
 static int
 ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
-                                uint8_t att_op,
-                                struct ble_att_svr_access_ctxt *ctxt,
+                                uint8_t att_op, uint16_t offset,
+                                struct os_mbuf *om,
                                 struct ble_store_value_cccd *out_cccd,
                                 uint8_t *out_prev_clt_cfg_flags,
                                 uint8_t *out_cur_clt_cfg_flags)
@@ -571,8 +611,7 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
     uint16_t chr_val_handle;
     uint16_t flags;
     uint8_t gatt_op;
-
-    static uint8_t buf[2];
+    uint8_t *buf;
 
     /* Assume nothing needs to be persisted. */
     out_cccd->chr_val_handle = 0;
@@ -602,18 +641,23 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
     switch (gatt_op) {
     case BLE_GATT_ACCESS_OP_READ_DSC:
         STATS_INC(ble_gatts_stats, dsc_reads);
+        buf = os_mbuf_extend(om, 2);
+        if (buf == NULL) {
+            return BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
         htole16(buf, clt_cfg->flags & ~BLE_GATTS_CLT_CFG_F_RESERVED);
-        ctxt->read.data = buf;
-        ctxt->read.len = sizeof buf;
         break;
 
     case BLE_GATT_ACCESS_OP_WRITE_DSC:
         STATS_INC(ble_gatts_stats, dsc_writes);
-        if (ctxt->write.len != 2) {
+        if (OS_MBUF_PKTLEN(om) != 2) {
             return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
         }
 
-        flags = le16toh(ctxt->write.data);
+        om = os_mbuf_pullup(om, 2);
+        BLE_HS_DBG_ASSERT(om != NULL);
+
+        flags = le16toh(om->om_data);
         if ((flags & ~clt_cfg->allowed) != 0) {
             return BLE_ATT_ERR_WRITE_NOT_PERMITTED;
         }
@@ -643,8 +687,7 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle,
 
 static int
 ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
-                         uint8_t *uuid128, uint8_t op,
-                         struct ble_att_svr_access_ctxt *ctxt,
+                         uint8_t op, uint16_t offset, struct os_mbuf **om,
                          void *arg)
 {
     struct ble_store_value_cccd cccd_value;
@@ -661,9 +704,8 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
     if (conn == NULL) {
         rc = BLE_ATT_ERR_UNLIKELY;
     } else {
-        rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, op, ctxt,
-                                             &cccd_value,
-                                             &prev_flags,
+        rc = ble_gatts_clt_cfg_access_locked(conn, attr_handle, op, offset,
+                                             *om, &cccd_value, &prev_flags,
                                              &cur_flags);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_hs.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs.c b/net/nimble/host/src/ble_hs.c
index 5a40804..3d37c47 100644
--- a/net/nimble/host/src/ble_hs.c
+++ b/net/nimble/host/src/ble_hs.c
@@ -165,7 +165,7 @@ ble_hs_process_tx_data_queue(void)
     }
 }
 
-static void
+void
 ble_hs_process_rx_data_queue(void)
 {
     struct os_mbuf *om;
@@ -343,16 +343,19 @@ ble_hs_start(void)
  * @return                      0 on success; nonzero on failure.
  */
 int
-ble_hs_rx_data(struct os_mbuf *om)
+ble_hs_rx_data(struct os_mbuf **om)
 {
     int rc;
 
-    rc = os_mqueue_put(&ble_hs_rx_q, &ble_hs_evq, om);
-    if (rc != 0) {
-        return BLE_HS_EOS;
+    rc = os_mqueue_put(&ble_hs_rx_q, &ble_hs_evq, *om);
+    if (rc == 0) {
+        *om = NULL;
+    } else {
+        rc = BLE_HS_EOS;
     }
     os_eventq_put(ble_hs_parent_evq, &ble_hs_event_co.cf_c.c_ev);
 
+    os_mbuf_free_chain(*om);
     return 0;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_hs_mbuf.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_mbuf.c b/net/nimble/host/src/ble_hs_mbuf.c
new file mode 100644
index 0000000..7b8f47f
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_mbuf.c
@@ -0,0 +1,171 @@
+/**
+ * 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 "host/ble_hs.h"
+#include "ble_hs_priv.h"
+
+/**
+ * Allocates an mbuf for use by the nimble host.
+ */
+static struct os_mbuf *
+ble_hs_mbuf_gen_pkt(uint16_t leading_space)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = os_msys_get_pkthdr(0, 0);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    if (om->om_omp->omp_databuf_len < leading_space) {
+        rc = os_mbuf_free_chain(om);
+        BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+        return NULL;
+    }
+
+    om->om_data += leading_space;
+
+    return om;
+}
+
+/**
+ * Allocates an mbuf with no leading space.
+ *
+ * @return                  An empty mbuf on success; null on memory
+ *                              exhaustion.
+ */
+struct os_mbuf *
+ble_hs_mbuf_bare_pkt(void)
+{
+    return ble_hs_mbuf_gen_pkt(0);
+}
+
+/**
+ * Allocates an mbuf suitable for an HCI ACM data packet.
+ *
+ * @return                  An empty mbuf on success; null on memory
+ *                              exhaustion.
+ */
+struct os_mbuf *
+ble_hs_mbuf_acm_pkt(void)
+{
+    return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ);
+}
+
+/**
+ * Allocates an mbuf suitable for an L2CAP data packet.  The resulting packet
+ * has sufficient leading space for:
+ *     o ACM data header
+ *     o L2CAP B-frame header
+ *
+ * @return                  An empty mbuf on success; null on memory
+ *                              exhaustion.
+ */
+struct os_mbuf *
+ble_hs_mbuf_l2cap_pkt(void)
+{
+    return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + BLE_L2CAP_HDR_SZ);
+}
+
+/**
+ * Allocates an mbuf suitable for an ATT command packet.  The resulting packet
+ * has sufficient leading space for:
+ *     o ACM data header
+ *     o L2CAP B-frame header
+ *     o Largest ATT command base (prepare write request / response).
+ *
+ * @return                  An empty mbuf on success; null on memory
+ *                              exhaustion.
+ */
+struct os_mbuf *
+ble_hs_mbuf_att_pkt(void)
+{
+    /* Prepare write request and response are the larget ATT commands which
+     * contain attribute data.
+     */
+     return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ +
+                                BLE_L2CAP_HDR_SZ +
+                                BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
+}
+
+struct os_mbuf *
+ble_hs_mbuf_from_flat(const void *buf, uint16_t len)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_mbuf_att_pkt();
+    if (om == NULL) {
+        return NULL;
+    }
+
+    rc = os_mbuf_copyinto(om, 0, buf, len);
+    if (rc != 0) {
+        os_mbuf_free_chain(om);
+        return NULL;
+    }
+
+    return om;
+}
+
+int
+ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
+                    uint16_t *out_copy_len)
+{
+    uint16_t copy_len;
+    int rc;
+
+    if (OS_MBUF_PKTLEN(om) <= max_len) {
+        copy_len = OS_MBUF_PKTLEN(om);
+    } else {
+        copy_len = max_len;
+    }
+
+    rc = os_mbuf_copydata(om, 0, copy_len, flat);
+    if (rc != 0) {
+        return BLE_HS_EUNKNOWN;
+    }
+
+    if (copy_len > max_len) {
+        rc = BLE_HS_EMSGSIZE;
+    } else {
+        rc = 0;
+    }
+
+    if (out_copy_len != NULL) {
+        *out_copy_len = copy_len;
+    }
+    return rc;
+}
+
+int
+ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len)
+{
+    if (OS_MBUF_PKTLEN(*om) < base_len) {
+        return BLE_HS_EBADDATA;
+    }
+
+    *om = os_mbuf_pullup(*om, base_len);
+    if (*om == NULL) {
+        return BLE_HS_ENOMEM;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_hs_mbuf_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_mbuf_priv.h b/net/nimble/host/src/ble_hs_mbuf_priv.h
new file mode 100644
index 0000000..f0ea9b5
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_mbuf_priv.h
@@ -0,0 +1,11 @@
+#ifndef H_BLE_HS_MBUF_PRIV_
+#define H_BLE_HS_MBUF_PRIV_
+
+struct os_mbuf;
+
+struct os_mbuf *ble_hs_mbuf_bare_pkt(void);
+struct os_mbuf *ble_hs_mbuf_acm_pkt(void);
+struct os_mbuf *ble_hs_mbuf_l2cap_pkt(void);
+int ble_hs_mbuf_pullup_base(struct os_mbuf **om, int base_len);
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_hs_misc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_misc.c b/net/nimble/host/src/ble_hs_misc.c
index 616b0b5..216196b 100644
--- a/net/nimble/host/src/ble_hs_misc.c
+++ b/net/nimble/host/src/ble_hs_misc.c
@@ -45,47 +45,6 @@ ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool,
     return 0;
 }
 
-/**
- * Allocates an mbuf for use by the nimble host.
- */
-struct os_mbuf *
-ble_hs_misc_pkthdr(void)
-{
-    struct os_mbuf *om;
-    int rc;
-
-    om = os_msys_get_pkthdr(0, 0);
-    if (om == NULL) {
-        return NULL;
-    }
-
-    /* Make room in the buffer for various headers.  XXX Check this number. */
-    if (om->om_omp->omp_databuf_len < 8) {
-        rc = os_mbuf_free_chain(om);
-        BLE_HS_DBG_ASSERT_EVAL(rc == 0);
-        return NULL;
-    }
-
-    om->om_data += 8;
-
-    return om;
-}
-
-int
-ble_hs_misc_pullup_base(struct os_mbuf **om, int base_len)
-{
-    if (OS_MBUF_PKTLEN(*om) < base_len) {
-        return BLE_HS_EBADDATA;
-    }
-
-    *om = os_mbuf_pullup(*om, base_len);
-    if (*om == NULL) {
-        return BLE_HS_ENOMEM;
-    }
-
-    return 0;
-}
-
 int
 ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid,
                            struct ble_hs_conn **out_conn,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_hs_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_priv.h b/net/nimble/host/src/ble_hs_priv.h
index a6bb882..79ef6b9 100644
--- a/net/nimble/host/src/ble_hs_priv.h
+++ b/net/nimble/host/src/ble_hs_priv.h
@@ -31,6 +31,7 @@
 #include "ble_hs_conn_priv.h"
 #include "ble_hs_atomic_priv.h"
 #include "ble_hs_endian_priv.h"
+#include "ble_hs_mbuf_priv.h"
 #include "ble_hs_startup_priv.h"
 #include "ble_l2cap_priv.h"
 #include "ble_l2cap_sig_priv.h"
@@ -66,7 +67,7 @@ extern struct os_mbuf_pool ble_hs_mbuf_pool;
 extern const uint8_t ble_hs_misc_null_addr[6];
 
 void ble_hs_process_tx_data_queue(void);
-int ble_hs_rx_data(struct os_mbuf *om);
+void ble_hs_process_rx_data_queue(void);
 int ble_hs_tx_data(struct os_mbuf *om);
 
 int ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool,
@@ -88,10 +89,6 @@ void ble_hs_unlock(void);
 void ble_hs_heartbeat_sched(int32_t ticks);
 void ble_hs_notifications_sched(void);
 
-struct os_mbuf *ble_hs_misc_pkthdr(void);
-
-int ble_hs_misc_pullup_base(struct os_mbuf **om, int base_len);
-
 #if LOG_LEVEL <= LOG_LEVEL_DEBUG
 
 #define BLE_HS_LOG_CMD(is_tx, cmd_type, cmd_name, conn_handle,                \

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_l2cap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap.c b/net/nimble/host/src/ble_l2cap.c
index da66bf1..7f284f5 100644
--- a/net/nimble/host/src/ble_l2cap.c
+++ b/net/nimble/host/src/ble_l2cap.c
@@ -79,7 +79,7 @@ ble_l2cap_chan_free(struct ble_l2cap_chan *chan)
 }
 
 uint16_t
-ble_l2cap_chan_mtu(struct ble_l2cap_chan *chan)
+ble_l2cap_chan_mtu(const struct ble_l2cap_chan *chan)
 {
     uint16_t mtu;
 
@@ -120,14 +120,16 @@ struct os_mbuf *
 ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid, uint16_t len)
 {
     struct ble_l2cap_hdr hdr;
+    struct os_mbuf *om2;
 
     htole16(&hdr.blh_len, len);
     htole16(&hdr.blh_cid, cid);
 
-    om = os_mbuf_prepend(om, sizeof hdr);
-    if (om == NULL) {
+    om2 = os_mbuf_prepend(om, sizeof hdr);
+    if (om2 == NULL) {
         return NULL;
     }
+    BLE_HS_DBG_ASSERT(om2 == om);
 
     memcpy(om->om_data, &hdr, sizeof hdr);
 
@@ -276,18 +278,22 @@ err:
  */
 int
 ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
-             struct os_mbuf *om)
+             struct os_mbuf **txom)
 {
+    struct os_mbuf *om;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     om = ble_l2cap_prepend_hdr(om, chan->blc_cid, OS_MBUF_PKTLEN(om));
     if (om == NULL) {
         rc = BLE_HS_ENOMEM;
         goto err;
     }
 
-    rc = host_hci_data_tx(conn, om);
-    om = NULL;
+    rc = host_hci_data_tx(conn, &om);
     if (rc != 0) {
         goto err;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_l2cap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_priv.h b/net/nimble/host/src/ble_l2cap_priv.h
index 9cbf879..3eaf245 100644
--- a/net/nimble/host/src/ble_l2cap_priv.h
+++ b/net/nimble/host/src/ble_l2cap_priv.h
@@ -94,7 +94,7 @@ struct os_mbuf *ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid,
 struct ble_l2cap_chan *ble_l2cap_chan_alloc(void);
 void ble_l2cap_chan_free(struct ble_l2cap_chan *chan);
 
-uint16_t ble_l2cap_chan_mtu(struct ble_l2cap_chan *chan);
+uint16_t ble_l2cap_chan_mtu(const struct ble_l2cap_chan *chan);
 
 
 int ble_l2cap_rx(struct ble_hs_conn *conn,
@@ -103,7 +103,7 @@ int ble_l2cap_rx(struct ble_hs_conn *conn,
                  ble_l2cap_rx_fn **out_rx_cb,
                  struct os_mbuf **out_rx_buf);
 int ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
-                 struct os_mbuf *om);
+                 struct os_mbuf **txom);
 
 int ble_l2cap_init(void);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_l2cap_sig.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sig.c b/net/nimble/host/src/ble_l2cap_sig.c
index dd418f2..4838067 100644
--- a/net/nimble/host/src/ble_l2cap_sig.c
+++ b/net/nimble/host/src/ble_l2cap_sig.c
@@ -300,7 +300,7 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle,
 
     l2cap_result = 0; /* Silence spurious gcc warning. */
 
-    rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_UPDATE_REQ_SZ);
+    rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_REQ_SZ);
     if (rc != 0) {
         return rc;
     }
@@ -373,7 +373,7 @@ ble_l2cap_sig_update_rsp_rx(uint16_t conn_handle,
         return BLE_HS_ENOENT;
     }
 
-    rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_UPDATE_RSP_SZ);
+    rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_RSP_SZ);
     if (rc != 0) {
         cb_status = rc;
         goto done;
@@ -482,7 +482,7 @@ ble_l2cap_sig_rx(uint16_t conn_handle, struct os_mbuf **om)
     ble_hs_log_mbuf(*om);
     BLE_HS_LOG(DEBUG, "\n");
 
-    rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SIG_HDR_SZ);
+    rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_HDR_SZ);
     if (rc != 0) {
         return rc;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_l2cap_sig_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sig_cmd.c b/net/nimble/host/src/ble_l2cap_sig_cmd.c
index a93833c..6b08a2b 100644
--- a/net/nimble/host/src/ble_l2cap_sig_cmd.c
+++ b/net/nimble/host/src/ble_l2cap_sig_cmd.c
@@ -27,18 +27,21 @@ ble_l2cap_sig_init_cmd(uint8_t op, uint8_t id, uint8_t payload_len,
     struct ble_l2cap_sig_hdr hdr;
     struct os_mbuf *txom;
     void *v;
+    int rc;
 
     *out_om = NULL;
     *out_payload_buf = NULL;
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
-        return BLE_HS_ENOMEM;
+        rc = BLE_HS_ENOMEM;
+        goto err;
     }
 
     v = os_mbuf_extend(txom, BLE_L2CAP_SIG_HDR_SZ + payload_len);
     if (v == NULL) {
-        return BLE_HS_ENOMEM;
+        rc = BLE_HS_ENOMEM;
+        goto err;
     }
 
     hdr.op = op;
@@ -51,6 +54,10 @@ ble_l2cap_sig_init_cmd(uint8_t op, uint8_t id, uint8_t payload_len,
     *out_payload_buf = (uint8_t *)v + BLE_L2CAP_SIG_HDR_SZ;
 
     return 0;
+
+err:
+    os_mbuf_free(txom);
+    return rc;
 }
 
 static void
@@ -113,14 +120,21 @@ ble_l2cap_sig_reject_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     rc = ble_l2cap_sig_init_cmd(BLE_L2CAP_SIG_OP_REJECT, id,
                                 BLE_L2CAP_SIG_REJECT_MIN_SZ + data_len, &txom,
                                 &payload_buf);
+    if (rc != 0) {
+        return rc;
+    }
 
     cmd.reason = reason;
     ble_l2cap_sig_reject_write(payload_buf, txom->om_len, &cmd,
                                data, data_len);
 
     STATS_INC(ble_l2cap_stats, sig_rx);
-    rc = ble_l2cap_tx(conn, chan, txom);
-    return rc;
+    rc = ble_l2cap_tx(conn, chan, &txom);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
 }
 
 int
@@ -189,7 +203,7 @@ ble_l2cap_sig_update_req_tx(struct ble_hs_conn *conn,
     ble_l2cap_sig_update_req_write(payload_buf, BLE_L2CAP_SIG_UPDATE_REQ_SZ,
                                    req);
 
-    rc = ble_l2cap_tx(conn, chan, txom);
+    rc = ble_l2cap_tx(conn, chan, &txom);
     if (rc != 0) {
         return rc;
     }
@@ -241,7 +255,7 @@ ble_l2cap_sig_update_rsp_tx(struct ble_hs_conn *conn,
     ble_l2cap_sig_update_rsp_write(payload_buf, BLE_L2CAP_SIG_UPDATE_RSP_SZ,
                                    &rsp);
 
-    rc = ble_l2cap_tx(conn, chan, txom);
+    rc = ble_l2cap_tx(conn, chan, &txom);
     if (rc != 0) {
         return rc;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm.c b/net/nimble/host/src/ble_sm.c
index 6f77db2..ae2e5f8 100644
--- a/net/nimble/host/src/ble_sm.c
+++ b/net/nimble/host/src/ble_sm.c
@@ -1285,7 +1285,7 @@ ble_sm_random_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1335,7 +1335,7 @@ ble_sm_confirm_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *prev;
     uint8_t ioact;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1496,7 +1496,7 @@ ble_sm_pair_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *prev;
     struct ble_hs_conn *conn;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
     if (res->app_status != 0) {
         return;
     }
@@ -1553,7 +1553,7 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *prev;
     uint8_t ioact;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
     if (res->app_status != 0) {
         res->enc_cb = 1;
         return;
@@ -1616,7 +1616,7 @@ ble_sm_sec_req_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_hs_conn *conn;
     int authreq_mitm;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SEC_REQ_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_SEC_REQ_SZ);
     if (res->app_status != 0) {
         return;
     }
@@ -1841,7 +1841,7 @@ ble_sm_enc_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ENC_INFO_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ENC_INFO_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1877,7 +1877,7 @@ ble_sm_master_id_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_MASTER_ID_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_MASTER_ID_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1914,7 +1914,7 @@ ble_sm_id_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_INFO_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ID_INFO_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1951,7 +1951,7 @@ ble_sm_id_addr_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -1989,7 +1989,7 @@ ble_sm_sign_info_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SIGN_INFO_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_SIGN_INFO_SZ);
     if (res->app_status != 0) {
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
         res->enc_cb = 1;
@@ -2030,7 +2030,7 @@ ble_sm_fail_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
 
     res->enc_cb = 1;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_FAIL_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PAIR_FAIL_SZ);
     if (res->app_status == 0) {
         ble_sm_pair_fail_parse((*om)->om_data, (*om)->om_len, &cmd);
         BLE_SM_LOG_CMD(0, "fail", conn_handle, ble_sm_pair_fail_log, &cmd);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_sm_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm_cmd.c b/net/nimble/host/src/ble_sm_cmd.c
index 5f5026f..86b0c7b 100644
--- a/net/nimble/host/src/ble_sm_cmd.c
+++ b/net/nimble/host/src/ble_sm_cmd.c
@@ -28,12 +28,17 @@
 #if NIMBLE_OPT(SM)
 
 static int
-ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom)
+ble_sm_tx(uint16_t conn_handle, struct os_mbuf **txom)
 {
     struct ble_l2cap_chan *chan;
     struct ble_hs_conn *conn;
+    struct os_mbuf *om;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
 
     STATS_INC(ble_l2cap_stats, sm_tx);
@@ -41,7 +46,7 @@ ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom)
     rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM,
                                          &conn, &chan);
     if (rc == 0) {
-        rc = ble_l2cap_tx(conn, chan, txom);
+        rc = ble_l2cap_tx(conn, chan, &om);
     }
 
     return rc;
@@ -53,7 +58,7 @@ ble_sm_init_req(uint16_t initial_sz, struct os_mbuf **out_txom)
     void *buf;
     int rc;
 
-    *out_txom = ble_hs_misc_pkthdr();
+    *out_txom = ble_hs_mbuf_l2cap_pkt();
     if (*out_txom == NULL) {
         rc = BLE_HS_ENOMEM;
         goto err;
@@ -157,8 +162,10 @@ ble_sm_pair_cmd_tx(uint16_t conn_handle, int is_req,
                    ble_sm_pair_cmd_log, cmd);
     BLE_HS_DBG_ASSERT(ble_sm_pair_cmd_is_valid(cmd));
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -204,7 +211,6 @@ ble_sm_pair_confirm_tx(uint16_t conn_handle, struct ble_sm_pair_confirm *cmd)
     struct os_mbuf *txom;
     int rc;
 
-
     rc = ble_sm_init_req(BLE_SM_PAIR_CONFIRM_SZ, &txom);
     if (rc != 0) {
         rc = BLE_HS_ENOMEM;
@@ -214,8 +220,10 @@ ble_sm_pair_confirm_tx(uint16_t conn_handle, struct ble_sm_pair_confirm *cmd)
     ble_sm_pair_confirm_write(txom->om_data, txom->om_len, cmd);
     BLE_SM_LOG_CMD(1, "confirm", conn_handle, ble_sm_pair_confirm_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -267,8 +275,10 @@ ble_sm_pair_random_tx(uint16_t conn_handle, struct ble_sm_pair_random *cmd)
     ble_sm_pair_random_write(txom->om_data, txom->om_len, cmd);
     BLE_SM_LOG_CMD(1, "random", conn_handle, ble_sm_pair_random_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -327,8 +337,10 @@ ble_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason)
     ble_sm_pair_fail_write(txom->om_data, txom->om_len, &cmd);
     BLE_SM_LOG_CMD(1, "fail", conn_handle, ble_sm_pair_fail_log, &cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -376,8 +388,10 @@ ble_sm_enc_info_tx(uint16_t conn_handle, struct ble_sm_enc_info *cmd)
 
     BLE_SM_LOG_CMD(1, "enc info", conn_handle, ble_sm_enc_info_log, cmd);
     
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -434,8 +448,10 @@ ble_sm_master_id_tx(uint16_t conn_handle, struct ble_sm_master_id *cmd)
 
     BLE_SM_LOG_CMD(1, "master id", conn_handle, ble_sm_master_id_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -487,8 +503,10 @@ ble_sm_id_info_tx(uint16_t conn_handle, struct ble_sm_id_info *cmd)
 
     ble_sm_id_info_write(txom->om_data, txom->om_len, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -543,8 +561,10 @@ ble_sm_id_addr_info_tx(uint16_t conn_handle, struct ble_sm_id_addr_info *cmd)
 
     ble_sm_id_addr_info_write(txom->om_data, txom->om_len, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -593,8 +613,10 @@ ble_sm_sign_info_tx(uint16_t conn_handle, struct ble_sm_sign_info *cmd)
 
     ble_sm_sign_info_write(txom->om_data, txom->om_len, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -648,8 +670,10 @@ ble_sm_sec_req_tx(uint16_t conn_handle, struct ble_sm_sec_req *cmd)
 
     BLE_SM_LOG_CMD(1, "sec req", conn_handle, ble_sm_sec_req_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -713,8 +737,10 @@ ble_sm_public_key_tx(uint16_t conn_handle, struct ble_sm_public_key *cmd)
 
     BLE_SM_LOG_CMD(1, "public key", conn_handle, ble_sm_public_key_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);
@@ -774,8 +800,10 @@ ble_sm_dhkey_check_tx(uint16_t conn_handle, struct ble_sm_dhkey_check *cmd)
 
     BLE_SM_LOG_CMD(1, "dhkey check", conn_handle, ble_sm_dhkey_check_log, cmd);
 
-    rc = ble_sm_tx(conn_handle, txom);
-    txom = NULL;
+    rc = ble_sm_tx(conn_handle, &txom);
+    if (rc != 0) {
+        goto done;
+    }
 
 done:
     os_mbuf_free_chain(txom);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_sm_sc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm_sc.c b/net/nimble/host/src/ble_sm_sc.c
index c2980b6..455da90 100644
--- a/net/nimble/host/src/ble_sm_sc.c
+++ b/net/nimble/host/src/ble_sm_sc.c
@@ -482,7 +482,7 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *prev;
     int rc;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PUBLIC_KEY_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PUBLIC_KEY_SZ);
     if (res->app_status != 0) {
         res->enc_cb = 1;
         return;
@@ -693,7 +693,7 @@ ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_DHKEY_CHECK_SZ);
+    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_DHKEY_CHECK_SZ);
     if (res->app_status != 0) {
         res->enc_cb = 1;
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/host_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c
index 86e77c5..887c6fa 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -758,11 +758,18 @@ static struct os_mbuf *
 host_hci_data_hdr_prepend(struct os_mbuf *om, uint16_t handle, uint8_t pb_flag)
 {
     struct hci_data_hdr hci_hdr;
+    struct os_mbuf *om2;
 
     hci_hdr.hdh_handle_pb_bc = host_hci_handle_pb_bc_join(handle, pb_flag, 0);
     htole16(&hci_hdr.hdh_len, OS_MBUF_PKTHDR(om)->omp_len);
 
-    om = os_mbuf_prepend(om, sizeof hci_hdr);
+    om2 = os_mbuf_prepend(om, sizeof hci_hdr);
+    if (om2 == NULL) {
+        return NULL;
+    }
+    BLE_HS_DBG_ASSERT(om2 == om);
+
+    om = os_mbuf_pullup(om, sizeof hci_hdr);
     if (om == NULL) {
         return NULL;
     }
@@ -805,7 +812,7 @@ host_hci_split_frag(struct os_mbuf *om, struct os_mbuf **out_frag)
         return BLE_HS_EDONE;
     }
 
-    frag = os_msys_get_pkthdr(host_hci_buffer_sz, 0);
+    frag = ble_hs_mbuf_acm_pkt();
     if (frag == NULL) {
         rc = BLE_HS_ENOMEM;
         goto err;
@@ -836,13 +843,18 @@ err:
  * fragments.
  */
 int
-host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om)
+host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf **txom)
 {
     struct os_mbuf *frag;
+    struct os_mbuf *om;
     uint8_t pb;
     int done;
     int rc;
 
+    /* Consume mbuf from caller. */
+    om = *txom;
+    *txom = NULL;
+
     /* The first fragment uses the first-non-flush packet boundary value.
      * After sending the first fragment, pb gets set appropriately for all
      * subsequent fragments in this packet.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_att_clt_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_att_clt_test.c b/net/nimble/host/src/test/ble_att_clt_test.c
index dcb402e..869fb19 100644
--- a/net/nimble/host/src/test/ble_att_clt_test.c
+++ b/net/nimble/host/src/test/ble_att_clt_test.c
@@ -63,14 +63,17 @@ ble_att_clt_test_tx_write_req_or_cmd(uint16_t conn_handle,
                                      struct ble_att_write_req *req,
                                      void *value, int value_len, int is_req)
 {
+    struct os_mbuf *om;
     int rc;
 
+    om = ble_hs_test_util_om_from_flat(value, value_len);
     if (is_req) {
-        rc = ble_att_clt_tx_write_req(conn_handle, req, value, value_len);
+        rc = ble_att_clt_tx_write_req(conn_handle, req, &om);
     } else {
-        rc = ble_att_clt_tx_write_cmd(conn_handle, req, value, value_len);
+        rc = ble_att_clt_tx_write_cmd(conn_handle, req, &om);
     }
     TEST_ASSERT(rc == 0);
+    TEST_ASSERT(om == NULL);
 }
 
 TEST_CASE(ble_att_clt_test_tx_find_info)
@@ -212,9 +215,10 @@ ble_att_clt_test_misc_prep_good(uint16_t handle, uint16_t offset,
 
     req.bapc_handle = handle;
     req.bapc_offset = offset;
-    rc = ble_att_clt_tx_prep_write(conn_handle, &req, attr_data,
-                                   attr_data_len);
+    om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len);
+    rc = ble_att_clt_tx_prep_write(conn_handle, &req, &om);
     TEST_ASSERT(rc == 0);
+    TEST_ASSERT(om == NULL);
 
     ble_hs_test_util_tx_all();
     om = ble_hs_test_util_prev_tx_dequeue_pullup();
@@ -259,16 +263,19 @@ ble_att_clt_test_misc_prep_bad(uint16_t handle, uint16_t offset,
                                int status)
 {
     struct ble_att_prep_write_cmd req;
+    struct os_mbuf *om;
     uint16_t conn_handle;
     int rc;
 
     conn_handle = ble_att_clt_test_misc_init();
 
+    om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len);
+
     req.bapc_handle = handle;
     req.bapc_offset = offset;
-    rc = ble_att_clt_tx_prep_write(conn_handle, &req, attr_data,
-                                   attr_data_len);
+    rc = ble_att_clt_tx_prep_write(conn_handle, &req, &om);
     TEST_ASSERT(rc == status);
+    TEST_ASSERT(om == NULL);
 }
 
 TEST_CASE(ble_att_clt_test_tx_write)
@@ -504,6 +511,8 @@ TEST_CASE(ble_att_clt_test_tx_exec_write)
 
 TEST_SUITE(ble_att_clt_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_att_clt_test_tx_find_info();
     ble_att_clt_test_rx_find_info();
     ble_att_clt_test_tx_read();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_att_svr_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_att_svr_test.c b/net/nimble/host/src/test/ble_att_svr_test.c
index d8393a8..e5968d5 100644
--- a/net/nimble/host/src/test/ble_att_svr_test.c
+++ b/net/nimble/host/src/test/ble_att_svr_test.c
@@ -27,19 +27,19 @@
 #include "ble_hs_test_util.h"
 
 static uint8_t *ble_att_svr_test_attr_r_1;
-static int ble_att_svr_test_attr_r_1_len;
+static uint16_t ble_att_svr_test_attr_r_1_len;
 static uint8_t *ble_att_svr_test_attr_r_2;
-static int ble_att_svr_test_attr_r_2_len;
+static uint16_t ble_att_svr_test_attr_r_2_len;
 
 static uint8_t ble_att_svr_test_attr_w_1[1024];
-static int ble_att_svr_test_attr_w_1_len;
+static uint16_t ble_att_svr_test_attr_w_1_len;
 static uint8_t ble_att_svr_test_attr_w_2[1024];
-static int ble_att_svr_test_attr_w_2_len;
+static uint16_t ble_att_svr_test_attr_w_2_len;
 
 static uint16_t ble_att_svr_test_n_conn_handle;
 static uint16_t ble_att_svr_test_n_attr_handle;
 static uint8_t ble_att_svr_test_attr_n[1024];
-static int ble_att_svr_test_attr_n_len;
+static uint16_t ble_att_svr_test_attr_n_len;
 
 static int
 ble_att_svr_test_misc_gap_cb(struct ble_gap_event *event, void *arg)
@@ -48,11 +48,11 @@ ble_att_svr_test_misc_gap_cb(struct ble_gap_event *event, void *arg)
     case BLE_GAP_EVENT_NOTIFY_RX:
         ble_att_svr_test_n_conn_handle = event->notify_rx.conn_handle;
         ble_att_svr_test_n_attr_handle = event->notify_rx.attr_handle;
-        TEST_ASSERT_FATAL(event->notify_rx.attr_len <=
+        TEST_ASSERT_FATAL(OS_MBUF_PKTLEN(event->notify_rx.om) <=
                           sizeof ble_att_svr_test_attr_n);
-        ble_att_svr_test_attr_n_len = event->notify_rx.attr_len;
-        memcpy(ble_att_svr_test_attr_n, event->notify_rx.attr_data,
-               event->notify_rx.attr_len);
+        ble_att_svr_test_attr_n_len = OS_MBUF_PKTLEN(event->notify_rx.om);
+        os_mbuf_copydata(event->notify_rx.om, 0, ble_att_svr_test_attr_n_len,
+                         ble_att_svr_test_attr_n);
         break;
 
     default:
@@ -99,18 +99,17 @@ ble_att_svr_test_misc_init(uint16_t mtu)
 
 static int
 ble_att_svr_test_misc_attr_fn_r_1(uint16_t conn_handle, uint16_t attr_handle,
-                                  uint8_t *uuid128, uint8_t op,
-                                  struct ble_att_svr_access_ctxt *ctxt,
-                                  void *arg)
+                                  uint8_t op, uint16_t offset,
+                                  struct os_mbuf **om, void *arg)
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_READ:
-        if (ctxt->read.offset > ble_att_svr_test_attr_r_1_len) {
+        if (offset > ble_att_svr_test_attr_r_1_len) {
             return BLE_ATT_ERR_INVALID_OFFSET;
         }
 
-        ctxt->read.data = ble_att_svr_test_attr_r_1 + ctxt->read.offset;
-        ctxt->read.len = ble_att_svr_test_attr_r_1_len - ctxt->read.offset;
+        os_mbuf_append(*om, ble_att_svr_test_attr_r_1 + offset,
+                       ble_att_svr_test_attr_r_1_len - offset);
         return 0;
 
     default:
@@ -120,18 +119,18 @@ ble_att_svr_test_misc_attr_fn_r_1(uint16_t conn_handle, uint16_t attr_handle,
 
 static int
 ble_att_svr_test_misc_attr_fn_r_2(uint16_t conn_handle, uint16_t attr_handle,
-                                  uint8_t *uuid128, uint8_t op,
-                                  struct ble_att_svr_access_ctxt *ctxt,
-                                  void *arg)
+                                  uint8_t op, uint16_t offset,
+                                  struct os_mbuf **om, void *arg)
 {
 
     switch (op) {
     case BLE_ATT_ACCESS_OP_READ:
-        if (ctxt->read.offset > ble_att_svr_test_attr_r_2_len) {
+        if (offset > ble_att_svr_test_attr_r_2_len) {
             return BLE_ATT_ERR_INVALID_OFFSET;
         }
-        ctxt->read.data = ble_att_svr_test_attr_r_2 + ctxt->read.offset;
-        ctxt->read.len = ble_att_svr_test_attr_r_2_len - ctxt->read.offset;
+
+        os_mbuf_append(*om, ble_att_svr_test_attr_r_2 + offset,
+                       ble_att_svr_test_attr_r_2_len - offset);
         return 0;
 
     default:
@@ -144,11 +143,15 @@ ble_att_svr_test_misc_attr_fn_r_2(uint16_t conn_handle, uint16_t attr_handle,
 
 static int
 ble_att_svr_test_misc_attr_fn_r_group(uint16_t conn_handle,
-                                      uint16_t attr_handle, uint8_t *uuid128,
+                                      uint16_t attr_handle,
                                       uint8_t op,
-                                      struct ble_att_svr_access_ctxt *ctxt,
+                                      uint16_t offset,
+                                      struct os_mbuf **om,
                                       void *arg)
 {
+    uint8_t *src;
+    int rc;
+
     /* Service 0x1122 from 1 to 5 */
     /* Service 0x2233 from 6 to 10 */
     /* Service 010203...0f from 11 to 24 */
@@ -189,11 +192,14 @@ ble_att_svr_test_misc_attr_fn_r_group(uint16_t conn_handle,
     TEST_ASSERT_FATAL(attr_handle >= 1 &&
                       attr_handle <= BLE_ATT_SVR_TEST_LAST_ATTR);
 
-    ctxt->read.data = vals + attr_handle;
-    if (memcmp(ctxt->read.data + 2, zeros, 14) == 0) {
-        ctxt->read.len = 2;
+    src = &vals[attr_handle][0];
+    if (memcmp(src + 2, zeros, 14) == 0) {
+        rc = os_mbuf_append(*om, src, 2);
     } else {
-        ctxt->read.len = 16;
+        rc = os_mbuf_append(*om, src, 16);
+    }
+    if (rc != 0) {
+        return BLE_ATT_ERR_INSUFFICIENT_RES;
     }
 
     return 0;
@@ -281,14 +287,14 @@ ble_att_svr_test_misc_register_group_attrs(void)
 
 static int
 ble_att_svr_test_misc_attr_fn_w_1(uint16_t conn_handle, uint16_t attr_handle,
-                                  uint8_t *uuid128, uint8_t op,
-                                  struct ble_att_svr_access_ctxt *ctxt,
-                                  void *arg)
+                                  uint8_t op, uint16_t offset,
+                                  struct os_mbuf **om, void *arg)
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_WRITE:
-        memcpy(ble_att_svr_test_attr_w_1, ctxt->write.data, ctxt->write.len);
-        ble_att_svr_test_attr_w_1_len = ctxt->write.len;
+        os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om),
+                         ble_att_svr_test_attr_w_1);
+        ble_att_svr_test_attr_w_1_len = OS_MBUF_PKTLEN(*om);
         return 0;
 
     default:
@@ -298,14 +304,14 @@ ble_att_svr_test_misc_attr_fn_w_1(uint16_t conn_handle, uint16_t attr_handle,
 
 static int
 ble_att_svr_test_misc_attr_fn_w_2(uint16_t conn_handle, uint16_t attr_handle,
-                                  uint8_t *uuid128, uint8_t op,
-                                  struct ble_att_svr_access_ctxt *ctxt,
-                                  void *arg)
+                                  uint8_t op, uint16_t offset,
+                                  struct os_mbuf **om, void *arg)
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_WRITE:
-        memcpy(ble_att_svr_test_attr_w_2, ctxt->write.data, ctxt->write.len);
-        ble_att_svr_test_attr_w_2_len = ctxt->write.len;
+        os_mbuf_copydata(*om, 0, OS_MBUF_PKTLEN(*om),
+                         ble_att_svr_test_attr_w_2);
+        ble_att_svr_test_attr_w_2_len = OS_MBUF_PKTLEN(*om);
         return 0;
 
     default:
@@ -404,18 +410,17 @@ ble_att_svr_test_misc_rx_read_mult_req(uint16_t conn_handle,
 }
 
 static void
-ble_att_svr_test_misc_verify_tx_read_mult_rsp(uint16_t conn_handle,
-                                              struct ble_gatt_attr *attrs,
-                                              int num_attrs)
+ble_att_svr_test_misc_verify_tx_read_mult_rsp(
+    uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs,
+    int num_attrs)
 {
     struct ble_l2cap_chan *chan;
     struct os_mbuf *om;
+    uint16_t attr_len;
     uint16_t mtu;
-    const uint8_t *attr_value;
     uint8_t u8;
     int rc;
     int off;
-    int ii;
     int i;
 
     ble_hs_test_util_tx_all();
@@ -437,25 +442,21 @@ ble_att_svr_test_misc_verify_tx_read_mult_rsp(uint16_t conn_handle,
 
     off = 1;
     for (i = 0; i < num_attrs; i++) {
-        attr_value = attrs[i].value;
+        attr_len = min(attrs[i].value_len, mtu - off);
 
-        for (ii = 0; ii < attrs[i].value_len && off < mtu; ii++) {
-            rc = os_mbuf_copydata(om, off, 1, &u8);
-            TEST_ASSERT(rc == 0);
-            TEST_ASSERT(u8 == attr_value[ii]);
+        rc = os_mbuf_cmpf(om, off, attrs[i].value, attr_len);
+        TEST_ASSERT(rc == 0);
 
-            off++;
-        }
+        off += attr_len;
     }
 
-    rc = os_mbuf_copydata(om, off, 1, &u8);
-    TEST_ASSERT(rc != 0);
+    TEST_ASSERT(OS_MBUF_PKTLEN(om) == off);
 }
 
 static void
-ble_att_svr_test_misc_verify_all_read_mult(uint16_t conn_handle,
-                                           struct ble_gatt_attr *attrs,
-                                           int num_attrs)
+ble_att_svr_test_misc_verify_all_read_mult(
+    uint16_t conn_handle, struct ble_hs_test_util_flat_attr *attrs,
+    int num_attrs)
 {
     uint16_t handles[256];
     int i;
@@ -809,6 +810,7 @@ ble_att_svr_test_misc_mtu_exchange(uint16_t my_mtu, uint16_t peer_sent,
     TEST_ASSERT(chan->blc_peer_mtu == peer_actual);
     TEST_ASSERT(ble_l2cap_chan_mtu(chan) == chan_mtu);
     ble_hs_unlock();
+
 }
 
 static void
@@ -995,12 +997,11 @@ TEST_CASE(ble_att_svr_test_read)
 {
     struct ble_att_read_req req;
     struct ble_hs_conn *conn;
+    struct os_mbuf *om;
     uint16_t conn_handle;
-    uint16_t attr_len;
     uint8_t buf[BLE_ATT_READ_REQ_SZ];
     uint8_t uuid_sec[16] = {1};
     uint8_t uuid[16] = {0};
-    const void *attr_data;
     int rc;
 
     conn_handle = ble_att_svr_test_misc_init(0);
@@ -1061,10 +1062,12 @@ TEST_CASE(ble_att_svr_test_read)
                                             BLE_ATT_ERR_INSUFFICIENT_AUTHEN);
 
     /* Security check bypassed for local reads. */
-    rc = ble_att_svr_read_local(req.barq_handle, &attr_data, &attr_len);
-    TEST_ASSERT(rc == 0);
-    TEST_ASSERT(attr_len == ble_att_svr_test_attr_r_1_len);
-    TEST_ASSERT(attr_data == ble_att_svr_test_attr_r_1);
+    rc = ble_att_svr_read_local(req.barq_handle, &om);
+    TEST_ASSERT_FATAL(rc == 0);
+    TEST_ASSERT(OS_MBUF_PKTLEN(om) == ble_att_svr_test_attr_r_1_len);
+    TEST_ASSERT(os_mbuf_cmpf(om, 0, ble_att_svr_test_attr_r_1,
+                               ble_att_svr_test_attr_r_1_len) == 0);
+    os_mbuf_free_chain(om);
 
     /* Ensure no response got sent. */
     ble_hs_test_util_tx_all();
@@ -1081,6 +1084,7 @@ TEST_CASE(ble_att_svr_test_read)
     TEST_ASSERT(rc == 0);
     ble_hs_test_util_verify_tx_read_rsp(ble_att_svr_test_attr_r_1,
                                         BLE_ATT_MTU_DFLT - 1);
+
 }
 
 TEST_CASE(ble_att_svr_test_read_blob)
@@ -1104,11 +1108,12 @@ TEST_CASE(ble_att_svr_test_read_blob)
     ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ, 0,
                                             BLE_ATT_ERR_INVALID_HANDLE);
 
-    /*** Short read failure. */
+
+    /*** Successful partial read. */
     ble_att_svr_test_attr_r_1 =
         (uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,
                     22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};
-    ble_att_svr_test_attr_r_1_len = BLE_ATT_MTU_DFLT - 3;
+    ble_att_svr_test_attr_r_1_len = 40;
     rc = ble_att_svr_register(uuid, HA_FLAG_PERM_RW, &req.babq_handle,
                               ble_att_svr_test_misc_attr_fn_r_1, NULL);
     TEST_ASSERT(rc == 0);
@@ -1117,18 +1122,6 @@ TEST_CASE(ble_att_svr_test_read_blob)
 
     rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
                                                 buf, sizeof buf);
-    TEST_ASSERT(rc != 0);
-    ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_BLOB_REQ,
-                                            req.babq_handle,
-                                            BLE_ATT_ERR_ATTR_NOT_LONG);
-
-    /*** Successful partial read. */
-    ble_att_svr_test_attr_r_1_len = 40;
-
-    ble_att_read_blob_req_write(buf, sizeof buf, &req);
-
-    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
-                                                buf, sizeof buf);
     TEST_ASSERT(rc == 0);
     ble_att_svr_test_misc_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1,
                                                   BLE_ATT_MTU_DFLT - 1);
@@ -1153,32 +1146,43 @@ TEST_CASE(ble_att_svr_test_read_blob)
     TEST_ASSERT(rc == 0);
     ble_att_svr_test_misc_verify_tx_read_blob_rsp(ble_att_svr_test_attr_r_1,
                                                   0);
+
 }
 
 TEST_CASE(ble_att_svr_test_read_mult)
 {
-    struct ble_gatt_attr attr1;
-    struct ble_gatt_attr attr2;
     uint16_t conn_handle;
     int rc;
 
     conn_handle = ble_att_svr_test_misc_init(0);
 
-    attr1.value = (uint8_t[]){ 1, 2, 3, 4 };
-    attr1.value_len = 4;
-    ble_att_svr_test_attr_r_1 = (void *)attr1.value;
-    ble_att_svr_test_attr_r_1_len = attr1.value_len;
+    struct ble_hs_test_util_flat_attr attrs[2] = {
+        {
+            .handle = 0,
+            .offset = 0,
+            .value = { 1, 2, 3, 4 },
+            .value_len = 4,
+        },
+        {
+            .handle = 0,
+            .offset = 0,
+            .value = { 2, 3, 4, 5, 6 },
+            .value_len = 5,
+        },
+    };
+
+    ble_att_svr_test_attr_r_1 = attrs[0].value;
+    ble_att_svr_test_attr_r_1_len = attrs[0].value_len;
+    ble_att_svr_test_attr_r_2 = attrs[1].value;
+    ble_att_svr_test_attr_r_2_len = attrs[1].value_len;
+
     rc = ble_att_svr_register(BLE_UUID16(0x1111), HA_FLAG_PERM_RW,
-                              &attr1.handle,
+                              &attrs[0].handle,
                               ble_att_svr_test_misc_attr_fn_r_1, NULL);
     TEST_ASSERT(rc == 0);
 
-    attr2.value = (uint8_t[]){ 2, 3, 4, 5, 6 };
-    attr2.value_len = 5;
-    ble_att_svr_test_attr_r_2 = (void *)attr2.value;
-    ble_att_svr_test_attr_r_2_len = attr2.value_len;
     rc = ble_att_svr_register(BLE_UUID16(0x2222), HA_FLAG_PERM_RW,
-                              &attr2.handle,
+                              &attrs[1].handle,
                               ble_att_svr_test_misc_attr_fn_r_2, NULL);
     TEST_ASSERT(rc == 0);
 
@@ -1189,37 +1193,37 @@ TEST_CASE(ble_att_svr_test_read_mult)
                                             100, BLE_ATT_ERR_INVALID_HANDLE);
 
     /*** Single attribute. */
-    ble_att_svr_test_misc_verify_all_read_mult(conn_handle, &attr1, 1);
+    ble_att_svr_test_misc_verify_all_read_mult(conn_handle, &attrs[0], 1);
 
     /*** Two attributes. */
-    ble_att_svr_test_misc_verify_all_read_mult(
-        conn_handle, ((struct ble_gatt_attr[]) { attr1, attr2 }), 2);
+    ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2);
 
     /*** Reverse order. */
-    ble_att_svr_test_misc_verify_all_read_mult(
-        conn_handle, ((struct ble_gatt_attr[]) { attr2, attr1 }), 2);
+    ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2);
 
     /*** Second attribute nonexistent; verify only error txed. */
     ble_att_svr_test_misc_rx_read_mult_req(
-        conn_handle, ((uint16_t[]){ attr1.handle, 100 }), 2, 0);
+        conn_handle, ((uint16_t[]){ attrs[0].handle, 100 }), 2, 0);
     ble_att_svr_test_misc_verify_tx_err_rsp(BLE_ATT_OP_READ_MULT_REQ,
                                             100, BLE_ATT_ERR_INVALID_HANDLE);
 
     /*** Response too long; verify only MTU bytes sent. */
-    attr1.value =
-        (uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
-    attr1.value_len = 20;
-    ble_att_svr_test_attr_r_1 = (void *)attr1.value;
-    ble_att_svr_test_attr_r_1_len = attr1.value_len;
-
-    attr2.value =
-        (uint8_t[]){22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};
-    attr2.value_len = 20;
-    ble_att_svr_test_attr_r_2 = (void *)attr2.value;
-    ble_att_svr_test_attr_r_2_len = attr2.value_len;
-
-    ble_att_svr_test_misc_verify_all_read_mult(
-        conn_handle, ((struct ble_gatt_attr[]) { attr1, attr2 }), 2);
+    attrs[0].value_len = 20;
+    memcpy(attrs[0].value,
+           ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}),
+           attrs[0].value_len);
+    ble_att_svr_test_attr_r_1_len = attrs[0].value_len;
+
+    attrs[1].value_len = 20;
+    memcpy(attrs[1].value,
+           ((uint8_t[]){
+                22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39
+           }),
+           attrs[1].value_len);
+    ble_att_svr_test_attr_r_2_len = attrs[1].value_len;
+
+    ble_att_svr_test_misc_verify_all_read_mult(conn_handle, attrs, 2);
+
 }
 
 TEST_CASE(ble_att_svr_test_write)
@@ -1264,7 +1268,7 @@ TEST_CASE(ble_att_svr_test_write)
                                             BLE_ATT_ERR_WRITE_NOT_PERMITTED);
 
     /* Local write (success). */
-    rc = ble_att_svr_write_local(req.bawq_handle, buf, sizeof buf);
+    rc = ble_hs_test_util_write_local_flat(req.bawq_handle, buf, sizeof buf);
     TEST_ASSERT(rc == 0);
 
     /* Ensure no response got sent. */
@@ -1304,7 +1308,7 @@ TEST_CASE(ble_att_svr_test_write)
                                             BLE_ATT_ERR_INSUFFICIENT_AUTHEN);
 
     /* Security check bypassed for local writes. */
-    rc = ble_att_svr_write_local(req.bawq_handle, buf, sizeof buf);
+    rc = ble_hs_test_util_write_local_flat(req.bawq_handle, buf, sizeof buf);
     TEST_ASSERT(rc == 0);
 
     /* Ensure no response got sent. */
@@ -1474,6 +1478,7 @@ TEST_CASE(ble_att_svr_test_find_info)
         }, {
             .handle = 0,
         } }));
+
 }
 
 TEST_CASE(ble_att_svr_test_find_type_value)
@@ -1674,6 +1679,7 @@ TEST_CASE(ble_att_svr_test_find_type_value)
         }, {
             .first = 0,
         } }));
+
 }
 
 static void
@@ -1880,6 +1886,7 @@ ble_att_svr_test_misc_read_type(uint16_t mtu)
         }, {
             .handle = 0,
         } }));
+
 }
 
 TEST_CASE(ble_att_svr_test_read_type)
@@ -2059,6 +2066,7 @@ TEST_CASE(ble_att_svr_test_read_group_type)
         }, {
             .start_handle = 0,
         } }));
+
 }
 
 TEST_CASE(ble_att_svr_test_prep_write)
@@ -2068,7 +2076,7 @@ TEST_CASE(ble_att_svr_test_prep_write)
 
     static uint8_t data[1024];
 
-    conn_handle = ble_att_svr_test_misc_init(200);
+    conn_handle = ble_att_svr_test_misc_init(205);
 
     /* Initialize some attribute data. */
     for (i = 0; i < sizeof data; i++) {
@@ -2190,6 +2198,7 @@ TEST_CASE(ble_att_svr_test_notify)
     /* Attribute handle of 0. */
     ble_att_svr_test_misc_verify_notify(conn_handle, 0,
                                         (uint8_t[]) { 1, 2, 3 }, 3, 0);
+
 }
 
 TEST_CASE(ble_att_svr_test_indicate)
@@ -2212,10 +2221,13 @@ TEST_CASE(ble_att_svr_test_indicate)
     /* Attribute handle of 0. */
     ble_att_svr_test_misc_verify_indicate(conn_handle, 0,
                                           (uint8_t[]) { 1, 2, 3 }, 3, 0);
+
 }
 
 TEST_SUITE(ble_att_svr_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_att_svr_test_mtu();
     ble_att_svr_test_read();
     ble_att_svr_test_read_blob();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gap_test.c b/net/nimble/host/src/test/ble_gap_test.c
index 7834d8a..86d0e6f 100644
--- a/net/nimble/host/src/test/ble_gap_test.c
+++ b/net/nimble/host/src/test/ble_gap_test.c
@@ -549,6 +549,8 @@ TEST_CASE(ble_gap_test_case_wl_good)
 
 TEST_SUITE(ble_gap_test_suite_wl)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_wl_good();
     ble_gap_test_case_wl_bad_args();
     ble_gap_test_case_wl_ctlr_fail();
@@ -688,6 +690,7 @@ TEST_CASE(ble_gap_test_case_disc_good)
         TEST_ASSERT(ble_gap_test_disc_desc.rssi == 0);
         TEST_ASSERT(memcmp(ble_gap_test_disc_desc.addr, desc.addr, 6) == 0);
         TEST_ASSERT(ble_gap_test_disc_arg == NULL);
+
     }
 }
 
@@ -738,6 +741,7 @@ TEST_CASE(ble_gap_test_case_disc_ltd_mismatch)
      * hears everything.
      */
     TEST_ASSERT(ble_gap_test_disc_event_type == BLE_GAP_EVENT_DISC);
+
 }
 
 TEST_CASE(ble_gap_test_case_disc_hci_fail)
@@ -817,6 +821,8 @@ TEST_CASE(ble_gap_test_case_disc_dflts)
 
 TEST_SUITE(ble_gap_test_suite_disc)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_disc_bad_args();
     ble_gap_test_case_disc_good();
     ble_gap_test_case_disc_ltd_mismatch();
@@ -940,6 +946,8 @@ TEST_CASE(ble_gap_test_case_conn_dir_dflt_params)
 
 TEST_SUITE(ble_gap_test_suite_conn_dir)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_conn_dir_good();
     ble_gap_test_case_conn_dir_bad_args();
     ble_gap_test_case_conn_dir_dflt_params();
@@ -1054,6 +1062,8 @@ TEST_CASE(ble_gap_test_case_conn_cancel_ctlr_fail)
 
 TEST_SUITE(ble_gap_test_suite_conn_cancel)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_conn_cancel_good();
     ble_gap_test_case_conn_cancel_bad_args();
     ble_gap_test_case_conn_cancel_ctlr_fail();
@@ -1180,6 +1190,8 @@ TEST_CASE(ble_gap_test_case_conn_terminate_hci_fail)
 
 TEST_SUITE(ble_gap_test_suite_conn_terminate)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_conn_terminate_bad_args();
     ble_gap_test_case_conn_terminate_good();
     ble_gap_test_case_conn_terminate_ctlr_fail();
@@ -1289,6 +1301,8 @@ TEST_CASE(ble_gap_test_case_conn_find)
 
 TEST_SUITE(ble_gap_test_suite_conn_find)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_conn_find();
 }
 
@@ -1607,6 +1621,8 @@ TEST_CASE(ble_gap_test_case_adv_hci_fail)
 
 TEST_SUITE(ble_gap_test_suite_adv)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_adv_bad_args();
     ble_gap_test_case_adv_dflt_params();
     ble_gap_test_case_adv_good();
@@ -1684,6 +1700,8 @@ TEST_CASE(ble_gap_test_case_stop_adv_hci_fail)
 
 TEST_SUITE(ble_gap_test_suite_stop_adv)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_stop_adv_good();
     ble_gap_test_case_stop_adv_hci_fail();
 }
@@ -2248,6 +2266,8 @@ TEST_CASE(ble_gap_test_case_update_concurrent_hci_fail)
 
 TEST_SUITE(ble_gap_test_suite_update_conn)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gap_test_case_update_conn_good();
     ble_gap_test_case_update_conn_bad();
     ble_gap_test_case_update_conn_hci_fail();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_conn_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_conn_test.c b/net/nimble/host/src/test/ble_gatt_conn_test.c
index 4c30425..be4a46d 100644
--- a/net/nimble/host/src/test/ble_gatt_conn_test.c
+++ b/net/nimble/host/src/test/ble_gatt_conn_test.c
@@ -36,16 +36,16 @@ struct ble_gatt_conn_test_cb_arg {
 
 static int
 ble_gatt_conn_test_attr_cb(uint16_t conn_handle, uint16_t attr_handle,
-                           uint8_t *uuid128, uint8_t op,
-                           struct ble_att_svr_access_ctxt *ctxt,
+                           uint8_t op, uint16_t offset, struct os_mbuf **om,
                            void *arg)
 {
-    static uint8_t data = 1;
+    uint8_t *buf;
 
     switch (op) {
     case BLE_ATT_ACCESS_OP_READ:
-        ctxt->read.data = &data;
-        ctxt->read.len = 1;
+        buf = os_mbuf_extend(*om, 1);
+        TEST_ASSERT_FATAL(buf != NULL);
+        *buf = 1;
         return 0;
 
     default:
@@ -201,7 +201,7 @@ ble_gatt_conn_test_disc_all_dscs_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_read_cb(uint16_t conn_handle,
                            const struct ble_gatt_error *error,
-                           const struct ble_gatt_attr *attr, void *arg)
+                           struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
 
@@ -221,7 +221,7 @@ ble_gatt_conn_test_read_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle,
                                 const struct ble_gatt_error *error,
-                                const struct ble_gatt_attr *attr, void *arg)
+                                struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
 
@@ -241,7 +241,7 @@ ble_gatt_conn_test_read_uuid_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_read_long_cb(uint16_t conn_handle,
                                 const struct ble_gatt_error *error,
-                                const struct ble_gatt_attr *attr, void *arg)
+                                struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
 
@@ -260,7 +260,7 @@ ble_gatt_conn_test_read_long_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle,
                                 const struct ble_gatt_error *error,
-                                const struct ble_gatt_attr *attr, void *arg)
+                                struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
 
@@ -270,7 +270,7 @@ ble_gatt_conn_test_read_mult_cb(uint16_t 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->om == NULL);
 
     cb_arg->called++;
 
@@ -280,7 +280,7 @@ ble_gatt_conn_test_read_mult_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_write_cb(uint16_t conn_handle,
                             const struct ble_gatt_error *error,
-                            const struct ble_gatt_attr *attr,
+                            struct ble_gatt_attr *attr,
                             void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
@@ -302,7 +302,7 @@ ble_gatt_conn_test_write_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_write_long_cb(uint16_t conn_handle,
                                  const struct ble_gatt_error *error,
-                                 const struct ble_gatt_attr *attr, void *arg)
+                                 struct ble_gatt_attr *attr, void *arg)
 {
     struct ble_gatt_conn_test_cb_arg *cb_arg;
 
@@ -323,7 +323,7 @@ ble_gatt_conn_test_write_long_cb(uint16_t conn_handle,
 static int
 ble_gatt_conn_test_write_rel_cb(uint16_t conn_handle,
                                 const struct ble_gatt_error *error,
-                                const struct ble_gatt_attr *attrs,
+                                struct ble_gatt_attr *attrs,
                                 uint8_t num_attrs,
                                 void *arg)
 {
@@ -358,6 +358,7 @@ TEST_CASE(ble_gatt_conn_test_disconnect)
     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;
 
@@ -439,25 +440,25 @@ TEST_CASE(ble_gatt_conn_test_disconnect)
     TEST_ASSERT_FATAL(rc == 0);
 
     write_arg.exp_conn_handle = 3;
-    rc = ble_gattc_write(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);
+    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_gattc_write_long(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);
+    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,
-                                  ((struct ble_gatt_attr[]){{8, 0, 0, NULL}}),
-                                  1, ble_gatt_conn_test_write_rel_cb,
-                                  &write_rel_arg);
+    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. */
@@ -518,6 +519,8 @@ TEST_CASE(ble_gatt_conn_test_disconnect)
 
 TEST_SUITE(ble_gatt_break_suite)
 {
+    tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
+
     ble_gatt_conn_test_disconnect();
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_disc_c_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_disc_c_test.c b/net/nimble/host/src/test/ble_gatt_disc_c_test.c
index 7db9350..a4eb67b 100644
--- a/net/nimble/host/src/test/ble_gatt_disc_c_test.c
+++ b/net/nimble/host/src/test/ble_gatt_disc_c_test.c
@@ -532,6 +532,8 @@ TEST_CASE(ble_gatt_disc_c_test_disc_uuid)
 
 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();
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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
index 048ecb7..7e021e2 100644
--- a/net/nimble/host/src/test/ble_gatt_disc_d_test.c
+++ b/net/nimble/host/src/test/ble_gatt_disc_d_test.c
@@ -349,6 +349,8 @@ TEST_CASE(ble_gatt_disc_d_test_1)
 
 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();
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_disc_s_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_disc_s_test.c b/net/nimble/host/src/test/ble_gatt_disc_s_test.c
index 1275e38..2e278d6 100644
--- a/net/nimble/host/src/test/ble_gatt_disc_s_test.c
+++ b/net/nimble/host/src/test/ble_gatt_disc_s_test.c
@@ -391,6 +391,8 @@ TEST_CASE(ble_gatt_disc_s_test_disc_service_uuid)
 
 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();
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/test/ble_gatt_find_s_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatt_find_s_test.c b/net/nimble/host/src/test/ble_gatt_find_s_test.c
index cf988d6..c3ab93d 100644
--- a/net/nimble/host/src/test/ble_gatt_find_s_test.c
+++ b/net/nimble/host/src/test/ble_gatt_find_s_test.c
@@ -328,6 +328,8 @@ TEST_CASE(ble_gatt_find_s_test_1)
 
 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();
 }
 


[08/11] incubator-mynewt-core git commit: BLE Host - Use mbufs instead of flat bufs.

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_att_svr.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_svr.c b/net/nimble/host/src/ble_att_svr.c
index 18a2523..a1ec715 100644
--- a/net/nimble/host/src/ble_att_svr.c
+++ b/net/nimble/host/src/ble_att_svr.c
@@ -202,7 +202,7 @@ ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len,
     uint8_t att_err;
     int rc;
 
-    rc = ble_hs_misc_pullup_base(om, base_len);
+    rc = ble_hs_mbuf_pullup_base(om, base_len);
     if (rc == BLE_HS_ENOMEM) {
         att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
     } else {
@@ -287,27 +287,11 @@ ble_att_svr_check_security(uint16_t conn_handle, int is_read,
     return 0;
 }
 
-static uint16_t
-ble_att_max_read_len(uint16_t conn_handle)
-{
-    uint16_t mtu;
-
-    if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
-        /* The application is reading from itself; no MTU. */
-        mtu = BLE_ATT_MTU_MAX;
-    } else {
-        mtu = ble_att_mtu(conn_handle);
-    }
-
-    /* Subtract one to account for the att-read-response header. */
-    BLE_HS_DBG_ASSERT(mtu > 0);
-    return mtu - 1;
-}
-
 static int
 ble_att_svr_read(uint16_t conn_handle,
                  struct ble_att_svr_entry *entry,
-                 struct ble_att_svr_access_ctxt *ctxt,
+                 uint16_t offset,
+                 struct os_mbuf *om,
                  uint8_t *out_att_err)
 {
     uint8_t att_err;
@@ -328,17 +312,9 @@ ble_att_svr_read(uint16_t conn_handle,
         }
     }
 
-    /* Give the application access to the ATT flat buffer in case it needs
-     * to generate the read response dynamically.
-     */
-    ctxt->read.buf = ble_att_get_flat_buf();
-    ctxt->read.data = ctxt->read.buf;
-    ctxt->read.max_data_len = ble_att_max_read_len(conn_handle);
-
     BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
     rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
-                      entry->ha_uuid, BLE_ATT_ACCESS_OP_READ, ctxt,
-                      entry->ha_cb_arg);
+                      BLE_ATT_ACCESS_OP_READ, offset, &om, entry->ha_cb_arg);
     if (rc != 0) {
         att_err = rc;
         rc = BLE_HS_EAPP;
@@ -354,9 +330,51 @@ err:
     return rc;
 }
 
+static int
+ble_att_svr_read_flat(uint16_t conn_handle, 
+                      struct ble_att_svr_entry *entry,
+                      uint16_t offset,
+                      uint16_t max_len,
+                      void *dst,
+                      uint16_t *out_len,
+                      uint8_t *out_att_err)
+{
+    struct os_mbuf *om;
+    uint16_t len;
+    int rc;
+
+    om = ble_hs_mbuf_l2cap_pkt();
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
+    if (rc != 0) {
+        goto done;
+    }
+
+    len = OS_MBUF_PKTLEN(om);
+    if (len > max_len) {
+        rc = BLE_HS_EMSGSIZE;
+        *out_att_err = BLE_ATT_ERR_UNLIKELY;
+        goto done;
+    }
+
+    rc = os_mbuf_copydata(om, 0, len, dst);
+    BLE_HS_DBG_ASSERT(rc == 0);
+
+    *out_len = len;
+    rc = 0;
+
+done:
+    os_mbuf_free_chain(om);
+    return rc;
+}
+
 int
 ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
-                        struct ble_att_svr_access_ctxt *ctxt,
+                        uint16_t offset, struct os_mbuf *om,
                         uint8_t *out_att_err)
 {
     struct ble_att_svr_entry *entry;
@@ -370,7 +388,7 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
         return BLE_HS_ENOENT;
     }
 
-    rc = ble_att_svr_read(conn_handle, entry, ctxt, out_att_err);
+    rc = ble_att_svr_read(conn_handle, entry, offset, om, out_att_err);
     if (rc != 0) {
         return rc;
     }
@@ -384,41 +402,45 @@ ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
  * performed by calling the registered GATT access callback.
  *
  * @param attr_handle           The 16-bit handle of the attribute to read.
- * @param out_data              On success, this points to the attribute data
- *                                  just read.
- * @param out_attr_len          On success, this points to the number of bytes
- *                                  of attribute data just read.
+ * @param out_om                On success, this is made to point to a
+ *                                  newly-allocated mbuf containing the
+ *                                  attribute data read.
  *
- * @return                      0 on success
+ * @return                      0 on success;
  *                              NimBLE host ATT return code if the attribute
  *                                  access callback reports failure;
  *                              NimBLE host core return code on unexpected
  *                                  error.
  */
 int
-ble_att_svr_read_local(uint16_t attr_handle, const void **out_data,
-                       uint16_t *out_attr_len)
+ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om)
 {
-    struct ble_att_svr_access_ctxt ctxt;
+    struct os_mbuf *om;
     int rc;
 
-    ctxt.read.offset = 0;
+    om = ble_hs_mbuf_bare_pkt();
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto err;
+    }
 
-    rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt,
+    rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0, om,
                                  NULL);
     if (rc != 0) {
-        return rc;
+        goto err;
     }
 
-    *out_attr_len = ctxt.read.len;
-    *out_data = ctxt.read.data;
-
+    *out_om = om;
     return 0;
+
+err:
+    os_mbuf_free_chain(om);
+    return rc;
 }
 
 static int
 ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry,
-                  struct ble_att_svr_access_ctxt *ctxt, uint8_t *out_att_err)
+                  uint16_t offset, struct os_mbuf **om, uint8_t *out_att_err)
 {
     uint8_t att_err;
     int rc;
@@ -429,28 +451,25 @@ ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry,
         if (!(entry->ha_flags & BLE_ATT_F_WRITE)) {
             att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED;
             rc = BLE_HS_ENOTSUP;
-            goto err;
+            goto done;
         }
 
         rc = ble_att_svr_check_security(conn_handle, 0, entry, &att_err);
         if (rc != 0) {
-            goto err;
+            goto done;
         }
     }
 
     BLE_HS_DBG_ASSERT(entry->ha_cb != NULL);
     rc = entry->ha_cb(conn_handle, entry->ha_handle_id,
-                      entry->ha_uuid, BLE_ATT_ACCESS_OP_WRITE, ctxt,
-                      entry->ha_cb_arg);
+                      BLE_ATT_ACCESS_OP_WRITE, offset, om, entry->ha_cb_arg);
     if (rc != 0) {
         att_err = rc;
         rc = BLE_HS_EAPP;
-        goto err;
+        goto done;
     }
 
-    return 0;
-
-err:
+done:
     if (out_att_err != NULL) {
         *out_att_err = att_err;
     }
@@ -459,7 +478,7 @@ err:
 
 static int
 ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
-                         struct ble_att_svr_access_ctxt *ctxt,
+                         uint16_t offset, struct os_mbuf **om,
                          uint8_t *out_att_err)
 {
     struct ble_att_svr_entry *entry;
@@ -471,7 +490,7 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
         return BLE_HS_ENOENT;
     }
 
-    rc = ble_att_svr_write(conn_handle, entry, ctxt, out_att_err);
+    rc = ble_att_svr_write(conn_handle, entry, offset, om, out_att_err);
     if (rc != 0) {
         return rc;
     }
@@ -481,25 +500,19 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle,
 
 static int
 ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
-                         uint8_t req_op, uint16_t handle, uint8_t error_code)
+                         struct os_mbuf **om, uint8_t req_op,
+                         uint16_t handle, uint8_t error_code)
 {
     struct ble_att_error_rsp rsp;
-    struct os_mbuf *txom;
     void *dst;
     int rc;
 
     BLE_HS_DBG_ASSERT(error_code != 0);
+    BLE_HS_DBG_ASSERT(OS_MBUF_PKTLEN(*om) == 0);
 
-    txom = ble_hs_misc_pkthdr();
-    if (txom == NULL) {
-        rc = BLE_HS_ENOMEM;
-        goto err;
-    }
-
-    dst = os_mbuf_extend(txom, BLE_ATT_ERROR_RSP_SZ);
+    dst = os_mbuf_extend(*om, BLE_ATT_ERROR_RSP_SZ);
     if (dst == NULL) {
-        rc = BLE_HS_ENOMEM;
-        goto err;
+        return BLE_HS_ENOMEM;
     }
 
     rsp.baep_req_op = req_op;
@@ -510,17 +523,12 @@ ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     BLE_ATT_LOG_CMD(1, "error rsp", conn->bhc_handle,
                     ble_att_error_rsp_log, &rsp);
 
-    rc = ble_l2cap_tx(conn, chan, txom);
-    txom = NULL;
+    rc = ble_l2cap_tx(conn, chan, om);
     if (rc != 0) {
-        goto err;
+        return rc;
     }
 
     return 0;
-
-err:
-    os_mbuf_free_chain(txom);
-    return rc;
 }
 
 /**
@@ -547,13 +555,15 @@ err:
  *                                  field.
  */
 static int
-ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
+ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf **om,
                    uint8_t att_op, uint8_t err_status, uint16_t err_handle)
 {
     struct ble_l2cap_chan *chan;
     struct ble_hs_conn *conn;
     int do_tx;
 
+    BLE_HS_DBG_ASSERT(om != NULL);
+
     if (rc == BLE_HS_ENOTCONN) {
         /* No connection; tx is not possible. */
         do_tx = 0;
@@ -572,10 +582,11 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
             rc = BLE_HS_ENOTCONN;
         } else {
             if (rc == 0) {
-                BLE_HS_DBG_ASSERT(txom != NULL);
-                ble_att_inc_tx_stat(txom->om_data[0]);
-                rc = ble_l2cap_tx(conn, chan, txom);
-                txom = NULL;
+                BLE_HS_DBG_ASSERT(*om != NULL);
+
+                ble_att_inc_tx_stat((*om)->om_data[0]);
+                ble_att_truncate_to_mtu(chan, *om);
+                rc = ble_l2cap_tx(conn, chan, om);
                 if (rc != 0) {
                     err_status = BLE_ATT_ERR_UNLIKELY;
                 }
@@ -583,16 +594,24 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int rc, struct os_mbuf *txom,
 
             if (rc != 0) {
                 STATS_INC(ble_att_stats, error_rsp_tx);
-                ble_att_svr_tx_error_rsp(conn, chan, att_op,
-                                         err_handle, err_status);
+
+                /* Reuse om for error response. */
+                if (*om == NULL) {
+                    *om = ble_hs_mbuf_l2cap_pkt();
+                } else {
+                    /* Remove response from mbuf. */
+                    os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om));
+                }
+                if (om != NULL) {
+                    ble_att_svr_tx_error_rsp(conn, chan, om, att_op,
+                                             err_handle, err_status);
+                }
             }
         }
 
         ble_hs_unlock();
     }
 
-    os_mbuf_free_chain(txom);
-
     return rc;
 }
 
@@ -621,7 +640,7 @@ ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **out_txom,
         goto done;
     }
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -648,7 +667,7 @@ done:
 }
 
 int
-ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
+ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom)
 {
     struct ble_att_mtu_cmd cmd;
     struct ble_l2cap_chan *chan;
@@ -659,12 +678,12 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
 
     txom = NULL;
 
-    rc = ble_att_svr_pullup_req_base(om, BLE_ATT_MTU_CMD_SZ, &att_err);
+    rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_MTU_CMD_SZ, &att_err);
     if (rc != 0) {
         goto done;
     }
 
-    ble_att_mtu_cmd_parse((*om)->om_data, (*om)->om_len, &cmd);
+    ble_att_mtu_cmd_parse((*rxom)->om_data, (*rxom)->om_len, &cmd);
     BLE_ATT_LOG_CMD(0, "mtu req", conn_handle, ble_att_mtu_cmd_log, &cmd);
 
     rc = ble_att_svr_build_mtu_rsp(conn_handle, &txom, &att_err);
@@ -675,8 +694,10 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_MTU_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_MTU_REQ,
                             att_err, 0);
+    os_mbuf_free_chain(txom);
+
     if (rc == 0) {
         ble_hs_lock();
         ble_att_conn_chan_find(conn_handle, &conn, &chan);
@@ -806,7 +827,7 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle,
         goto done;
     }
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -893,8 +914,9 @@ ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_FIND_INFO_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_FIND_INFO_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1033,8 +1055,9 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
                             struct os_mbuf *rxom, struct os_mbuf *txom,
                             uint16_t mtu, uint8_t *out_att_err)
 {
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_svr_entry *ha;
+    uint8_t buf[16];
+    uint16_t attr_len;
     uint16_t uuid16;
     uint16_t first;
     uint16_t prev;
@@ -1063,13 +1086,13 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
              */
             uuid16 = ble_uuid_128_to_16(ha->ha_uuid);
             if (uuid16 == req->bavq_attr_type) {
-                ctxt.read.offset = 0;
-                rc = ble_att_svr_read(conn_handle, ha, &ctxt, out_att_err);
+                rc = ble_att_svr_read_flat(conn_handle, ha, 0, sizeof buf, buf,
+                                           &attr_len, out_att_err);
                 if (rc != 0) {
                     goto done;
                 }
-                rc = os_mbuf_memcmp(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ,
-                                    ctxt.read.data, ctxt.read.len);
+                rc = os_mbuf_cmpf(rxom, BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ,
+                                  buf, attr_len);
                 if (rc == 0) {
                     match = 1;
                 }
@@ -1122,7 +1145,7 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle,
     uint8_t *buf;
     int rc;
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *out_att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -1211,9 +1234,10 @@ ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom,
                             BLE_ATT_OP_FIND_TYPE_VALUE_REQ, att_err,
                             err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1225,16 +1249,16 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
                                 uint8_t *att_err,
                                 uint16_t *err_handle)
 {
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_read_type_rsp rsp;
     struct ble_att_svr_entry *entry;
     struct os_mbuf *txom;
+    uint16_t attr_len;
     uint16_t mtu;
+    uint8_t buf[19];
     uint8_t *dptr;
     int entry_written;
     int txomlen;
     int prev_attr_len;
-    int attr_len;
     int rc;
 
     *att_err = 0;    /* Silence unnecessary warning. */
@@ -1248,7 +1272,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
         return BLE_HS_ENOTCONN;
     }
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         *err_handle = 0;
@@ -1277,17 +1301,15 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
         }
 
         if (entry->ha_handle_id >= req->batq_start_handle) {
-            ctxt.read.offset = 0;
-            rc = ble_att_svr_read(conn_handle, entry, &ctxt, att_err);
+            rc = ble_att_svr_read_flat(conn_handle, entry, 0, sizeof buf, buf,
+                                       &attr_len, att_err);
             if (rc != 0) {
                 *err_handle = entry->ha_handle_id;
                 goto done;
             }
 
-            if (ctxt.read.len > mtu - 4) {
+            if (attr_len > mtu - 4) {
                 attr_len = mtu - 4;
-            } else {
-                attr_len = ctxt.read.len;
             }
 
             if (prev_attr_len == 0) {
@@ -1310,7 +1332,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
             }
 
             htole16(dptr + 0, entry->ha_handle_id);
-            memcpy(dptr + 2, ctxt.read.data, attr_len);
+            memcpy(dptr + 2, buf, attr_len);
             entry_written = 1;
         }
     }
@@ -1341,6 +1363,7 @@ done:
     return rc;
 }
 
+int yourmom;
 int
 ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
 {
@@ -1378,6 +1401,11 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
     BLE_ATT_LOG_CMD(0, "read type req", conn_handle, ble_att_read_type_req_log,
                     &req);
 
+
+    if (req.batq_start_handle == 29) {
+        yourmom++;
+    }
+
     if (req.batq_start_handle > req.batq_end_handle ||
         req.batq_start_handle == 0) {
 
@@ -1419,67 +1447,9 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_TYPE_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_TYPE_REQ,
                             att_err, err_handle);
-    return rc;
-}
-
-/**
- * @return                      0 on success; nonzero on failure.
- */
-static int
-ble_att_svr_build_read_rsp(uint16_t conn_handle, const void *attr_data,
-                           int attr_len, struct os_mbuf **out_txom,
-                           uint8_t *att_err)
-{
-    struct os_mbuf *txom;
-    uint16_t data_len;
-    uint16_t mtu;
-    uint8_t op;
-    int rc;
-
-    txom = NULL;
-
-    mtu = ble_att_mtu(conn_handle);
-    if (mtu == 0) {
-        rc = BLE_HS_ENOTCONN;
-        goto done;
-    }
-
-    txom = ble_hs_misc_pkthdr();
-    if (txom == NULL) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
-        rc = BLE_HS_ENOMEM;
-        goto done;
-    }
-
-    op = BLE_ATT_OP_READ_RSP;
-    rc = os_mbuf_append(txom, &op, 1);
-    if (rc != 0) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
-        rc = BLE_HS_ENOMEM;
-        goto done;
-    }
-
-    /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */
-    if (attr_len > mtu - 1) {
-        data_len = mtu - 1;
-    } else {
-        data_len = attr_len;
-    }
-
-    rc = os_mbuf_append(txom, attr_data, data_len);
-    if (rc != 0) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
-        rc = BLE_HS_ENOMEM;
-        goto done;
-    }
-
-    BLE_ATT_LOG_EMPTY_CMD(1, "read rsp", conn_handle);
-    rc = 0;
-
-done:
-    *out_txom = txom;
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1490,11 +1460,11 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_read_req req;
     struct os_mbuf *txom;
     uint16_t err_handle;
     uint8_t att_err;
+    uint8_t *dptr;
     int rc;
 
     /* Initialize some values in case of early error. */
@@ -1511,75 +1481,32 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
     ble_att_read_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
     BLE_ATT_LOG_CMD(0, "read req", conn_handle, ble_att_read_req_log, &req);
 
-    ctxt.read.offset = 0;
-    rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, &ctxt,
-                                 &att_err);
-    if (rc != 0) {
-        err_handle = req.barq_handle;
-        goto done;
-    }
-
-    rc = ble_att_svr_build_read_rsp(conn_handle, ctxt.read.data, ctxt.read.len,
-                                    &txom, &att_err);
-    if (rc != 0) {
-        err_handle = req.barq_handle;
-        goto done;
-    }
-
-    rc = 0;
-
-done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ,
-                            att_err, err_handle);
-    return rc;
-}
-
-/**
- * @return                      0 on success; nonzero on failure.
- */
-static int
-ble_att_svr_build_read_blob_rsp(const void *attr_data, int attr_len,
-                                uint16_t mtu, struct os_mbuf **out_txom,
-                                uint8_t *att_err)
-{
-    struct os_mbuf *txom;
-    uint16_t data_len;
-    uint8_t op;
-    int rc;
-
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
         goto done;
     }
 
-    op = BLE_ATT_OP_READ_BLOB_RSP;
-    rc = os_mbuf_append(txom, &op, 1);
-    if (rc != 0) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+    dptr = os_mbuf_extend(txom, 1);
+    if (dptr == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
         goto done;
     }
+    *dptr = BLE_ATT_OP_READ_RSP;
 
-    /* Vol. 3, part F, 3.2.9; don't send more than ATT_MTU-1 bytes of data. */
-    if (attr_len > mtu - 1) {
-        data_len = mtu - 1;
-    } else {
-        data_len = attr_len;
-    }
-
-    rc = os_mbuf_append(txom, attr_data, data_len);
+    rc = ble_att_svr_read_handle(conn_handle, req.barq_handle, 0, txom,
+                                 &att_err);
     if (rc != 0) {
-        *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
-        rc = BLE_HS_ENOMEM;
+        err_handle = req.barq_handle;
         goto done;
     }
 
-    rc = 0;
-
 done:
-    *out_txom = txom;
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_REQ,
+                            att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1590,11 +1517,11 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_read_blob_req req;
     struct os_mbuf *txom;
     uint16_t err_handle;
     uint16_t mtu;
+    uint8_t *dptr;
     uint8_t att_err;
     int rc;
 
@@ -1619,34 +1546,36 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
     BLE_ATT_LOG_CMD(0, "read blob req", conn_handle, ble_att_read_blob_req_log,
                     &req);
 
-    ctxt.read.offset = req.babq_offset;
-    rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, &ctxt,
-                                 &att_err);
-    if (rc != 0) {
-        err_handle = req.babq_handle;
+    txom = ble_hs_mbuf_l2cap_pkt();
+    if (txom == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        rc = BLE_HS_ENOMEM;
         goto done;
     }
 
-    if (ctxt.read.offset + ctxt.read.len <= mtu - 3) {
-        att_err = BLE_ATT_ERR_ATTR_NOT_LONG;
-        err_handle = req.babq_handle;
-        rc = BLE_HS_ENOTSUP;
+    dptr = os_mbuf_extend(txom, 1);
+    if (dptr == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        rc = BLE_HS_ENOMEM;
         goto done;
     }
+    *dptr = BLE_ATT_OP_READ_BLOB_RSP;
 
-    rc = ble_att_svr_build_read_blob_rsp(ctxt.read.data, ctxt.read.len, mtu,
-                                         &txom, &att_err);
+    rc = ble_att_svr_read_handle(conn_handle, req.babq_handle, req.babq_offset,
+                                 txom, &att_err);
     if (rc != 0) {
         err_handle = req.babq_handle;
         goto done;
     }
+
     BLE_ATT_LOG_EMPTY_CMD(1, "read blob rsp", conn_handle);
 
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_BLOB_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_BLOB_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1657,10 +1586,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
                                 uint8_t *att_err,
                                 uint16_t *err_handle)
 {
-    struct ble_att_svr_access_ctxt ctxt;
     struct os_mbuf *txom;
-    uint16_t chunk_sz;
-    uint16_t tx_space;
     uint16_t handle;
     uint16_t mtu;
     uint8_t *dptr;
@@ -1674,7 +1600,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
         goto done;
     }
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         *err_handle = 0;
@@ -1691,13 +1617,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
     }
     ble_att_read_mult_rsp_write(dptr, BLE_ATT_READ_MULT_RSP_BASE_SZ);
 
-    tx_space = mtu - OS_MBUF_PKTLEN(txom);
-
     /* Iterate through requested handles, reading the corresponding attribute
      * for each.  Stop when there are no more handles to process, or the
      * response is full.
      */
-    while (OS_MBUF_PKTLEN(*rxom) >= 2 && tx_space > 0) {
+    while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) {
         /* Ensure the full 16-bit handle is contiguous at the start of the
          * mbuf.
          */
@@ -1713,28 +1637,11 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle,
         handle = le16toh((*rxom)->om_data);
         os_mbuf_adj(*rxom, 2);
 
-        ctxt.read.offset = 0;
-        rc = ble_att_svr_read_handle(conn_handle, handle, &ctxt, att_err);
-        if (rc != 0) {
-            *err_handle = handle;
-            goto done;
-        }
-
-        if (ctxt.read.len > tx_space) {
-            chunk_sz = tx_space;
-        } else {
-            chunk_sz = ctxt.read.len;
-        }
-
-        rc = os_mbuf_append(txom, ctxt.read.data, chunk_sz);
+        rc = ble_att_svr_read_handle(conn_handle, handle, 0, txom, att_err);
         if (rc != 0) {
-            *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
             *err_handle = handle;
-            rc = BLE_HS_ENOMEM;
             goto done;
         }
-
-        tx_space -= chunk_sz;
     }
 
     BLE_ATT_LOG_EMPTY_CMD(1, "read mult rsp", conn_handle);
@@ -1785,8 +1692,9 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_READ_MULT_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -1805,23 +1713,22 @@ static int
 ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16,
                          uint8_t *uuid128)
 {
-    struct ble_att_svr_access_ctxt ctxt;
+    uint16_t attr_len;
     int rc;
 
-    ctxt.read.offset = 0;
-    rc = ble_att_svr_read(BLE_HS_CONN_HANDLE_NONE, entry, &ctxt, NULL);
+    rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE, entry, 0, 16, uuid128,
+                               &attr_len, NULL);
     if (rc != 0) {
         return rc;
     }
 
-    switch (ctxt.read.len) {
+    switch (attr_len) {
     case 16:
         *uuid16 = 0;
-        memcpy(uuid128, ctxt.read.data, 16);
         return 0;
 
     case 2:
-        *uuid16 = le16toh(ctxt.read.data);
+        *uuid16 = le16toh(uuid128);
         if (*uuid16 == 0) {
             return BLE_HS_EINVAL;
         }
@@ -1905,7 +1812,7 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle,
         goto done;
     }
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -2123,9 +2030,10 @@ ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom,
                             BLE_ATT_OP_READ_GROUP_TYPE_REQ, att_err,
                             err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -2136,7 +2044,7 @@ ble_att_svr_build_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err)
     uint8_t *dst;
     int rc;
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -2166,10 +2074,8 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_write_req req;
     struct os_mbuf *txom;
-    void *buf;
     uint16_t err_handle;
     uint8_t att_err;
     int rc;
@@ -2193,12 +2099,7 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
     /* Strip the request base from the front of the mbuf. */
     os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ);
 
-    buf = ble_att_get_flat_buf();
-    ctxt.write.len = OS_MBUF_PKTLEN(*rxom);
-    ctxt.write.data = buf;
-    os_mbuf_copydata(*rxom, 0, ctxt.write.len, buf);
-
-    rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, &ctxt,
+    rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom,
                                   &att_err);
     if (rc != 0) {
         err_handle = req.bawq_handle;
@@ -2215,8 +2116,9 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_WRITE_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_WRITE_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -2227,10 +2129,8 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_write_req req;
     uint8_t att_err;
-    void *buf;
     int rc;
 
     rc = ble_att_svr_pullup_req_base(rxom, BLE_ATT_WRITE_REQ_BASE_SZ,
@@ -2246,12 +2146,7 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
     /* Strip the request base from the front of the mbuf. */
     os_mbuf_adj(*rxom, BLE_ATT_WRITE_REQ_BASE_SZ);
 
-    buf = ble_att_get_flat_buf();
-    ctxt.write.len = OS_MBUF_PKTLEN(*rxom);
-    ctxt.write.data = buf;
-    os_mbuf_copydata(*rxom, 0, ctxt.write.len, buf);
-
-    rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, &ctxt,
+    rc = ble_att_svr_write_handle(conn_handle, req.bawq_handle, 0, rxom,
                                   &att_err);
     if (rc != 0) {
         return rc;
@@ -2261,34 +2156,33 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
 }
 
 /**
- * Writes a locally registered attribute.  If the specified attribute handle
+ * Writes a locally registered attribute.  This function consumes the supplied
+ * mbuf regardless of the outcome.  If the specified attribute handle
  * coresponds to a GATT characteristic value or descriptor, the write is
  * performed by calling the registered GATT access callback.
  *
  * @param attr_handle           The 16-bit handle of the attribute to write.
- * @param data                  Buffer containing the data to write to the
- *                                  attribute.
- * @param data_len              The number of bytes to write.
+ * @param om                    The value to write to the attribute.  Double
+ *                                  indirection is used to effect a transfer of
+ *                                  ownership from the caller.
  *
- * @return                      0 on success
+ * @return                      0 on success;
  *                              NimBLE host ATT return code if the attribute
  *                                  access callback reports failure;
  *                              NimBLE host core return code on unexpected
  *                                  error.
  */
 int
-ble_att_svr_write_local(uint16_t attr_handle, const void *data,
-                        uint16_t data_len)
+ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf **om)
 {
-    struct ble_att_svr_access_ctxt ctxt;
     int rc;
 
-    ctxt.write.data = data;
-    ctxt.write.len = data_len;
-    ctxt.write.offset = 0;
+    rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, 0,
+                                  om, NULL);
 
-    rc = ble_att_svr_write_handle(BLE_HS_CONN_HANDLE_NONE, attr_handle, &ctxt,
-                                  NULL);
+    /* Free the mbuf in case it wasn't consumed (i.e., something failed). */
+    os_mbuf_free_chain(*om);
+    *om = NULL;
 
     return rc;
 }
@@ -2311,7 +2205,7 @@ ble_att_svr_prep_alloc(void)
     }
 
     memset(entry, 0, sizeof *entry);
-    entry->bape_value = ble_hs_misc_pkthdr();
+    entry->bape_value = ble_hs_mbuf_l2cap_pkt();
     if (entry->bape_value == NULL) {
         ble_att_svr_prep_free(entry);
         return NULL;
@@ -2395,6 +2289,42 @@ ble_att_svr_prep_validate(struct ble_att_prep_entry_list *prep_list,
     return 0;
 }
 
+static void
+ble_att_svr_prep_extract(struct ble_att_prep_entry_list *prep_list,
+                         uint16_t *out_attr_handle,
+                         struct os_mbuf **out_om)
+{
+    struct ble_att_prep_entry *entry;
+    struct ble_att_prep_entry *first;
+    struct os_mbuf *om;
+    uint16_t attr_handle;
+
+    BLE_HS_DBG_ASSERT(!SLIST_EMPTY(prep_list));
+
+    first = SLIST_FIRST(prep_list);
+    attr_handle = first->bape_handle;
+    om = NULL;
+
+    while ((entry = SLIST_FIRST(prep_list)) != NULL) {
+        if (entry->bape_handle != attr_handle) {
+            break;
+        }
+
+        if (om == NULL) {
+            om = entry->bape_value;
+        } else {
+            os_mbuf_concat(om, entry->bape_value);
+        }
+        entry->bape_value = NULL;
+
+        SLIST_REMOVE_HEAD(prep_list, bape_next);
+        ble_att_svr_prep_free(entry);
+    }
+
+    *out_attr_handle = attr_handle;
+    *out_om = om;
+}
+
 /**
  * @return                      0 on success; ATT error code on failure.
  */
@@ -2403,13 +2333,10 @@ ble_att_svr_prep_write(uint16_t conn_handle,
                        struct ble_att_prep_entry_list *prep_list,
                        uint16_t *err_handle)
 {
-    struct ble_att_svr_access_ctxt ctxt;
-    struct ble_att_prep_entry *entry;
-    struct ble_att_prep_entry *next;
     struct ble_att_svr_entry *attr;
-    uint8_t *flat_buf;
+    struct os_mbuf *om;
+    uint16_t attr_handle;
     uint8_t att_err;
-    int buf_off;
     int rc;
 
     *err_handle = 0; /* Silence unnecessary warning. */
@@ -2420,40 +2347,19 @@ ble_att_svr_prep_write(uint16_t conn_handle,
         return rc;
     }
 
-    flat_buf = ble_att_get_flat_buf();
-
     /* Contents are valid; perform the writes. */
-    buf_off = 0;
-    entry = SLIST_FIRST(prep_list);
-    while (entry != NULL) {
-        next = SLIST_NEXT(entry, bape_next);
-
-        rc = os_mbuf_copydata(entry->bape_value, 0,
-                              OS_MBUF_PKTLEN(entry->bape_value),
-                              flat_buf + buf_off);
-        BLE_HS_DBG_ASSERT_EVAL(rc == 0);
-        buf_off += OS_MBUF_PKTLEN(entry->bape_value);
-
-        /* If this is the last entry for this attribute, perform the write. */
-        if (next == NULL || entry->bape_handle != next->bape_handle) {
-            attr = ble_att_svr_find_by_handle(entry->bape_handle);
-            if (attr == NULL) {
-                *err_handle = entry->bape_handle;
-                return BLE_ATT_ERR_INVALID_HANDLE;
-            }
+    while (!SLIST_EMPTY(prep_list)) {
+        ble_att_svr_prep_extract(prep_list, &attr_handle, &om);
 
-            ctxt.write.data = flat_buf;
-            ctxt.write.len = buf_off;
-            rc = ble_att_svr_write(conn_handle, attr, &ctxt, &att_err);
-            if (rc != 0) {
-                *err_handle = entry->bape_handle;
-                return att_err;
-            }
-
-            buf_off = 0;
+        attr = ble_att_svr_find_by_handle(attr_handle);
+        if (attr == NULL) {
+            rc = BLE_ATT_ERR_INVALID_HANDLE;
+            *err_handle = attr_handle;
+        } else {
+            rc = ble_att_svr_write(conn_handle, attr, 0, &om, &att_err);
         }
 
-        entry = next;
+        os_mbuf_free_chain(om);
     }
 
     return 0;
@@ -2474,6 +2380,7 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
     struct os_mbuf *srcom;
     struct os_mbuf *txom;
     uint16_t err_handle;
+    uint8_t *buf;
     uint8_t att_err;
     int rc;
 
@@ -2493,6 +2400,7 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
     ble_att_prep_write_req_parse((*rxom)->om_data, (*rxom)->om_len, &req);
     BLE_ATT_LOG_CMD(0, "prep write req", conn_handle,
                     ble_att_prep_write_cmd_log, &req);
+    err_handle = req.bapc_handle;
 
     /* Strip the request base from the front of the mbuf. */
     os_mbuf_adj(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
@@ -2501,14 +2409,12 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
     if (attr_entry == NULL) {
         rc = BLE_HS_ENOENT;
         att_err = BLE_ATT_ERR_INVALID_HANDLE;
-        err_handle = req.bapc_handle;
         goto done;
     }
 
     prep_entry = ble_att_svr_prep_alloc();
     if (prep_entry == NULL) {
         att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
-        err_handle = req.bapc_handle;
         rc = BLE_HS_ENOMEM;
         goto done;
     }
@@ -2540,7 +2446,6 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
                                 srcom->om_len);
             if (rc != 0) {
                 att_err = BLE_ATT_ERR_PREPARE_QUEUE_FULL;
-                err_handle = req.bapc_handle;
                 break;
             }
         }
@@ -2552,20 +2457,28 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
         goto done;
     }
 
-    /* The receive buffer now contains the attribute value.  Repurpose this
-     * buffer for the response.  Prepend a response header.
-     */
-    *rxom = os_mbuf_prepend(*rxom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
-    if (*rxom == NULL) {
+    txom = ble_hs_mbuf_l2cap_pkt();
+    if (txom == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    buf = os_mbuf_extend(txom, BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
+    if (buf == NULL) {
+        att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+    ble_att_prep_write_rsp_write(buf, BLE_ATT_PREP_WRITE_CMD_BASE_SZ, &req);
+
+    rc = os_mbuf_appendfrom(txom, *rxom, 0, OS_MBUF_PKTLEN(*rxom));
+    if (rc != 0) {
         att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
-        err_handle = req.bapc_handle;
         rc = BLE_HS_ENOMEM;
         goto done;
     }
-    txom = *rxom;
 
-    ble_att_prep_write_rsp_write(txom->om_data, BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
-                                 &req);
     BLE_ATT_LOG_CMD(1, "prep write rsp", conn_handle,
                     ble_att_prep_write_cmd_log, &req);
 
@@ -2595,13 +2508,10 @@ done:
         ble_hs_unlock();
     }
 
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_PREP_WRITE_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
 
-    /* Make sure the receive buffer doesn't get freed since we are using it for
-     * the response.
-     */
-    *rxom = NULL;
     return rc;
 }
 
@@ -2615,7 +2525,7 @@ ble_att_svr_build_exec_write_rsp(struct os_mbuf **out_txom, uint8_t *att_err)
     uint8_t *dst;
     int rc;
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         *att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
         rc = BLE_HS_ENOMEM;
@@ -2707,8 +2617,9 @@ done:
         }
     }
 
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_EXEC_WRITE_REQ,
                             att_err, err_handle);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 
@@ -2720,8 +2631,6 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom)
 #endif
 
     struct ble_att_notify_req req;
-    uint16_t attr_len;
-    void *attr_data;
     int rc;
 
     if (OS_MBUF_PKTLEN(*rxom) < BLE_ATT_NOTIFY_REQ_BASE_SZ) {
@@ -2744,11 +2653,8 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom)
     /* Strip the request base from the front of the mbuf. */
     os_mbuf_adj(*rxom, BLE_ATT_NOTIFY_REQ_BASE_SZ);
 
-    attr_data = ble_att_get_flat_buf();
-    attr_len = OS_MBUF_PKTLEN(*rxom);
-    os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
-
-    ble_gap_notify_rx_event(conn_handle, req.banq_handle, attr_data, attr_len, 0);
+    ble_gap_notify_rx_event(conn_handle, req.banq_handle, *rxom, 0);
+    *rxom = NULL;
 
     return 0;
 }
@@ -2763,7 +2669,7 @@ ble_att_svr_build_indicate_rsp(struct os_mbuf **out_txom)
     uint8_t *dst;
     int rc;
 
-    txom = ble_hs_misc_pkthdr();
+    txom = ble_hs_mbuf_l2cap_pkt();
     if (txom == NULL) {
         rc = BLE_HS_ENOMEM;
         goto done;
@@ -2793,8 +2699,6 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
 
     struct ble_att_indicate_req req;
     struct os_mbuf *txom;
-    uint16_t attr_len;
-    void *attr_data;
     int rc;
 
     /* Initialize some values in case of early error. */
@@ -2822,11 +2726,8 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
     /* Strip the request base from the front of the mbuf. */
     os_mbuf_adj(*rxom, BLE_ATT_INDICATE_REQ_BASE_SZ);
 
-    attr_data = ble_att_get_flat_buf();
-    attr_len = OS_MBUF_PKTLEN(*rxom);
-    os_mbuf_copydata(*rxom, 0, attr_len, attr_data);
-
-    ble_gap_notify_rx_event(conn_handle, req.baiq_handle, attr_data, attr_len, 1);
+    ble_gap_notify_rx_event(conn_handle, req.baiq_handle, *rxom, 1);
+    *rxom = NULL;
 
     rc = ble_att_svr_build_indicate_rsp(&txom);
     if (rc != 0) {
@@ -2837,8 +2738,9 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom)
     rc = 0;
 
 done:
-    rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_INDICATE_REQ,
+    rc = ble_att_svr_tx_rsp(conn_handle, rc, &txom, BLE_ATT_OP_INDICATE_REQ,
                             0, 0);
+    os_mbuf_free_chain(txom);
     return rc;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index 18c4122..c8d0383 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -2806,7 +2806,7 @@ ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi)
 
 void
 ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
-                        void *attr_data, uint16_t attr_len, int is_indication)
+                        struct os_mbuf *om, int is_indication)
 {
 #if !NIMBLE_OPT(GATT_NOTIFY) && !NIMBLE_OPT(GATT_INDICATE)
     return;
@@ -2818,10 +2818,11 @@ ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
     event.type = BLE_GAP_EVENT_NOTIFY_RX;
     event.notify_rx.conn_handle = conn_handle;
     event.notify_rx.attr_handle = attr_handle;
-    event.notify_rx.attr_data = attr_data;
-    event.notify_rx.attr_len = attr_len;
+    event.notify_rx.om = om;
     event.notify_rx.indication = is_indication;
     ble_gap_call_conn_event_cb(&event, conn_handle);
+
+    os_mbuf_free_chain(event.notify_rx.om);
 }
 
 void

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/net/nimble/host/src/ble_gap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h
index 69d9538..449a4b0 100644
--- a/net/nimble/host/src/ble_gap_priv.h
+++ b/net/nimble/host/src/ble_gap_priv.h
@@ -83,8 +83,7 @@ void ble_gap_enc_event(uint16_t conn_handle, int status,
 void ble_gap_passkey_event(uint16_t conn_handle,
                            struct ble_gap_passkey_params *passkey_params);
 void ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
-                             void *attr_data, uint16_t attr_len,
-                             int is_indication);
+                             struct os_mbuf *om, int is_indication);
 void ble_gap_notify_tx_event(int status, uint16_t conn_handle,
                              uint16_t attr_handle, int is_indication);
 void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 73907b7..c33d5c6 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -95,21 +95,19 @@ struct ble_gatts_conn {
 
 /*** @client. */
 int ble_gattc_locked_by_cur_task(void);
-int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle);
 void ble_gatts_indicate_fail_notconn(uint16_t conn_handle);
-int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
 
 void ble_gattc_rx_err(uint16_t conn_handle, struct ble_att_error_rsp *rsp);
 void ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu);
 void ble_gattc_rx_read_type_adata(uint16_t conn_handle,
                                   struct ble_att_read_type_adata *adata);
 void ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status);
-void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
-                           int value_len);
+void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status,
+                           struct os_mbuf **om);
 void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
-                                void *value, int value_len);
+                                struct os_mbuf **om);
 void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
-                                void *value, int value_len);
+                                struct os_mbuf **om);
 void ble_gattc_rx_read_group_type_adata(
     uint16_t conn_handle, struct ble_att_read_group_type_adata *adata);
 void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int rc);
@@ -119,7 +117,7 @@ void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status);
 void ble_gattc_rx_write_rsp(uint16_t conn_handle);
 void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
                                  struct ble_att_prep_write_cmd *rsp,
-                                 void *attr_data, uint16_t attr_data_len);
+                                 struct os_mbuf **om);
 void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status);
 void ble_gattc_rx_indicate_rsp(uint16_t conn_handle);
 void ble_gattc_rx_find_info_idata(uint16_t conn_handle,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ef7abf7d/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 c4ba96b..323c7f2 100644
--- a/net/nimble/host/src/ble_gattc.c
+++ b/net/nimble/host/src/ble_gattc.c
@@ -182,9 +182,10 @@ struct ble_gattc_proc {
         } write_long;
 
         struct {
-            const struct ble_gatt_attr *attrs;
-            int num_attrs;
-            int cur_attr;
+            struct ble_gatt_attr attrs[NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)];
+            uint8_t num_attrs;
+            uint8_t cur_attr;
+            uint16_t length;
             ble_gatt_reliable_attr_fn *cb;
             void *cb_arg;
         } write_reliable;
@@ -246,10 +247,10 @@ typedef int ble_gattc_rx_adata_fn(struct ble_gattc_proc *proc,
 
 typedef int ble_gattc_rx_prep_fn(struct ble_gattc_proc *proc, int status,
                                  struct ble_att_prep_write_cmd *rsp,
-                                 void *attr_data, uint16_t attr_len);
+                                 struct os_mbuf **om);
 
 typedef int ble_gattc_rx_attr_fn(struct ble_gattc_proc *proc, int status,
-                                 void *value, int value_len);
+                                 struct os_mbuf **om);
 
 typedef int ble_gattc_rx_complete_fn(struct ble_gattc_proc *proc, int status);
 typedef int ble_gattc_rx_exec_fn(struct ble_gattc_proc *proc, int status);
@@ -516,7 +517,8 @@ ble_gattc_log_write_long(struct ble_gattc_proc *proc)
 {
     ble_gattc_log_proc_init("write long; ");
     BLE_HS_LOG(INFO, "att_handle=%d len=%d\n",
-               proc->write_long.attr.handle, proc->write_long.attr.value_len);
+               proc->write_long.attr.handle,
+               OS_MBUF_PKTLEN(proc->write_long.attr.om));
 }
 
 static void
@@ -601,10 +603,26 @@ static void
 ble_gattc_proc_free(struct ble_gattc_proc *proc)
 {
     int rc;
+    int i;
 
     if (proc != NULL) {
         ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+        switch (proc->op) {
+        case BLE_GATT_OP_WRITE_LONG:
+            os_mbuf_free_chain(proc->write_long.attr.om);
+            break;
+
+        case BLE_GATT_OP_WRITE_RELIABLE:
+            for (i = 0; i < proc->write_reliable.num_attrs; i++) {
+                os_mbuf_free_chain(proc->write_reliable.attrs[i].om);
+            }
+            break;
+
+        default:
+            break;
+        }
+
         rc = os_memblock_put(&ble_gattc_proc_pool, proc);
         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
     }
@@ -1577,13 +1595,24 @@ ble_gattc_find_inc_svcs_err(struct ble_gattc_proc *proc, int status,
  */
 static int
 ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
-                                    void *value, int value_len)
+                                    struct os_mbuf **om)
 {
     struct ble_gatt_svc service;
+    uint16_t om_len;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+    rc = ble_hs_mbuf_to_flat(*om, service.uuid128, 16, &om_len);
+    os_mbuf_free_chain(*om);
+    *om = NULL;
+
+    if (rc != 0 || om_len != 16) {
+        /* Invalid UUID. */
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+
     if (proc->find_inc_svcs.cur_start == 0) {
         /* Unexpected read response; terminate procedure. */
         rc = BLE_HS_EBADDATA;
@@ -1595,16 +1624,9 @@ ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
         goto err;
     }
 
-    if (value_len != 16) {
-        /* Invalid UUID. */
-        rc = BLE_HS_EBADDATA;
-        goto err;
-    }
-
     /* Report discovered service to application. */
     service.start_handle = proc->find_inc_svcs.cur_start;
     service.end_handle = proc->find_inc_svcs.cur_end;
-    memcpy(service.uuid128, value, 16);
     rc = ble_gattc_find_inc_svcs_cb(proc, 0, 0, &service);
     if (rc != 0) {
         /* Application has indicated that the procedure should be aborted. */
@@ -2529,7 +2551,7 @@ ble_gattc_read_err(struct ble_gattc_proc *proc, int status,
  */
 static int
 ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status,
-                           void *value, int value_len)
+                           struct os_mbuf **om)
 {
     struct ble_gatt_attr attr;
 
@@ -2537,11 +2559,13 @@ ble_gattc_read_rx_read_rsp(struct ble_gattc_proc *proc, int status,
 
     attr.handle = proc->read.handle;
     attr.offset = 0;
-    attr.value_len = value_len;
-    attr.value = value;
+    attr.om = *om;
 
     ble_gattc_read_cb(proc, status, 0, &attr);
 
+    /* Indicate to the caller whether the application consumed the mbuf. */
+    *om = attr.om;
+
     /* The read operation only has a single request / response exchange. */
     return BLE_HS_EDONE;
 }
@@ -2670,10 +2694,18 @@ ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc *proc,
 
     attr.handle = adata->att_handle;
     attr.offset = 0;
-    attr.value_len = adata->value_len;
-    attr.value = adata->value;
+    attr.om = ble_hs_mbuf_from_flat(adata->value, adata->value_len);
+    if (attr.om == NULL) {
+        rc = BLE_HS_ENOMEM;
+    } else {
+        rc = 0;
+    }
+
+    rc = ble_gattc_read_uuid_cb(proc, rc, 0, &attr);
+
+    /* Free the attribute mbuf if the application has not consumed it. */
+    os_mbuf_free_chain(attr.om);
 
-    rc = ble_gattc_read_uuid_cb(proc, 0, 0, &attr);
     if (rc != 0) {
         return BLE_HS_EDONE;
     }
@@ -2847,21 +2879,27 @@ ble_gattc_read_long_err(struct ble_gattc_proc *proc, int status,
  */
 static int
 ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status,
-                                void *value, int value_len)
+                                struct os_mbuf **om)
 {
     struct ble_gatt_attr attr;
+    uint16_t data_len;
     uint16_t mtu;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+    data_len = OS_MBUF_PKTLEN(*om);
+
     attr.handle = proc->read_long.handle;
     attr.offset = proc->read_long.offset;
-    attr.value_len = value_len;
-    attr.value = value;
+    attr.om = *om;
 
     /* Report partial payload to application. */
     rc = ble_gattc_read_long_cb(proc, status, 0, &attr);
+
+    /* Indicate to the caller whether the application consumed the mbuf. */
+    *om = attr.om;
+
     if (rc != 0 || status != 0) {
         return BLE_HS_EDONE;
     }
@@ -2873,14 +2911,14 @@ ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status,
         return BLE_HS_EDONE;
     }
 
-    if (value_len < mtu - 1) {
+    if (data_len < mtu - 1) {
         /* Response shorter than maximum allowed; read complete. */
         ble_gattc_read_long_cb(proc, BLE_HS_EDONE, 0, NULL);
         return BLE_HS_EDONE;
     }
 
     /* Send follow-up request. */
-    proc->read_long.offset += value_len;
+    proc->read_long.offset += data_len;
     rc = ble_gattc_read_long_go(proc, 1);
     if (rc != 0) {
         return BLE_HS_EDONE;
@@ -2957,39 +2995,40 @@ done:
  */
 static int
 ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status,
-                       uint16_t att_handle, uint8_t *attr_data,
-                       uint16_t attr_data_len)
+                       uint16_t att_handle, struct os_mbuf **om)
 {
-    struct ble_gatt_attr *attrp;
     struct ble_gatt_attr attr;
     int rc;
 
     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
-    BLE_HS_DBG_ASSERT(attr_data != NULL || status != 0);
+    BLE_HS_DBG_ASSERT(om != NULL || status != 0);
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
     if (status != 0 && status != BLE_HS_EDONE) {
         STATS_INC(ble_gattc_stats, read_mult_fail);
     }
 
+    attr.handle = 0;
+    attr.offset = 0;
+    if (om == NULL) {
+        attr.om = NULL;
+    } else {
+        attr.om = *om;
+    }
+
     if (proc->read_mult.cb == NULL) {
         rc = 0;
     } else {
-        if (status != 0) {
-            attrp = NULL;
-        } else {
-            attrp = &attr;
-            attr.handle = 0;
-            attr.offset = 0;
-            attr.value_len = attr_data_len;
-            attr.value = attr_data;
-        }
-
         rc = proc->read_mult.cb(proc->conn_handle,
-                                ble_gattc_error(status, att_handle), attrp,
+                                ble_gattc_error(status, att_handle), &attr,
                                 proc->read_mult.cb_arg);
     }
 
+    /* Indicate to the caller whether the application consumed the mbuf. */
+    if (om != NULL) {
+        *om = attr.om;
+    }
+
     return rc;
 }
 
@@ -3002,7 +3041,7 @@ ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status,
                         uint16_t att_handle)
 {
     ble_gattc_dbg_assert_proc_not_inserted(proc);
-    ble_gattc_read_mult_cb(proc, status, att_handle, NULL, 0);
+    ble_gattc_read_mult_cb(proc, status, att_handle, NULL);
 }
 
 /**
@@ -3065,20 +3104,22 @@ done:
  *****************************************************************************/
 
 /**
- * Initiates GATT procedure: Write Without Response.
+ * Initiates GATT procedure: Write Without Response.  This function consumes
+ * the supplied mbuf regardless of the outcome.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
  * @param attr_handle           The handle of the characteristic value to write
  *                                  to.
- * @param value                 The value to write to the characteristic.
- * @param value_len             The number of bytes to write.
+ * @param txom                  The value to write to the characteristic.
+ *                                  Double indirection is used to effect a
+ *                                  transfer of ownership from the caller.
  *
  * @return                      0 on success; nonzero on failure.
  */
 int
 ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
-                       const void *value, uint16_t value_len)
+                       struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(GATT_WRITE_NO_RSP)
     return BLE_HS_ENOTSUP;
@@ -3089,17 +3130,54 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
 
     STATS_INC(ble_gattc_stats, write_no_rsp);
 
-    ble_gattc_log_write(attr_handle, value_len, 0);
+    ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(*txom), 0);
 
     req.bawq_handle = attr_handle;
-    rc = ble_att_clt_tx_write_cmd(conn_handle, &req, value, value_len);
+    rc = ble_att_clt_tx_write_cmd(conn_handle, &req, txom);
     if (rc != 0) {
         STATS_INC(ble_gattc_stats, write);
     }
 
+    /* Free the mbuf in case the send failed. */
+    os_mbuf_free_chain(*txom);
+    *txom = NULL;
+
     return rc;
 }
 
+/**
+ * Initiates GATT procedure: Write Without Response.  This function consumes
+ * the supplied mbuf regardless of the outcome.
+ *
+ * @param conn_handle           The connection over which to execute the
+ *                                  procedure.
+ * @param attr_handle           The handle of the characteristic value to write
+ *                                  to.
+ * @param value                 The value to write to the characteristic.
+ * @param value_len             The number of bytes to write.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
+                            const void *data, uint16_t data_len)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_mbuf_from_flat(data, data_len);
+    if (om == NULL) {
+        return BLE_HS_ENOMEM;
+    }
+
+    rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, &om);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
 /*****************************************************************************
  * $write                                                                    *
  *****************************************************************************/
@@ -3151,14 +3229,16 @@ ble_gattc_write_err(struct ble_gattc_proc *proc, int status,
 }
 
 /**
- * Initiates GATT procedure: Write Characteristic Value.
+ * Initiates GATT procedure: Write Characteristic Value.  This function
+ * consumes the supplied mbuf regardless of the outcome.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
  * @param attr_handle           The handle of the characteristic value to write
  *                                  to.
- * @param value                 The value to write to the characteristic.
- * @param value_len             The number of bytes to write.
+ * @param txom                  The value to write to the characteristic.
+ *                                  Double indirection is used to effect a
+ *                                  transfer of ownership from the caller.
  * @param cb                    The function to call to report procedure status
  *                                  updates; null for no callback.
  * @param cb_arg                The optional argument to pass to the callback
@@ -3167,8 +3247,8 @@ ble_gattc_write_err(struct ble_gattc_proc *proc, int status,
  * @return                      0 on success; nonzero on failure.
  */
 int
-ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
-                uint16_t value_len, ble_gatt_attr_fn *cb, void *cb_arg)
+ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
+                struct os_mbuf **txom, ble_gatt_attr_fn *cb, void *cb_arg)
 {
 #if !NIMBLE_OPT(GATT_WRITE)
     return BLE_HS_ENOTSUP;
@@ -3192,10 +3272,10 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
     proc->write.cb = cb;
     proc->write.cb_arg = cb_arg;
 
-    ble_gattc_log_write(attr_handle, value_len, 1);
+    ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(*txom), 1);
 
     req.bawq_handle = attr_handle;
-    rc = ble_att_clt_tx_write_req(conn_handle, &req, value, value_len);
+    rc = ble_att_clt_tx_write_req(conn_handle, &req, txom);
     if (rc != 0) {
         goto done;
     }
@@ -3205,10 +3285,51 @@ done:
         STATS_INC(ble_gattc_stats, write_fail);
     }
 
+    /* Free the mbuf in case the send failed. */
+    os_mbuf_free_chain(*txom);
+    *txom = NULL;
+
     ble_gattc_process_status(proc, rc);
     return rc;
 }
 
+/**
+ * Initiates GATT procedure: Write Characteristic Value (flat buffer version).
+ *
+ * @param conn_handle           The connection over which to execute the
+ *                                  procedure.
+ * @param attr_handle           The handle of the characteristic value to write
+ *                                  to.
+ * @param value                 The value to write to the characteristic.
+ * @param value_len             The number of bytes to write.
+ * @param cb                    The function to call to report procedure status
+ *                                  updates; null for no callback.
+ * @param cb_arg                The optional argument to pass to the callback
+ *                                  function.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
+                     const void *data, uint16_t data_len,
+                     ble_gatt_attr_fn *cb, void *cb_arg)
+{
+    struct os_mbuf *om;
+    int rc;
+
+    om = ble_hs_mbuf_from_flat(data, data_len);
+    if (om == NULL) {
+        return BLE_HS_ENOMEM;
+    }
+
+    rc = ble_gattc_write(conn_handle, attr_handle, &om, cb, cb_arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
 /*****************************************************************************
  * $write long                                                               *
  *****************************************************************************/
@@ -3254,48 +3375,65 @@ ble_gattc_write_long_go(struct ble_gattc_proc *proc, int cb_on_err)
 {
     struct ble_att_prep_write_cmd prep_req;
     struct ble_att_exec_write_req exec_req;
-    const void *value;
+    struct os_mbuf *om;
     int max_sz;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
-    if (proc->write_long.attr.offset < proc->write_long.attr.value_len) {
-        max_sz = ble_att_mtu(proc->conn_handle) -
-                 BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
-        if (max_sz == 0) {
-            /* Not connected. */
-            rc = BLE_HS_ENOTCONN;
-        } else {
-            if (proc->write_long.attr.offset + max_sz >
-                proc->write_long.attr.value_len) {
+    om = NULL;
 
-                proc->write_long.length = proc->write_long.attr.value_len -
-                                          proc->write_long.attr.offset;
-            } else {
-                proc->write_long.length = max_sz;
-            }
+    if (proc->write_long.attr.offset +
+        OS_MBUF_PKTLEN(proc->write_long.attr.om) <= 0) {
 
-            prep_req.bapc_handle = proc->write_long.attr.handle;
-            prep_req.bapc_offset = proc->write_long.attr.offset;
-            value = proc->write_long.attr.value + proc->write_long.attr.offset;
-            rc = ble_att_clt_tx_prep_write(proc->conn_handle,
-                                           &prep_req, value,
-                                           proc->write_long.length);
-        }
-    } else {
         exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM;
         rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
+        goto done;
     }
 
+    max_sz = ble_att_mtu(proc->conn_handle) -
+             BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
+    if (max_sz <= 0) {
+        /* Not connected. */
+        rc = BLE_HS_ENOTCONN;
+        goto done;
+    }
+
+    proc->write_long.length =
+        min(max_sz,
+            OS_MBUF_PKTLEN(proc->write_long.attr.om) -
+                proc->write_long.attr.offset);
+
+    om = ble_hs_mbuf_att_pkt();
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    rc = os_mbuf_appendfrom(om, proc->write_long.attr.om,
+                            proc->write_long.attr.offset,
+                            proc->write_long.length);
     if (rc != 0) {
-        if (cb_on_err) {
-            ble_gattc_write_long_cb(proc, rc, 0);
-        }
-        return rc;
+        rc = BLE_HS_ENOMEM;
+        goto done;
     }
 
-    return 0;
+    prep_req.bapc_handle = proc->write_long.attr.handle;
+    prep_req.bapc_offset = proc->write_long.attr.offset;
+
+    rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, &om);
+    if (rc != 0) {
+        goto done;
+    }
+
+done:
+    os_mbuf_free_chain(om);
+
+    if (rc != 0 && cb_on_err) {
+        ble_gattc_write_long_cb(proc, rc, 0);
+    }
+
+    return rc;
 }
 
 /**
@@ -3314,7 +3452,8 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
      * we could send the execute write command, then erase all queued data.
      */
     if (proc->write_long.attr.offset > 0 &&
-        proc->write_long.attr.offset < proc->write_long.attr.value_len) {
+        proc->write_long.attr.offset <
+            OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
 
         exec_req.baeq_flags = 0;
         ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
@@ -3331,12 +3470,16 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status,
 static int
 ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc,
                              int status, struct ble_att_prep_write_cmd *rsp,
-                             void *attr_data, uint16_t attr_len)
+                             struct os_mbuf **rxom)
 {
+    struct os_mbuf *om;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+    /* Let the caller free the mbuf. */
+    om = *rxom;
+
     if (status != 0) {
         rc = status;
         goto err;
@@ -3351,22 +3494,26 @@ ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc,
         rc = BLE_HS_EBADDATA;
         goto err;
     }
-    if (rsp->bapc_offset + attr_len > proc->write_long.attr.value_len) {
+    if (rsp->bapc_offset + OS_MBUF_PKTLEN(om) >
+        OS_MBUF_PKTLEN(proc->write_long.attr.om)) {
+
         rc = BLE_HS_EBADDATA;
         goto err;
     }
-    if (attr_len != proc->write_long.length) {
+    if (OS_MBUF_PKTLEN(om) != proc->write_long.length) {
         rc = BLE_HS_EBADDATA;
         goto err;
     }
-    if (memcmp(attr_data, proc->write_long.attr.value + rsp->bapc_offset,
-               attr_len) != 0) {
+    if (os_mbuf_cmpm(om, 0,
+                     proc->write_long.attr.om, rsp->bapc_offset,
+                     proc->write_long.length) != 0) {
+
         rc = BLE_HS_EBADDATA;
         goto err;
     }
 
     /* Send follow-up request. */
-    proc->write_long.attr.offset += attr_len;
+    proc->write_long.attr.offset += OS_MBUF_PKTLEN(om);
     rc = ble_gattc_write_long_go(proc, 1);
     if (rc != 0) {
         goto err;
@@ -3393,14 +3540,16 @@ ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
 }
 
 /**
- * Initiates GATT procedure: Write Long Characteristic Values.
+ * Initiates GATT procedure: Write Long Characteristic Values.  This function
+ * consumes the supplied mbuf regardless of the outcome.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
  * @param attr_handle           The handle of the characteristic value to write
  *                                  to.
- * @param value                 The value to write to the characteristic.
- * @param value_len             The number of bytes to write.
+ * @param txom                  The value to write to the characteristic.
+ *                                  Double indirection is used to effect a
+ *                                  transfer of ownership from the caller.
  * @param cb                    The function to call to report procedure status
  *                                  updates; null for no callback.
  * @param cb_arg                The optional argument to pass to the callback
@@ -3410,8 +3559,7 @@ ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
  */
 int
 ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
-                     const void *value, uint16_t value_len,
-                     ble_gatt_attr_fn *cb, void *cb_arg)
+                     struct os_mbuf **txom, ble_gatt_attr_fn *cb, void *cb_arg)
 {
 #if !NIMBLE_OPT(GATT_WRITE_LONG)
     return BLE_HS_ENOTSUP;
@@ -3432,11 +3580,13 @@ ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
     proc->conn_handle = conn_handle;
     proc->write_long.attr.handle = attr_handle;
     proc->write_long.attr.offset = 0;
-    proc->write_long.attr.value = value;
-    proc->write_long.attr.value_len = value_len;
+    proc->write_long.attr.om = *txom;
     proc->write_long.cb = cb;
     proc->write_long.cb_arg = cb_arg;
 
+    /* The mbuf is consumed by the procedure. */
+    *txom = NULL;
+
     ble_gattc_log_write_long(proc);
 
     rc = ble_gattc_write_long_go(proc, 0);
@@ -3449,6 +3599,10 @@ done:
         STATS_INC(ble_gattc_stats, write_long_fail);
     }
 
+    /* Free the mbuf in case of failure. */
+    os_mbuf_free_chain(*txom);
+    *txom = NULL;
+
     ble_gattc_process_status(proc, rc);
     return rc;
 }
@@ -3499,32 +3653,65 @@ ble_gattc_write_reliable_go(struct ble_gattc_proc *proc, int cb_on_err)
 {
     struct ble_att_prep_write_cmd prep_req;
     struct ble_att_exec_write_req exec_req;
-    const struct ble_gatt_attr *attr;
+    struct ble_gatt_attr *attr;
+    struct os_mbuf *om;
+    uint16_t max_sz;
     int attr_idx;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+    om = NULL;
+
     attr_idx = proc->write_reliable.cur_attr;
-    if (attr_idx < proc->write_reliable.num_attrs) {
-        attr = proc->write_reliable.attrs + attr_idx;
-        prep_req.bapc_handle = attr->handle;
-        prep_req.bapc_offset = 0;
-        rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req,
-                                       attr->value, attr->value_len);
-    } else {
+
+    if (attr_idx >= proc->write_reliable.num_attrs) {
         exec_req.baeq_flags = BLE_ATT_EXEC_WRITE_F_CONFIRM;
         rc = ble_att_clt_tx_exec_write(proc->conn_handle, &exec_req);
+        goto done;
+    }
+
+    attr = proc->write_reliable.attrs + attr_idx;
+
+    max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
+    if (max_sz <= 0) {
+        /* Not connected. */
+        rc = BLE_HS_ENOTCONN;
+        goto done;
+    }
+
+    proc->write_reliable.length =
+        min(max_sz, OS_MBUF_PKTLEN(attr->om) - attr->offset);
+
+    om = ble_hs_mbuf_att_pkt();
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
     }
 
+    rc = os_mbuf_appendfrom(om, attr->om, attr->offset,
+                            proc->write_reliable.length);
     if (rc != 0) {
-        if (cb_on_err) {
-            ble_gattc_write_reliable_cb(proc, rc, 0);
-        }
-        return rc;
+        rc = BLE_HS_ENOMEM;
+        goto done;
     }
 
-    return 0;
+    prep_req.bapc_handle = attr->handle;
+    prep_req.bapc_offset = attr->offset;
+
+    rc = ble_att_clt_tx_prep_write(proc->conn_handle, &prep_req, &om);
+    if (rc != 0) {
+        goto done;
+    }
+
+done:
+    os_mbuf_free_chain(om);
+
+    if (rc != 0 && cb_on_err) {
+        ble_gattc_write_reliable_cb(proc, rc, 0);
+    }
+
+    return rc;
 }
 
 /**
@@ -3559,19 +3746,24 @@ static int
 ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
                                  int status,
                                  struct ble_att_prep_write_cmd *rsp,
-                                 void *attr_data, uint16_t attr_len)
+                                 struct os_mbuf **rxom)
 {
-    const struct ble_gatt_attr *attr;
+    struct ble_gatt_attr *attr;
+    struct os_mbuf *om;
     int rc;
 
     ble_gattc_dbg_assert_proc_not_inserted(proc);
 
+    /* Let the caller free the mbuf. */
+    om = *rxom;
+
     if (status != 0) {
         rc = status;
         goto err;
     }
 
     if (proc->write_reliable.cur_attr >= proc->write_reliable.num_attrs) {
+        /* Expecting an execute write response, not a prepare write response. */
         rc = BLE_HS_EBADDATA;
         goto err;
     }
@@ -3582,21 +3774,23 @@ ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
         rc = BLE_HS_EBADDATA;
         goto err;
     }
-    if (rsp->bapc_offset != 0) {
-        rc = BLE_HS_EBADDATA;
-        goto err;
-    }
-    if (attr_len != attr->value_len) {
+    if (rsp->bapc_offset != attr->offset) {
         rc = BLE_HS_EBADDATA;
         goto err;
     }
-    if (memcmp(attr_data, attr->value, attr_len) != 0) {
+    if (os_mbuf_cmpm(attr->om, rsp->bapc_offset, om, 0,
+                     proc->write_reliable.length) != 0) {
+
         rc = BLE_HS_EBADDATA;
         goto err;
     }
 
     /* Send follow-up request. */
-    proc->write_reliable.cur_attr++;
+    attr->offset += proc->write_reliable.length;
+    if (attr->offset >= OS_MBUF_PKTLEN(attr->om)) {
+        attr->offset = 0;
+        proc->write_reliable.cur_attr++;
+    }
     rc = ble_gattc_write_reliable_go(proc, 1);
     if (rc != 0) {
         goto err;
@@ -3623,13 +3817,16 @@ ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status)
 }
 
 /**
- * Initiates GATT procedure: Reliable Writes.
+ * Initiates GATT procedure: Reliable Writes.  This function consumes the
+ * supplied mbufs regardless of the outcome.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
  * @param attrs                 An array of attribute descriptors; specifies
  *                                  which characteristics to write to and what
- *                                  data to write to them.
+ *                                  data to write to them.  The mbuf pointer in
+ *                                  each attribute is set to NULL by this
+ *                                  function.
  * @param num_attrs             The number of characteristics to write; equal
  *                                  to the number of elements in the 'attrs'
  *                                  array.
@@ -3640,9 +3837,9 @@ ble_gattc_write_reliable_rx_exec(struct ble_gattc_proc *proc, int status)
  */
 int
 ble_gattc_write_reliable(uint16_t conn_handle,
-                         const struct ble_gatt_attr *attrs,
-                         int num_attrs, ble_gatt_reliable_attr_fn *cb,
-                         void *cb_arg)
+                         struct ble_gatt_attr *attrs,
+                         int num_attrs,
+                         ble_gatt_reliable_attr_fn *cb, void *cb_arg)
 {
 #if !NIMBLE_OPT(GATT_WRITE_RELIABLE)
     return BLE_HS_ENOTSUP;
@@ -3650,9 +3847,17 @@ ble_gattc_write_reliable(uint16_t conn_handle,
 
     struct ble_gattc_proc *proc;
     int rc;
+    int i;
+
+    proc = NULL;
 
     STATS_INC(ble_gattc_stats, write_reliable);
 
+    if (num_attrs > NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)) {
+        rc = BLE_HS_EINVAL;
+        goto done;
+    }
+
     proc = ble_gattc_proc_alloc();
     if (proc == NULL) {
         rc = BLE_HS_ENOMEM;
@@ -3661,12 +3866,19 @@ ble_gattc_write_reliable(uint16_t conn_handle,
 
     proc->op = BLE_GATT_OP_WRITE_RELIABLE;
     proc->conn_handle = conn_handle;
-    proc->write_reliable.attrs = attrs;
     proc->write_reliable.num_attrs = num_attrs;
     proc->write_reliable.cur_attr = 0;
     proc->write_reliable.cb = cb;
     proc->write_reliable.cb_arg = cb_arg;
 
+    for (i = 0; i < num_attrs; i++) {
+        proc->write_reliable.attrs[i] = attrs[i];
+        proc->write_reliable.attrs[i].offset = 0;
+
+        /* Consume mbuf from caller. */
+        attrs[i].om = NULL;
+    }
+
     ble_gattc_log_write_reliable(proc);
 
     rc = ble_gattc_write_reliable_go(proc, 1);
@@ -3679,6 +3891,12 @@ done:
         STATS_INC(ble_gattc_stats, write_reliable_fail);
     }
 
+    /* Free supplied mbufs in case something failed. */
+    for (i = 0; i < num_attrs; i++) {
+        os_mbuf_free_chain(attrs[i].om);
+        attrs[i].om = NULL;
+    }
+
     ble_gattc_process_status(proc, rc);
     return rc;
 }
@@ -3688,54 +3906,59 @@ done:
  *****************************************************************************/
 
 /**
- * Sends a "free-form" characteristic notification.  The content of the message
- * is specified in the attr parameter.
+ * Sends a "free-form" characteristic notification.  This function consumes the
+ * supplied mbuf regardless of the outcome.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
  * @param chr_val_handle        The attribute handle to indicate in the
  *                                  outgoing notification.
- * @param attr_data             The characteristic value to include in the
- *                                  outgoing notification.
- * @param attr_data_len         The number of bytes of attribute data to include
- *                                  in the notification.
+ * @param txom                  The value to write to the characteristic.
+ *                                  Double indirection is used to effect a
+ *                                  transfer of ownership from the caller.
  *
  * @return                      0 on success; nonzero on failure.
  */
 int
 ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
-                        const void *attr_data, uint16_t attr_data_len)
+                        struct os_mbuf **txom)
 {
 #if !NIMBLE_OPT(GATT_NOTIFY)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_notify_req req;
+    struct os_mbuf *om;
     int rc;
 
     STATS_INC(ble_gattc_stats, notify);
 
     ble_gattc_log_notify(chr_val_handle);
 
-    if (attr_data == NULL) {
+    if (txom != NULL) {
+        /* Consume mbuf from caller. */
+        om = *txom;
+        *txom = NULL;
+    } else {
         /* No custom attribute data; read the value from the specified
          * attribute.
          */
+        om = ble_hs_mbuf_att_pkt();
+        if (om == NULL) {
+            rc = BLE_HS_ENOMEM;
+            goto done;
+        }
         rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE,
-                                     chr_val_handle, &ctxt, NULL);
+                                     chr_val_handle, 0, om, NULL);
         if (rc != 0) {
             /* Fatal error; application disallowed attribute read. */
             rc = BLE_HS_EAPP;
             goto done;
         }
-
-        attr_data = ctxt.read.data;
-        attr_data_len = ctxt.read.len;
     }
 
     req.banq_handle = chr_val_handle;
-    rc = ble_att_clt_tx_notify(conn_handle, &req, attr_data, attr_data_len);
+    rc = ble_att_clt_tx_notify(conn_handle, &req, &om);
     if (rc != 0) {
         goto done;
     }
@@ -3747,12 +3970,14 @@ done:
         STATS_INC(ble_gattc_stats, notify_fail);
     }
 
+    os_mbuf_free_chain(om);
+
     return rc;
 }
 
 /**
- * Sends a characteristic notification.  The content of the message is read from
- * the specified characteristic.
+ * Sends a characteristic notification.  The content of the message is read
+ * from the specified characteristic.
  *
  * @param conn_handle           The connection over which to execute the
  *                                  procedure.
@@ -3771,7 +3996,7 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle)
 
     int rc;
 
-    rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL, 0);
+    rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL);
 
     /* Tell the application that a notification transmission was attempted. */
     ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 0);
@@ -3867,10 +4092,10 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
     return BLE_HS_ENOTSUP;
 #endif
 
-    struct ble_att_svr_access_ctxt ctxt;
     struct ble_att_indicate_req req;
     struct ble_gattc_proc *proc;
     struct ble_hs_conn *conn;
+    struct os_mbuf *om;
     int rc;
 
     STATS_INC(ble_gattc_stats, indicate);
@@ -3887,8 +4112,14 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
 
     ble_gattc_log_indicate(chr_val_handle);
 
-    rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle,
-                                 &ctxt, NULL);
+    om = ble_hs_mbuf_att_pkt();
+    if (om == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, chr_val_handle, 0,
+                                 om, NULL);
     if (rc != 0) {
         /* Fatal error; application disallowed attribute read. */
         BLE_HS_DBG_ASSERT(0);
@@ -3897,9 +4128,7 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle)
     }
 
     req.baiq_handle = chr_val_handle;
-    rc = ble_att_clt_tx_indicate(conn_handle, &req,
-                                 ctxt.read.data, ctxt.read.len);
-
+    rc = ble_att_clt_tx_indicate(conn_handle, &req, &om);
     if (rc != 0) {
         goto done;
     }
@@ -3922,6 +4151,7 @@ done:
     ble_gap_notify_tx_event(rc, conn_handle, chr_val_handle, 1);
 
     ble_gattc_process_status(proc, rc);
+    os_mbuf_free_chain(om);
     return rc;
 }
 
@@ -4149,8 +4379,7 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status)
  * procedure.
  */
 void
-ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
-                      int value_len)
+ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om)
 {
 #if !NIMBLE_OPT(ATT_CLT_READ)
     return;
@@ -4164,7 +4393,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
                                          ble_gattc_rx_read_rsp_entries,
                                          &rx_entry);
     if (proc != NULL) {
-        rc = rx_entry->cb(proc, status, value, value_len);
+        rc = rx_entry->cb(proc, status, om);
         ble_gattc_process_status(proc, rc);
     }
 }
@@ -4175,7 +4404,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, void *value,
  */
 void
 ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
-                           void *value, int value_len)
+                           struct os_mbuf **om)
 {
 #if !NIMBLE_OPT(ATT_CLT_READ_BLOB)
     return;
@@ -4186,7 +4415,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
 
     proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_LONG);
     if (proc != NULL) {
-        rc = ble_gattc_read_long_rx_read_rsp(proc, status, value, value_len);
+        rc = ble_gattc_read_long_rx_read_rsp(proc, status, om);
         ble_gattc_process_status(proc, rc);
     }
 }
@@ -4197,7 +4426,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status,
  */
 void
 ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
-                           void *value, int value_len)
+                           struct os_mbuf **om)
 {
 #if !NIMBLE_OPT(ATT_CLT_READ_MULT)
     return;
@@ -4207,7 +4436,7 @@ ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status,
 
     proc = ble_gattc_extract(conn_handle, BLE_GATT_OP_READ_MULT);
     if (proc != NULL) {
-        ble_gattc_read_mult_cb(proc, status, 0, value, value_len);
+        ble_gattc_read_mult_cb(proc, status, 0, om);
         ble_gattc_process_status(proc, BLE_HS_EDONE);
     }
 }
@@ -4239,7 +4468,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle)
 void
 ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
                             struct ble_att_prep_write_cmd *rsp,
-                            void *attr_data, uint16_t attr_data_len)
+                            struct os_mbuf **om)
 {
 #if !NIMBLE_OPT(ATT_CLT_PREP_WRITE)
     return;
@@ -4253,7 +4482,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status,
                                          ble_gattc_rx_prep_entries,
                                          &rx_entry);
     if (proc != NULL) {
-        rc = rx_entry->cb(proc, status, rsp, attr_data, attr_data_len);
+        rc = rx_entry->cb(proc, status, rsp, om);
         ble_gattc_process_status(proc, rc);
     }
 }


[03/11] incubator-mynewt-core git commit: os - Add an mbuf function: os_mbuf_prepend_pullup

Posted by cc...@apache.org.
os - Add an mbuf function: os_mbuf_prepend_pullup

/**
 * Prepends a chunk of empty data to the specified mbuf chain and
 * ensures the chunk is contiguous.  If either operation fails, the
 * specified mbuf chain is freed and NULL is returned.
 *
 * @param om                    The mbuf chain to prepend to.
 * @param len                   The number of bytes to prepend and
 *                                  pullup.
 *
 * @return                      The modified mbuf on success;
 *                              NULL on failure (and the mbuf chain is
 *                                  freed).
 */
struct os_mbuf *
os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len)


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/5c4b292e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/5c4b292e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/5c4b292e

Branch: refs/heads/develop
Commit: 5c4b292edb2523a30585740171b025048912f0d9
Parents: 010602f
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Jul 21 12:26:55 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:01 2016 -0700

----------------------------------------------------------------------
 libs/os/include/os/os_mbuf.h |  1 +
 libs/os/src/os_mbuf.c        | 27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5c4b292e/libs/os/include/os/os_mbuf.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
index 785cafe..93e5ba4 100644
--- a/libs/os/include/os/os_mbuf.h
+++ b/libs/os/include/os/os_mbuf.h
@@ -284,6 +284,7 @@ int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
                  uint16_t len);
 
 struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len);
+struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len);
 int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len);
 void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second);
 void *os_mbuf_extend(struct os_mbuf *om, uint16_t len);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/5c4b292e/libs/os/src/os_mbuf.c
----------------------------------------------------------------------
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
index 2703caf..8306d16 100644
--- a/libs/os/src/os_mbuf.c
+++ b/libs/os/src/os_mbuf.c
@@ -967,6 +967,33 @@ os_mbuf_prepend(struct os_mbuf *om, int len)
 }
 
 /**
+ * Prepends a chunk of empty data to the specified mbuf chain and ensures the
+ * chunk is contiguous.  If either operation fails, the specified mbuf chain is
+ * freed and NULL is returned.
+ *
+ * @param om                    The mbuf chain to prepend to.
+ * @param len                   The number of bytes to prepend and pullup.
+ *
+ * @return                      The modified mbuf on success;
+ *                              NULL on failure (and the mbuf chain is freed).
+ */
+struct os_mbuf *
+os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len)
+{
+    om = os_mbuf_prepend(om, len);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    om = os_mbuf_pullup(om, len);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    return om;
+}
+
+/**
  * Copies the contents of a flat buffer into an mbuf chain, starting at the
  * specified destination offset.  If the mbuf is too small for the source data,
  * it is extended as necessary.  If the destination mbuf contains a packet


[04/11] incubator-mynewt-core git commit: newtmgr_ble - Use new host mbuf API.

Posted by cc...@apache.org.
newtmgr_ble - Use new host mbuf API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/a10cdd0f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/a10cdd0f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/a10cdd0f

Branch: refs/heads/develop
Commit: a10cdd0f4e04e70fca63b152a305ea000cc5b0d3
Parents: ef7abf7
Author: Christopher Collins <cc...@apache.org>
Authored: Fri Jul 22 12:09:06 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:01 2016 -0700

----------------------------------------------------------------------
 libs/newtmgr/transport/ble/src/newtmgr_ble.c | 82 ++++++++++++++---------
 1 file changed, 50 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/a10cdd0f/libs/newtmgr/transport/ble/src/newtmgr_ble.c
----------------------------------------------------------------------
diff --git a/libs/newtmgr/transport/ble/src/newtmgr_ble.c b/libs/newtmgr/transport/ble/src/newtmgr_ble.c
index e618593..aff9eb2 100644
--- a/libs/newtmgr/transport/ble/src/newtmgr_ble.c
+++ b/libs/newtmgr/transport/ble/src/newtmgr_ble.c
@@ -33,15 +33,13 @@ struct nmgr_transport ble_nt;
 /* ble nmgr attr handle */
 uint16_t g_ble_nmgr_attr_handle;
 
-/* ble nmgr response buffer */
-char ble_nmgr_resp_buf[BLE_ATT_MTU_MAX];
-
 struct os_eventq *app_evq;
 /**
- * The vendor specific "newtmgr" service consists of one write no-rsp characteristic
- * for newtmgr requests
- *     o "write no-rsp": a single-byte characteristic that can always be read, but
- *       can only be written over an encrypted connection.
+ * The vendor specific "newtmgr" service consists of one write no-rsp
+ * characteristic for newtmgr requests: a single-byte characteristic that can
+ * only accepts write-without-response commands.  The contents of each write
+ * command contains an NMP request.  NMP responses are sent back in the form of
+ * unsolicited notifications from the same characteristic.
  */
 
 /* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */
@@ -90,31 +88,57 @@ gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle,
 
     switch (ctxt->op) {
         case BLE_GATT_ACCESS_OP_WRITE_CHR:
-            m_req = os_msys_get_pkthdr(ctxt->att->write.len, sizeof(conn_handle));
-            if (!m_req) {
-                goto err;
-            }
-            rc = os_mbuf_copyinto(m_req, OS_MBUF_PKTHDR(m_req)->omp_len,
-                                  ctxt->att->write.data, ctxt->att->write.len);
-            if (rc) {
-                goto err;
+            /* Try to reuse the BLE packet mbuf as the newtmgr request.  This
+             * requires a two-byte usrhdr to hold the BLE connection handle so
+             * that the newtmgr response can be sent to the correct peer.  If
+             * it is not possible to reuse the mbuf, then allocate a new one
+             * and copy the request contents.
+             */
+            if (OS_MBUF_USRHDR_LEN(ctxt->om) > sizeof (conn_handle)) {
+                /* Sufficient usrhdr space already present. */
+                m_req = ctxt->om;
+                ctxt->om = NULL;
+            } else if (OS_MBUF_LEADINGSPACE(ctxt->om) > sizeof (conn_handle)) {
+                /* Usrhdr isn't present, but there is enough leading space to
+                 * add one.
+                 */
+                m_req = ctxt->om;
+                ctxt->om = NULL;
+
+                m_req->om_pkthdr_len += sizeof (conn_handle);
+            } else {
+                /* The mbuf can't be reused.  Allocate a new one and perform a
+                 * copy.  Don't set ctxt->om to NULL; let the NimBLE host free
+                 * it.
+                 */
+                m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om),
+                                           sizeof (conn_handle));
+                if (!m_req) {
+                    return BLE_ATT_ERR_INSUFFICIENT_RES;
+                }
+                rc = os_mbuf_appendfrom(m_req, ctxt->om, 0,
+                                        OS_MBUF_PKTLEN(ctxt->om));
+                if (rc) {
+                    return BLE_ATT_ERR_INSUFFICIENT_RES;
+                }
             }
+
+            /* Write the connection handle to the newtmgr request usrhdr.  This
+             * is necessary so that we later know who to send the newtmgr
+             * response to.
+             */
             memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle));
 
             rc = nmgr_rx_req(&ble_nt, m_req);
-            return rc;
+            if (rc != 0) {
+                return BLE_ATT_ERR_UNLIKELY;
+            }
+            return 0;
 
         default:
             assert(0);
             return BLE_ATT_ERR_UNLIKELY;
     }
-
-    /* Unknown characteristic; the nimble stack should not have called this
-     * function.
-     */
-    assert(0);
-err:
-    return BLE_ATT_ERR_UNLIKELY;
 }
 
 /**
@@ -130,12 +154,10 @@ nmgr_ble_proc_mq_evt(struct os_event *ev)
 {
     struct os_mbuf *m_resp;
     uint16_t conn_handle;
-    uint16_t max_pktlen;
     int rc;
 
     rc = 0;
     switch (ev->ev_type) {
-
         case OS_EVENT_T_MQUEUE_DATA:
             if (ev->ev_arg != &ble_nmgr_mq) {
                 rc = -1;
@@ -148,16 +170,12 @@ nmgr_ble_proc_mq_evt(struct os_event *ev)
                     break;
                 }
                 memcpy(&conn_handle, OS_MBUF_USRHDR(m_resp),
-                       sizeof(conn_handle));
-                max_pktlen = min(OS_MBUF_PKTLEN(m_resp), sizeof(ble_nmgr_resp_buf));
-                rc = os_mbuf_copydata(m_resp, 0, max_pktlen, ble_nmgr_resp_buf);
-                assert(rc == 0);
-                rc = os_mbuf_free_chain(m_resp);
-                assert(rc == 0);
+                       sizeof (conn_handle));
                 ble_gattc_notify_custom(conn_handle, g_ble_nmgr_attr_handle,
-                                        ble_nmgr_resp_buf, max_pktlen);
+                                        &m_resp);
             }
             break;
+
         default:
             rc = -1;
             goto done;


[02/11] incubator-mynewt-core git commit: os - Rename os_mbuf_memcmp -> os_mbuf_cmpf.

Posted by cc...@apache.org.
os - Rename os_mbuf_memcmp -> os_mbuf_cmpf.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/491ef447
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/491ef447
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/491ef447

Branch: refs/heads/develop
Commit: 491ef447dcf478f758bab1fb2c0a70350800a6a2
Parents: 5c4b292
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Jul 21 12:29:31 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:01 2016 -0700

----------------------------------------------------------------------
 libs/os/include/os/os_mbuf.h |  5 +++--
 libs/os/src/os_mbuf.c        | 22 +++++++++++-----------
 2 files changed, 14 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/491ef447/libs/os/include/os/os_mbuf.h
----------------------------------------------------------------------
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
index 93e5ba4..f3c48ae 100644
--- a/libs/os/include/os/os_mbuf.h
+++ b/libs/os/include/os/os_mbuf.h
@@ -259,7 +259,8 @@ struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp,
 /* Duplicate a mbuf from the pool */
 struct os_mbuf *os_mbuf_dup(struct os_mbuf *m);
 
-struct os_mbuf * os_mbuf_off(const struct os_mbuf *om, int off, int *out_off);
+struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off,
+                            uint16_t *out_off);
 
 /* Copy data from an mbuf to a flat buffer. */
 int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst);
@@ -277,7 +278,7 @@ int os_mbuf_free(struct os_mbuf *mb);
 int os_mbuf_free_chain(struct os_mbuf *om);
 
 void os_mbuf_adj(struct os_mbuf *mp, int req_len);
-int os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data,
+int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data,
                    int len);
 int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1,
                  const struct os_mbuf *om2, uint16_t offset2,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/491ef447/libs/os/src/os_mbuf.c
----------------------------------------------------------------------
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
index 8306d16..eda58ef 100644
--- a/libs/os/src/os_mbuf.c
+++ b/libs/os/src/os_mbuf.c
@@ -526,8 +526,8 @@ os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src,
                    uint16_t src_off, uint16_t len)
 {
     const struct os_mbuf *src_cur_om;
+    uint16_t src_cur_off;
     uint16_t chunk_sz;
-    int src_cur_off;
     int rc;
 
     src_cur_om = os_mbuf_off(src, src_off, &src_cur_off);
@@ -616,7 +616,7 @@ err:
  *                              NULL if the specified offset is out of bounds.
  */
 struct os_mbuf *
-os_mbuf_off(const struct os_mbuf *om, int off, int *out_off)
+os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off)
 {
     struct os_mbuf *next;
     struct os_mbuf *cur;
@@ -783,14 +783,14 @@ os_mbuf_adj(struct os_mbuf *mp, int req_len)
  *
  * @return                      0 if both memory regions are identical;
  *                              A memcmp return code if there is a mismatch;
- *                              -1 if the mbuf is too short.
+ *                              INT_MAX if the mbuf is too short.
  */
 int
-os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
+os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len)
 {
-    int chunk_sz;
-    int data_off;
-    int om_off;
+    uint16_t chunk_sz;
+    uint16_t data_off;
+    uint16_t om_off;
     int rc;
 
     if (len <= 0) {
@@ -798,10 +798,10 @@ os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
     }
 
     data_off = 0;
-    om = os_mbuf_off((struct os_mbuf *)om, off, &om_off);
+    om = os_mbuf_off(om, off, &om_off);
     while (1) {
         if (om == NULL) {
-            return -1;
+            return INT_MAX;
         }
 
         chunk_sz = min(om->om_len - om_off, len - data_off);
@@ -821,7 +821,7 @@ os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
         om_off = 0;
 
         if (om == NULL) {
-            return -1;
+            return INT_MAX;
         }
     }
 }
@@ -1013,8 +1013,8 @@ os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len)
     struct os_mbuf *next;
     struct os_mbuf *cur;
     const uint8_t *sptr;
+    uint16_t cur_off;
     int copylen;
-    int cur_off;
     int rc;
 
     /* Find the mbuf,offset pair for the start of the destination. */


[10/11] incubator-mynewt-core git commit: Update sample NimBLE apps to use new mbuf API.

Posted by cc...@apache.org.
Update sample NimBLE apps to use new mbuf API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/d1877420
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/d1877420
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/d1877420

Branch: refs/heads/develop
Commit: d1877420ca1f22352f616c478b42dfe2c21946bd
Parents: a10cdd0
Author: Christopher Collins <cc...@apache.org>
Authored: Fri Jul 22 18:31:39 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 19:40:24 2016 -0700

----------------------------------------------------------------------
 apps/blecent/src/blecent.h  |  1 +
 apps/blecent/src/main.c     | 18 +++++------
 apps/blecent/src/misc.c     | 17 ++++++++++
 apps/blehci/src/main.c      | 33 +++++++++++--------
 apps/bleprph/src/gatt_svr.c | 69 +++++++++++++++++++---------------------
 apps/bletiny/src/bletiny.h  |  9 +++---
 apps/bletiny/src/cmd.c      | 48 ++++++++++++++++------------
 apps/bletiny/src/gatt_svr.c | 68 +++++++++++++++++++--------------------
 apps/bletiny/src/main.c     | 54 +++++++++++++++++--------------
 apps/bletiny/src/misc.c     | 17 ++++++++++
 10 files changed, 192 insertions(+), 142 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/blecent/src/blecent.h
----------------------------------------------------------------------
diff --git a/apps/blecent/src/blecent.h b/apps/blecent/src/blecent.h
index c2a2aee..4731eb9 100644
--- a/apps/blecent/src/blecent.h
+++ b/apps/blecent/src/blecent.h
@@ -51,6 +51,7 @@ void gatt_svr_init_cfg(struct ble_hs_cfg *cfg);
 
 /** Misc. */
 void print_bytes(const uint8_t *bytes, int len);
+void print_mbuf(const struct os_mbuf *om);
 char *addr_str(const void *addr);
 void print_uuid(const void *uuid128);
 void print_conn_desc(const struct ble_gap_conn_desc *desc);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/blecent/src/main.c
----------------------------------------------------------------------
diff --git a/apps/blecent/src/main.c b/apps/blecent/src/main.c
index f4f11f4..4c1ebe5 100755
--- a/apps/blecent/src/main.c
+++ b/apps/blecent/src/main.c
@@ -82,14 +82,14 @@ static int blecent_gap_event(struct ble_gap_event *event, void *arg);
 static int
 blecent_on_read(uint16_t conn_handle,
                 const struct ble_gatt_error *error,
-                const struct ble_gatt_attr *attr,
+                struct ble_gatt_attr *attr,
                 void *arg)
 {
     BLECENT_LOG(INFO, "Read complete; status=%d conn_handle=%d", error->status,
                 conn_handle);
     if (error->status == 0) {
         BLECENT_LOG(INFO, " attr_handle=%d value=", attr->handle);
-        print_bytes(attr->value, attr->value_len);
+        print_mbuf(attr->om);
     }
     BLECENT_LOG(INFO, "\n");
 
@@ -103,7 +103,7 @@ blecent_on_read(uint16_t conn_handle,
 static int
 blecent_on_write(uint16_t conn_handle,
                  const struct ble_gatt_error *error,
-                 const struct ble_gatt_attr *attr,
+                 struct ble_gatt_attr *attr,
                  void *arg)
 {
     BLECENT_LOG(INFO, "Write complete; status=%d conn_handle=%d "
@@ -120,7 +120,7 @@ blecent_on_write(uint16_t conn_handle,
 static int
 blecent_on_subscribe(uint16_t conn_handle,
                      const struct ble_gatt_error *error,
-                     const struct ble_gatt_attr *attr,
+                     struct ble_gatt_attr *attr,
                      void *arg)
 {
     BLECENT_LOG(INFO, "Subscribe complete; status=%d conn_handle=%d "
@@ -182,8 +182,8 @@ blecent_read_write_subscribe(const struct peer *peer)
 
     value[0] = 99;
     value[1] = 100;
-    rc = ble_gattc_write(peer->conn_handle, chr->chr.val_handle, 
-                         value, sizeof value, blecent_on_write, NULL);
+    rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle, 
+                              value, sizeof value, blecent_on_write, NULL);
     if (rc != 0) {
         BLECENT_LOG(ERROR, "Error: Failed to write characteristic; rc=%d\n",
                     rc);
@@ -205,8 +205,8 @@ blecent_read_write_subscribe(const struct peer *peer)
 
     value[0] = 1;
     value[1] = 0;
-    rc = ble_gattc_write(peer->conn_handle, dsc->dsc.handle,
-                         value, sizeof value, blecent_on_subscribe, NULL);
+    rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
+                              value, sizeof value, blecent_on_subscribe, NULL);
     if (rc != 0) {
         BLECENT_LOG(ERROR, "Error: Failed to subscribe to characteristic; "
                            "rc=%d\n", rc);
@@ -439,7 +439,7 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
                         "notification",
                     event->notify_rx.conn_handle,
                     event->notify_rx.attr_handle,
-                    event->notify_rx.attr_len);
+                    OS_MBUF_PKTLEN(event->notify_rx.om));
 
         /* Attribute data is contained in event->notify_rx.attr_data. */
         return 0;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/blecent/src/misc.c
----------------------------------------------------------------------
diff --git a/apps/blecent/src/misc.c b/apps/blecent/src/misc.c
index ea3f055..8366749 100644
--- a/apps/blecent/src/misc.c
+++ b/apps/blecent/src/misc.c
@@ -36,6 +36,23 @@ print_bytes(const uint8_t *bytes, int len)
     }
 }
 
+void
+print_mbuf(const struct os_mbuf *om)
+{
+    int colon;
+
+    colon = 0;
+    while (om != NULL) {
+        if (colon) {
+            BLECENT_LOG(DEBUG, ":");
+        } else {
+            colon = 1;
+        }
+        print_bytes(om->om_data, om->om_len);
+        om = SLIST_NEXT(om, om_next);
+    }
+}
+
 char *
 addr_str(const void *addr)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/blehci/src/main.c
----------------------------------------------------------------------
diff --git a/apps/blehci/src/main.c b/apps/blehci/src/main.c
index 09fb456..554572d 100755
--- a/apps/blehci/src/main.c
+++ b/apps/blehci/src/main.c
@@ -109,28 +109,35 @@ static struct {
 } hci;
 
 int
-ble_hs_rx_data(struct os_mbuf *om)
+ble_hs_rx_data(struct os_mbuf **om)
 {
     struct os_event *ev;
     os_sr_t sr;
+    int rc;
 
     ev = os_memblock_get(&g_hci_os_event_pool);
-    if (!ev) {
-        os_mbuf_free_chain(om);
-        return -1;
-    }
+    if (ev != NULL) {
+        ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_DATA;
+        ev->ev_arg = *om;
+        ev->ev_queued = 1;
 
-    ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_DATA;
-    ev->ev_arg = om;
-    ev->ev_queued = 1;
+        *om = NULL;
 
-    OS_ENTER_CRITICAL(sr);
-    STAILQ_INSERT_TAIL(&hci.rx_pkts, ev, ev_next);
-    OS_EXIT_CRITICAL(sr);
+        OS_ENTER_CRITICAL(sr);
+        STAILQ_INSERT_TAIL(&hci.rx_pkts, ev, ev_next);
+        OS_EXIT_CRITICAL(sr);
 
-    hal_uart_start_tx(HCI_UART);
+        hal_uart_start_tx(HCI_UART);
 
-    return 0;
+        rc = 0;
+    } else {
+        rc = -1;
+    }
+
+    /* Free the mbuf if we weren't able to enqueue it. */
+    os_mbuf_free_chain(om);
+
+    return rc;
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bleprph/src/gatt_svr.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/gatt_svr.c b/apps/bleprph/src/gatt_svr.c
index 7722df4..a3268d9 100644
--- a/apps/bleprph/src/gatt_svr.c
+++ b/apps/bleprph/src/gatt_svr.c
@@ -21,7 +21,6 @@
 #include <stdio.h>
 #include <string.h>
 #include "bsp/bsp.h"
-#include "console/console.h"
 #include "host/ble_hs.h"
 #include "bleprph.h"
 
@@ -120,20 +119,20 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
 };
 
 static int
-gatt_svr_chr_write(uint8_t op, struct ble_gatt_access_ctxt *ctxt,
-                   uint16_t min_len, uint16_t max_len, void *dst,
-                   uint16_t *len)
+gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
+                   void *dst, uint16_t *len)
 {
-    assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-    if (ctxt->att->write.len < min_len ||
-        ctxt->att->write.len > max_len) {
+    uint16_t om_len;
+    int rc;
 
+    om_len = OS_MBUF_PKTLEN(om);
+    if (om_len < min_len || om_len > max_len) {
         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
     }
 
-    memcpy(dst, ctxt->att->write.data, ctxt->att->write.len);
-    if (len != NULL) {
-        *len = ctxt->att->write.len;
+    rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
+    if (rc != 0) {
+        return BLE_ATT_ERR_UNLIKELY;
     }
 
     return 0;
@@ -162,44 +161,43 @@ gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
     switch (uuid16) {
     case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &gatt_svr_new_alert_cat;
-        ctxt->att->read.len = sizeof gatt_svr_new_alert_cat;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_cat,
+                            sizeof gatt_svr_new_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case GATT_SVR_CHR_NEW_ALERT:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 0,
+            rc = gatt_svr_chr_write(ctxt->om, 0,
                                     sizeof gatt_svr_new_alert_val,
                                     gatt_svr_new_alert_val,
                                     &gatt_svr_new_alert_val_len);
             return rc;
         } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
-            ctxt->att->read.data = (void *)&gatt_svr_new_alert_val;
-            ctxt->att->read.len = sizeof gatt_svr_new_alert_val;
-            return 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_val,
+                                sizeof gatt_svr_new_alert_val);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
         }
 
     case GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &gatt_svr_unr_alert_cat;
-        ctxt->att->read.len = sizeof gatt_svr_unr_alert_cat;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_cat,
+                            sizeof gatt_svr_unr_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case GATT_SVR_CHR_UNR_ALERT_STAT_UUID:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 2, 2,
-                                    &gatt_svr_unr_alert_stat,
+            rc = gatt_svr_chr_write(ctxt->om, 2, 2, &gatt_svr_unr_alert_stat,
                                     NULL);
+            return rc;
         } else {
-            ctxt->att->read.data = &gatt_svr_unr_alert_stat;
-            ctxt->att->read.len = sizeof gatt_svr_unr_alert_stat;
-            rc = 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_stat,
+                                sizeof gatt_svr_unr_alert_stat);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
         }
-        return rc;
 
     case GATT_SVR_CHR_ALERT_NOT_CTRL_PT:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 2, 2,
+            rc = gatt_svr_chr_write(ctxt->om, 2, 2,
                                     &gatt_svr_alert_not_ctrl_pt, NULL);
         } else {
             rc = BLE_ATT_ERR_UNLIKELY;
@@ -230,24 +228,21 @@ gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
     if (memcmp(uuid128, gatt_svr_chr_sec_test_rand_uuid, 16) == 0) {
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
 
-        /* Respond with a 32-bit random number.  Use the stack-provided buffer
-         * to hold the response data.
-         */
+        /* Respond with a 32-bit random number. */
         rand_num = rand();
-        memcpy(ctxt->att->read.buf, &rand_num, sizeof rand_num);
-        ctxt->att->read.len = sizeof rand_num;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
     }
 
     if (memcmp(uuid128, gatt_svr_chr_sec_test_static_uuid, 16) == 0) {
         switch (ctxt->op) {
         case BLE_GATT_ACCESS_OP_READ_CHR:
-            ctxt->att->read.data = &gatt_svr_sec_test_static_val;
-            ctxt->att->read.len = sizeof gatt_svr_sec_test_static_val;
-            return 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
+                                sizeof gatt_svr_sec_test_static_val);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
         case BLE_GATT_ACCESS_OP_WRITE_CHR:
-            rc = gatt_svr_chr_write(ctxt->op, ctxt,
+            rc = gatt_svr_chr_write(ctxt->om,
                                     sizeof gatt_svr_sec_test_static_val,
                                     sizeof gatt_svr_sec_test_static_val,
                                     &gatt_svr_sec_test_static_val, NULL);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bletiny/src/bletiny.h
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/bletiny.h b/apps/bletiny/src/bletiny.h
index 64bce88..44831be 100644
--- a/apps/bletiny/src/bletiny.h
+++ b/apps/bletiny/src/bletiny.h
@@ -139,13 +139,13 @@ int bletiny_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
 int bletiny_read_mult(uint16_t conn_handle, uint16_t *attr_handles,
                        int num_attr_handles);
 int bletiny_write(uint16_t conn_handle, uint16_t attr_handle,
-                  const void *value, uint16_t value_len);
+                  struct os_mbuf **om);
 int bletiny_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
-                         const void *value, uint16_t value_len);
+                         struct os_mbuf **om);
 int bletiny_write_long(uint16_t conn_handle, uint16_t attr_handle,
-                       const void *value, uint16_t value_len);
+                       struct os_mbuf **om);
 int bletiny_write_reliable(uint16_t conn_handle,
-                           const struct ble_gatt_attr *attrs, int num_attrs);
+                           struct ble_gatt_attr *attrs, int num_attrs);
 int bletiny_adv_start(uint8_t own_addr_type, uint8_t peer_addr_type,
                       const uint8_t *peer_addr, int32_t duration_ms,
                       const struct ble_gap_adv_params *params);
@@ -193,6 +193,7 @@ int gatt_svr_init(struct ble_hs_cfg *cfg);
 
 /** Misc. */
 void print_bytes(const uint8_t *bytes, int len);
+void print_mbuf(const struct os_mbuf *om);
 void print_addr(const void *addr);
 void print_uuid(const void *uuid128);
 int svc_is_empty(const struct bletiny_svc *svc);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bletiny/src/cmd.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/cmd.c b/apps/bletiny/src/cmd.c
index e05a081..4733076 100644
--- a/apps/bletiny/src/cmd.c
+++ b/apps/bletiny/src/cmd.c
@@ -24,6 +24,7 @@
 #include "shell/shell.h"
 
 #include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
 #include "host/ble_gap.h"
 #include "host/ble_hs_adv.h"
@@ -1770,12 +1771,10 @@ cmd_wl(int argc, char **argv)
  * $write                                                                    *
  *****************************************************************************/
 
-#define CMD_WRITE_MAX_ATTRS 16
-
 static int
 cmd_write(int argc, char **argv)
 {
-    static struct ble_gatt_attr attrs[CMD_WRITE_MAX_ATTRS];
+    struct ble_gatt_attr attrs[NIMBLE_OPT(GATT_WRITE_MAX_ATTRS)] = { { 0 } };
     uint16_t attr_handle;
     uint16_t conn_handle;
     int total_attr_len;
@@ -1784,6 +1783,7 @@ cmd_write(int argc, char **argv)
     int is_long;
     int no_rsp;
     int rc;
+    int i;
 
     conn_handle = parse_arg_uint16("conn", &rc);
     if (rc != 0) {
@@ -1811,7 +1811,8 @@ cmd_write(int argc, char **argv)
         if (rc == ENOENT) {
             break;
         } else if (rc != 0) {
-            return rc;
+            rc = -rc;
+            goto done;
         }
 
         rc = parse_arg_byte_stream("value", sizeof cmd_buf - total_attr_len,
@@ -1819,17 +1820,21 @@ cmd_write(int argc, char **argv)
         if (rc == ENOENT) {
             break;
         } else if (rc != 0) {
-            return rc;
+            goto done;
         }
 
-        if (num_attrs >= CMD_WRITE_MAX_ATTRS) {
-            return EINVAL;
+        if (num_attrs >= sizeof attrs / sizeof attrs[0]) {
+            rc = -EINVAL;
+            goto done;
         }
 
         attrs[num_attrs].handle = attr_handle;
         attrs[num_attrs].offset = 0;
-        attrs[num_attrs].value_len = attr_len;
-        attrs[num_attrs].value = cmd_buf + total_attr_len;
+        attrs[num_attrs].om = ble_hs_mbuf_from_flat(cmd_buf + total_attr_len,
+                                                    attr_len);
+        if (attrs[num_attrs].om == NULL) {
+            goto done;
+        }
 
         total_attr_len += attr_len;
         num_attrs++;
@@ -1837,31 +1842,34 @@ cmd_write(int argc, char **argv)
 
     if (no_rsp) {
         if (num_attrs != 1) {
-            return EINVAL;
+            rc = -EINVAL;
+            goto done;
         }
-        rc = bletiny_write_no_rsp(conn_handle, attrs[0].handle,
-                                  attrs[0].value, attrs[0].value_len);
+        rc = bletiny_write_no_rsp(conn_handle, attrs[0].handle, &attrs[0].om);
     } else if (is_long) {
         if (num_attrs != 1) {
-            return EINVAL;
+            rc = -EINVAL;
+            goto done;
         }
-        rc = bletiny_write_long(conn_handle, attrs[0].handle,
-                                attrs[0].value, attrs[0].value_len);
+        rc = bletiny_write_long(conn_handle, attrs[0].handle, &attrs[0].om);
     } else if (num_attrs > 1) {
         rc = bletiny_write_reliable(conn_handle, attrs, num_attrs);
     } else if (num_attrs == 1) {
-        rc = bletiny_write(conn_handle, attrs[0].handle,
-                           attrs[0].value, attrs[0].value_len);
+        rc = bletiny_write(conn_handle, attrs[0].handle, &attrs[0].om);
     } else {
-        return EINVAL;
+        rc = -EINVAL;
+    }
+
+done:
+    for (i = 0; i < sizeof attrs / sizeof attrs[0]; i++) {
+        os_mbuf_free_chain(attrs[i].om);
     }
 
     if (rc != 0) {
         console_printf("error writing characteristic; rc=%d\n", rc);
-        return rc;
     }
 
-    return 0;
+    return rc;
 }
 
 /*****************************************************************************

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bletiny/src/gatt_svr.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/gatt_svr.c b/apps/bletiny/src/gatt_svr.c
index 964cb25..d0c7a59 100644
--- a/apps/bletiny/src/gatt_svr.c
+++ b/apps/bletiny/src/gatt_svr.c
@@ -120,20 +120,20 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
 };
 
 static int
-gatt_svr_chr_write(uint8_t op, struct ble_gatt_access_ctxt *ctxt,
-                   uint16_t min_len, uint16_t max_len, void *dst,
-                   uint16_t *len)
+gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
+                   void *dst, uint16_t *len)
 {
-    assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR);
-    if (ctxt->att->write.len < min_len ||
-        ctxt->att->write.len > max_len) {
+    uint16_t om_len;
+    int rc;
 
+    om_len = OS_MBUF_PKTLEN(om);
+    if (om_len < min_len || om_len > max_len) {
         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
     }
 
-    memcpy(dst, ctxt->att->write.data, ctxt->att->write.len);
-    if (len != NULL) {
-        *len = ctxt->att->write.len;
+    rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
+    if (rc != 0) {
+        return BLE_ATT_ERR_UNLIKELY;
     }
 
     return 0;
@@ -162,44 +162,43 @@ gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
     switch (uuid16) {
     case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &gatt_svr_new_alert_cat;
-        ctxt->att->read.len = sizeof gatt_svr_new_alert_cat;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_cat,
+                            sizeof gatt_svr_new_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case GATT_SVR_CHR_NEW_ALERT:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 0,
+            rc = gatt_svr_chr_write(ctxt->om, 0,
                                     sizeof gatt_svr_new_alert_val,
                                     gatt_svr_new_alert_val,
                                     &gatt_svr_new_alert_val_len);
             return rc;
         } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
-            ctxt->att->read.data = (void *)&gatt_svr_new_alert_val;
-            ctxt->att->read.len = sizeof gatt_svr_new_alert_val;
-            return 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_val,
+                                sizeof gatt_svr_new_alert_val);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
         }
 
     case GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID:
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
-        ctxt->att->read.data = &gatt_svr_unr_alert_cat;
-        ctxt->att->read.len = sizeof gatt_svr_unr_alert_cat;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_cat,
+                            sizeof gatt_svr_unr_alert_cat);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
     case GATT_SVR_CHR_UNR_ALERT_STAT_UUID:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 2, 2,
-                                    &gatt_svr_unr_alert_stat,
+            rc = gatt_svr_chr_write(ctxt->om, 2, 2, &gatt_svr_unr_alert_stat,
                                     NULL);
+            return rc;
         } else {
-            ctxt->att->read.data = &gatt_svr_unr_alert_stat;
-            ctxt->att->read.len = sizeof gatt_svr_unr_alert_stat;
-            rc = 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_stat,
+                                sizeof gatt_svr_unr_alert_stat);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
         }
-        return rc;
 
     case GATT_SVR_CHR_ALERT_NOT_CTRL_PT:
         if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-            rc = gatt_svr_chr_write(ctxt->op, ctxt, 2, 2,
+            rc = gatt_svr_chr_write(ctxt->om, 2, 2,
                                     &gatt_svr_alert_not_ctrl_pt, NULL);
         } else {
             rc = BLE_ATT_ERR_UNLIKELY;
@@ -230,24 +229,21 @@ gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
     if (memcmp(uuid128, gatt_svr_chr_sec_test_rand_uuid, 16) == 0) {
         assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
 
-        /* Respond with a 32-bit random number.  Use the stack-provided buffer
-         * to hold the response data.
-         */
+        /* Respond with a 32-bit random number. */
         rand_num = rand();
-        memcpy(ctxt->att->read.buf, &rand_num, sizeof rand_num);
-        ctxt->att->read.len = sizeof rand_num;
-        return 0;
+        rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
     }
 
     if (memcmp(uuid128, gatt_svr_chr_sec_test_static_uuid, 16) == 0) {
         switch (ctxt->op) {
         case BLE_GATT_ACCESS_OP_READ_CHR:
-            ctxt->att->read.data = &gatt_svr_sec_test_static_val;
-            ctxt->att->read.len = sizeof gatt_svr_sec_test_static_val;
-            return 0;
+            rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
+                                sizeof gatt_svr_sec_test_static_val);
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
 
         case BLE_GATT_ACCESS_OP_WRITE_CHR:
-            rc = gatt_svr_chr_write(ctxt->op, ctxt,
+            rc = gatt_svr_chr_write(ctxt->om,
                                     sizeof gatt_svr_sec_test_static_val,
                                     sizeof gatt_svr_sec_test_static_val,
                                     &gatt_svr_sec_test_static_val, NULL);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bletiny/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/main.c b/apps/bletiny/src/main.c
index 9dd0774..3432b80 100755
--- a/apps/bletiny/src/main.c
+++ b/apps/bletiny/src/main.c
@@ -839,14 +839,14 @@ bletiny_on_disc_d(uint16_t conn_handle, const struct ble_gatt_error *error,
 
 static int
 bletiny_on_read(uint16_t conn_handle, const struct ble_gatt_error *error,
-                const struct ble_gatt_attr *attr, void *arg)
+                struct ble_gatt_attr *attr, void *arg)
 {
     switch (error->status) {
     case 0:
         console_printf("characteristic read; conn_handle=%d "
                        "attr_handle=%d len=%d value=", conn_handle,
-                       attr->handle, attr->value_len);
-        print_bytes(attr->value, attr->value_len);
+                       attr->handle, OS_MBUF_PKTLEN(attr->om));
+        print_mbuf(attr->om);
         console_printf("\n");
         break;
 
@@ -864,15 +864,12 @@ bletiny_on_read(uint16_t conn_handle, const struct ble_gatt_error *error,
 
 static int
 bletiny_on_write(uint16_t conn_handle, const struct ble_gatt_error *error,
-                 const struct ble_gatt_attr *attr, void *arg)
+                 struct ble_gatt_attr *attr, void *arg)
 {
     switch (error->status) {
     case 0:
         console_printf("characteristic write complete; conn_handle=%d "
-                       "attr_handle=%d len=%d value=", conn_handle,
-                       attr->handle, attr->value_len);
-        print_bytes(attr->value, attr->value_len);
-        console_printf("\n");
+                       "attr_handle=%d\n", conn_handle, attr->handle);
         break;
 
     default:
@@ -886,7 +883,7 @@ bletiny_on_write(uint16_t conn_handle, const struct ble_gatt_error *error,
 static int
 bletiny_on_write_reliable(uint16_t conn_handle,
                           const struct ble_gatt_error *error,
-                          const struct ble_gatt_attr *attrs, uint8_t num_attrs,
+                          struct ble_gatt_attr *attrs, uint8_t num_attrs,
                           void *arg)
 {
     int i;
@@ -898,8 +895,8 @@ bletiny_on_write_reliable(uint16_t conn_handle,
 
         for (i = 0; i < num_attrs; i++) {
             console_printf(" attr_handle=%d len=%d value=", attrs[i].handle,
-                           attrs[i].value_len);
-            print_bytes(attrs[i].value, attrs[i].value_len);
+                           OS_MBUF_PKTLEN(attrs[i].om));
+            print_mbuf(attrs[i].om);
         }
         console_printf("\n");
         break;
@@ -1005,9 +1002,9 @@ bletiny_gap_event(struct ble_gap_event *event, void *arg)
                        "len=%d data=",
                        event->notify_rx.attr_handle,
                        event->notify_rx.indication,
-                       event->notify_rx.attr_len);
+                       OS_MBUF_PKTLEN(event->notify_rx.om));
 
-        print_bytes(event->notify_rx.attr_data, event->notify_rx.attr_len);
+        print_mbuf(event->notify_rx.om);
         console_printf("\n");
         return 0;
 
@@ -1201,10 +1198,19 @@ bletiny_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
 int
 bletiny_read(uint16_t conn_handle, uint16_t attr_handle)
 {
+    struct os_mbuf *om;
     int rc;
 
     if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
-        rc = ble_att_svr_read_local(attr_handle, NULL, NULL);
+        rc = ble_att_svr_read_local(attr_handle, &om);
+        if (rc == 0) {
+            console_printf("read local; attr_handle=%d len=%d value=",
+                           attr_handle, OS_MBUF_PKTLEN(om));
+            print_mbuf(om);
+            console_printf("\n");
+
+            os_mbuf_free_chain(om);
+        }
     } else {
         rc = ble_gattc_read(conn_handle, attr_handle, bletiny_on_read, NULL);
     }
@@ -1243,15 +1249,14 @@ bletiny_read_mult(uint16_t conn_handle, uint16_t *attr_handles,
 }
 
 int
-bletiny_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
-              uint16_t value_len)
+bletiny_write(uint16_t conn_handle, uint16_t attr_handle, struct os_mbuf **om)
 {
     int rc;
 
     if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
-        rc = ble_att_svr_write_local(attr_handle, value, value_len);
+        rc = ble_att_svr_write_local(attr_handle, om);
     } else {
-        rc = ble_gattc_write(conn_handle, attr_handle, value, value_len,
+        rc = ble_gattc_write(conn_handle, attr_handle, om,
                              bletiny_on_write, NULL);
     }
 
@@ -1260,29 +1265,29 @@ bletiny_write(uint16_t conn_handle, uint16_t attr_handle, const void *value,
 
 int
 bletiny_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
-                     const void *value, uint16_t value_len)
+                     struct os_mbuf **om)
 {
     int rc;
 
-    rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, value, value_len);
+    rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om);
 
     return rc;
 }
 
 int
 bletiny_write_long(uint16_t conn_handle, uint16_t attr_handle,
-                   const void *value, uint16_t value_len)
+                   struct os_mbuf **om)
 {
     int rc;
 
-    rc = ble_gattc_write_long(conn_handle, attr_handle, value, value_len,
+    rc = ble_gattc_write_long(conn_handle, attr_handle, om,
                               bletiny_on_write, NULL);
     return rc;
 }
 
 int
 bletiny_write_reliable(uint16_t conn_handle,
-                       const struct ble_gatt_attr *attrs,
+                       struct ble_gatt_attr *attrs,
                        int num_attrs)
 {
     int rc;
@@ -1561,6 +1566,9 @@ bletiny_task_handler(void *arg)
     rc = ble_hs_start();
     assert(rc == 0);
 
+    rc = ble_hs_id_set_rnd(((uint8_t[6]){0x79,0xe4,0x59,0x8f,0xbc,0xf2}));
+    assert(rc == 0);
+
     while (1) {
         ev = os_eventq_get(&bletiny_evq);
         switch (ev->ev_type) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d1877420/apps/bletiny/src/misc.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/misc.c b/apps/bletiny/src/misc.c
index 0df5dee..a7f2188 100644
--- a/apps/bletiny/src/misc.c
+++ b/apps/bletiny/src/misc.c
@@ -37,6 +37,23 @@ print_bytes(const uint8_t *bytes, int len)
 }
 
 void
+print_mbuf(const struct os_mbuf *om)
+{
+    int colon;
+
+    colon = 0;
+    while (om != NULL) {
+        if (colon) {
+            console_printf(":");
+        } else {
+            colon = 1;
+        }
+        print_bytes(om->om_data, om->om_len);
+        om = SLIST_NEXT(om, om_next);
+    }
+}
+
+void
 print_addr(const void *addr)
 {
     const uint8_t *u8p;


[11/11] incubator-mynewt-core git commit: BLE Host - Small doxygen update.

Posted by cc...@apache.org.
BLE Host - Small doxygen update.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/beab6f23
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/beab6f23
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/beab6f23

Branch: refs/heads/develop
Commit: beab6f23b48c47b115c5ff1cd237d441ebf2122c
Parents: d187742
Author: Christopher Collins <cc...@apache.org>
Authored: Fri Jul 22 19:34:03 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 19:40:24 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_att.h  | 74 ----------------------------
 net/nimble/host/include/host/ble_gatt.h | 51 +++++++++++--------
 net/nimble/host/src/ble_hs_mbuf.c       | 27 ++++++++++
 net/nimble/host/src/ble_uuid.c          |  2 +-
 4 files changed, 59 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/beab6f23/net/nimble/host/include/host/ble_att.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_att.h b/net/nimble/host/include/host/ble_att.h
index 3bccea5..e5eb820 100644
--- a/net/nimble/host/include/host/ble_att.h
+++ b/net/nimble/host/include/host/ble_att.h
@@ -94,80 +94,6 @@ struct os_mbuf;
 #define BLE_ATT_MTU_MAX                 240
 #define BLE_ATT_MTU_PREFERRED_DFLT      240
 
-/**
- * Context for an access to an ATT attribute.  When a client reads or writes a
- * locally registered attribute, an instance of this struct gets passed to the
- * access callback.
- */
-struct ble_att_svr_access_ctxt {
-    /**
-     * The ATT operation being performed dictates which field in this union is
-     * valid.  If a read is being performed, the read field is valid.
-     * Otherwise, a write is being performed, in which case the write field is
-     * valid.
-     */
-    union {
-        /** Context for reads of ATT attributes. */
-        struct {
-            /**
-             * (stack --> app)
-             * The offset within the attribute that the client is reading from.
-             */
-            uint16_t offset;
-
-            /**
-             * (stack --> app)
-             * Maximum number of data bytes the stack can send in the read
-             * response.  This is based on the connection's ATT MTU.
-             */
-            uint16_t max_data_len;
-
-            /**
-             * (stack --> app)
-             * A buffer that the app can use to write the characteristic
-             * response value to.  This buffer can hold up to max_data_len
-             * bytes.
-             */
-            uint8_t *buf;
-
-            /**
-             * (app --> stack)
-             * App points this at the characteristic data to respond with.
-             * Initially this points to "buf".
-             */
-            const void *data;
-
-            /**
-             * (app --> stack)
-             * App fills this with the number of data bytes contained in
-             * characteristic response.
-             */
-            uint16_t len;
-        } read;
-
-        /** Context for writes of ATT attributes. */
-        struct {
-            /**
-             * (stack --> app)
-             * The data that the peer is writing to the characteristic.
-             */
-            const void *data;
-
-            /**
-             * (stack --> app)
-             * The offset within the attribute that the client is writing to.
-             */
-            uint16_t offset;
-
-            /**
-             * (stack --> app)
-             * The number of bytes of characteristic data being written.
-             */
-            int len;
-        } write;
-    };
-};
-
 int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om);
 int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf **om);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/beab6f23/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 3695401..31a8427 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -104,10 +104,22 @@ typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle,
                                  const struct ble_gatt_error *error,
                                  const struct ble_gatt_svc *service,
                                  void *arg);
+
+/**
+ * The host will free the attribute mbuf automatically after the callback is
+ * executed.  The application can take ownership of the mbuf and prevent it
+ * from being freed by assigning NULL to attr->om.
+ */
 typedef int ble_gatt_attr_fn(uint16_t conn_handle,
                              const struct ble_gatt_error *error,
                              struct ble_gatt_attr *attr,
                              void *arg);
+
+/**
+ * The host will free the attribute mbufs automatically after the callback is
+ * executed.  The application can take ownership of the mbufs and prevent them
+ * from being freed by assigning NULL to each attribute's om field.
+ */
 typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle,
                                       const struct ble_gatt_error *error,
                                       struct ble_gatt_attr *attrs,
@@ -245,6 +257,23 @@ struct ble_gatt_svc_def {
     const struct ble_gatt_chr_def *characteristics;
 };
 
+struct ble_gatt_dsc_def {
+    /**
+     * The first element in a uint8_t[16]; use the BLE_UUID16 macro for 16-bit
+     * UUIDs; NULL if there are no more descriptors in the characteristic.
+     */
+    uint8_t *uuid128;
+
+    /** Specifies the set of permitted operations for this descriptor. */
+    uint8_t att_flags;
+
+    /** Callback that gets executed when the descriptor is read or written. */
+    ble_gatt_access_fn *access_cb;
+
+    /** Optional argument for callback. */
+    void *arg;
+};
+
 /**
  * Context for an access to a GATT characteristic or descriptor.  When a client
  * reads or writes a locally registered characteristic or descriptor, an
@@ -267,8 +296,8 @@ struct ble_gatt_access_ctxt {
      *       characteristic or descriptor being read.
      *     o For writes: This is already populated with the value being written
      *       by the peer.  If the application wishes to retain this mbuf for
-     *       later use, it must set this pointer to NULL to prevent the stack
-     *       from freeing it.
+     *       later use, the access callback must set this pointer to NULL to
+     *       prevent the stack from freeing it.
      */
     struct os_mbuf *om;
 
@@ -293,23 +322,6 @@ struct ble_gatt_access_ctxt {
     };
 };
 
-struct ble_gatt_dsc_def {
-    /**
-     * The first element in a uint8_t[16]; use the BLE_UUID16 macro for 16-bit
-     * UUIDs; NULL if there are no more descriptors in the characteristic.
-     */
-    uint8_t *uuid128;
-
-    /** Specifies the set of permitted operations for this descriptor. */
-    uint8_t att_flags;
-
-    /** Callback that gets executed when the descriptor is read or written. */
-    ble_gatt_access_fn *access_cb;
-
-    /** Optional argument for callback. */
-    void *arg;
-};
-
 /**
  * Context passed to the registration callback; represents the GATT service,
  * characteristic, or descriptor being registered.
@@ -415,7 +427,6 @@ struct ble_gatt_resources {
     uint16_t attrs;
 };
 
-struct ble_gatt_register_ctxt;
 typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt,
                                   void *arg);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/beab6f23/net/nimble/host/src/ble_hs_mbuf.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_mbuf.c b/net/nimble/host/src/ble_hs_mbuf.c
index 7b8f47f..870c88b 100644
--- a/net/nimble/host/src/ble_hs_mbuf.c
+++ b/net/nimble/host/src/ble_hs_mbuf.c
@@ -105,6 +105,16 @@ ble_hs_mbuf_att_pkt(void)
                                 BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
 }
 
+/**
+ * Allocates a an mbuf and fills it with the contents of the specified flat
+ * buffer.
+ *
+ * @param buf                   The flat buffer to copy from.
+ * @param len                   The length of the flat buffer.
+ *
+ * @return                      A newly-allocated mbuf on success;
+ *                              NULL on memory exhaustion.
+ */
 struct os_mbuf *
 ble_hs_mbuf_from_flat(const void *buf, uint16_t len)
 {
@@ -125,6 +135,23 @@ ble_hs_mbuf_from_flat(const void *buf, uint16_t len)
     return om;
 }
 
+/**
+ * Copies the contents of an mbuf into the specified flat buffer.  If the flat
+ * buffer is too small to contain the mbuf's contents, it is filled to capacity
+ * and BLE_HS_EMSGSIZE is returned.
+ *
+ * @param om                    The mbuf to copy from.
+ * @param flat                  The destination flat buffer.
+ * @param max_len               The size of the flat buffer.
+ * @param out_copy_len          The number of bytes actually copied gets
+ *                                  written here.
+ *
+ * @return                      0 on success;
+ *                              BLE_HS_EMSGSIZE if the flat buffer is too small
+ *                                  to contain the mbuf's contents;
+ *                              A BLE host core return code on unexpected
+ *                                  error.
+ */
 int
 ble_hs_mbuf_to_flat(const struct os_mbuf *om, void *flat, uint16_t max_len,
                     uint16_t *out_copy_len)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/beab6f23/net/nimble/host/src/ble_uuid.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_uuid.c b/net/nimble/host/src/ble_uuid.c
index 89a9bf4..805cf49 100644
--- a/net/nimble/host/src/ble_uuid.c
+++ b/net/nimble/host/src/ble_uuid.c
@@ -37,7 +37,7 @@ static uint8_t ble_uuid_base[16] = {
  * @param uuid128                   The 128-bit UUID to attempt to convert.
  *                                      This must point to 16 contiguous bytes.
  *
- * @return                          Positive 16-bit unsigned integer on
+ * @return                          A positive 16-bit unsigned integer on
  *                                      success;
  *                                  0 if the UUID cannot be represented in 16
  *                                      bits.


[05/11] incubator-mynewt-core git commit: testutil - Allow post-test callback per suite.

Posted by cc...@apache.org.
testutil - Allow post-test callback per suite.

/**
 * Configures a callback that gets executed at the end of each test case
 * in the current suite.  This is useful when there are some checks
 * that should be performed at the end of each test (e.g., verify no
 * memory leaks).  This callback is cleared when the current suite
 * completes.
 *
 * @param cb                    The callback to execute at the end of
 *                                  each test case.
 * @param cb_arg                An optional argument that gets passed to
 *                                  the callback.
 */
void
tu_suite_set_post_test_cb(tu_post_test_fn_t *cb, void *cb_arg)


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/6c457ca5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/6c457ca5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/6c457ca5

Branch: refs/heads/develop
Commit: 6c457ca51e3fe156fe585dd96ba0d8180715dc79
Parents: 491ef44
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Jul 21 12:32:59 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Fri Jul 22 18:34:01 2016 -0700

----------------------------------------------------------------------
 libs/testutil/include/testutil/testutil.h |  8 +++++++-
 libs/testutil/src/case.c                  | 10 ++++++++++
 libs/testutil/src/suite.c                 | 24 ++++++++++++++++++++++++
 libs/testutil/src/testutil_priv.h         |  5 +++++
 4 files changed, 46 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6c457ca5/libs/testutil/include/testutil/testutil.h
----------------------------------------------------------------------
diff --git a/libs/testutil/include/testutil/testutil.h b/libs/testutil/include/testutil/testutil.h
index da3f618..9c6192a 100644
--- a/libs/testutil/include/testutil/testutil.h
+++ b/libs/testutil/include/testutil/testutil.h
@@ -57,6 +57,9 @@ extern const char *tu_suite_name;
 extern const char *tu_case_name;
 extern int tu_first_idx;
 
+typedef void tu_post_test_fn_t(void *arg);
+
+void tu_suite_set_post_test_cb(tu_post_test_fn_t *cb, void *cb_arg);
 int tu_parse_args(int argc, char **argv);
 int tu_init(void);
 void tu_restart(void);
@@ -65,6 +68,7 @@ void tu_restart(void);
  * Private declarations                                                      *
  *****************************************************************************/
 
+void tu_suite_complete(void);
 void tu_suite_init(const char *name);
 
 void tu_case_init(const char *name);
@@ -74,7 +78,7 @@ void tu_case_fail_assert(int fatal, const char *file, int line,
 void tu_case_write_pass_auto(void);
 void tu_case_pass_manual(const char *file, int line,
                          const char *format, ...);
-
+void tu_case_post_test(void);
 
 extern int tu_any_failed;
 extern int tu_suite_failed;
@@ -91,6 +95,7 @@ extern jmp_buf tu_case_jb;
     {                                                                         \
         tu_suite_init(#suite_name);                                           \
         TEST_SUITE_##suite_name();                                            \
+        tu_suite_complete();                                                  \
                                                                               \
         return tu_suite_failed;                                               \
     }                                                                         \
@@ -113,6 +118,7 @@ extern jmp_buf tu_case_jb;
                                                                               \
             if (setjmp(tu_case_jb) == 0) {                                    \
                 TEST_CASE_##case_name();                                      \
+                tu_case_post_test();                                          \
                 tu_case_write_pass_auto();                                    \
             }                                                                 \
         }                                                                     \

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6c457ca5/libs/testutil/src/case.c
----------------------------------------------------------------------
diff --git a/libs/testutil/src/case.c b/libs/testutil/src/case.c
index bea6efa..614b142 100644
--- a/libs/testutil/src/case.c
+++ b/libs/testutil/src/case.c
@@ -30,6 +30,8 @@ int tu_case_failed;
 int tu_case_idx;
 
 const char *tu_case_name;
+tu_post_test_fn_t *tu_case_post_test_cb;
+void *tu_case_post_test_cb_arg;
 
 #define TU_CASE_BUF_SZ      1024
 
@@ -101,6 +103,14 @@ tu_case_complete(void)
     tu_case_idx++;
 }
 
+void
+tu_case_post_test(void)
+{
+    if (tu_case_post_test_cb != NULL) {
+        tu_case_post_test_cb(tu_case_post_test_cb_arg);
+    }
+}
+
 static void
 tu_case_write_fail_buf(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6c457ca5/libs/testutil/src/suite.c
----------------------------------------------------------------------
diff --git a/libs/testutil/src/suite.c b/libs/testutil/src/suite.c
index 5c2e5cb..93ca639 100644
--- a/libs/testutil/src/suite.c
+++ b/libs/testutil/src/suite.c
@@ -30,6 +30,30 @@ tu_suite_set_name(const char *name)
     tu_suite_name = name;
 }
 
+/**
+ * Configures a callback that gets executed at the end of each test case in the
+ * current suite.  This is useful when there are some checks that should be
+ * performed at the end of each test (e.g., verify no memory leaks).  This
+ * callback is cleared when the current suite completes.
+ *
+ * @param cb                    The callback to execute at the end of each test
+ *                                  case.
+ * @param cb_arg                An optional argument that gets passed to the
+ *                                  callback.
+ */
+void
+tu_suite_set_post_test_cb(tu_post_test_fn_t *cb, void *cb_arg)
+{
+    tu_case_post_test_cb = cb;
+    tu_case_post_test_cb_arg = cb_arg;
+}
+
+void
+tu_suite_complete(void)
+{
+    tu_suite_set_post_test_cb(NULL, NULL);
+}
+
 void
 tu_suite_init(const char *name)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6c457ca5/libs/testutil/src/testutil_priv.h
----------------------------------------------------------------------
diff --git a/libs/testutil/src/testutil_priv.h b/libs/testutil/src/testutil_priv.h
index 0047874..3f8cb2d 100644
--- a/libs/testutil/src/testutil_priv.h
+++ b/libs/testutil/src/testutil_priv.h
@@ -23,7 +23,12 @@
 #include <stddef.h>
 #include <inttypes.h>
 
+#include "testutil/testutil.h"
+
 void tu_arch_restart(void);
 void tu_case_abort(void);
 
+extern tu_post_test_fn_t *tu_case_post_test_cb;
+extern void *tu_case_post_test_cb_arg;
+
 #endif