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 2015/12/09 03:42:56 UTC

[2/3] incubator-mynewt-larva git commit: ATT read by group type; fix bugs.

ATT read by group type; fix bugs.


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

Branch: refs/heads/master
Commit: c1ac77ce1231b259ea0283745fe145f83143d4a5
Parents: 984a4b4
Author: Christopher Collins <cc...@gmail.com>
Authored: Tue Dec 8 18:37:57 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Tue Dec 8 18:42:06 2015 -0800

----------------------------------------------------------------------
 compiler/arm-none-eabi-m4/compiler.yml      |   2 +-
 net/nimble/host/include/host/ble_att.h      |  63 +++--
 net/nimble/host/src/ble_att.c               |  21 ++
 net/nimble/host/src/ble_att_clt.c           | 107 ++++----
 net/nimble/host/src/ble_att_cmd.h           |   2 +
 net/nimble/host/src/ble_att_priv.h          |   4 +
 net/nimble/host/src/ble_att_svr.c           | 301 ++++++++++++++++++++++-
 net/nimble/host/src/ble_gatt.c              |   3 -
 net/nimble/host/src/ble_hs.c                |   2 +-
 net/nimble/host/src/ble_hs_uuid.c           |   2 +-
 net/nimble/host/src/ble_l2cap.c             |   4 +-
 net/nimble/host/src/host_hci.c              |  21 +-
 net/nimble/host/src/test/ble_hs_test_util.c |   3 +-
 net/nimble/host/src/test/ble_l2cap_test.c   |   2 +-
 14 files changed, 446 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/compiler/arm-none-eabi-m4/compiler.yml
----------------------------------------------------------------------
diff --git a/compiler/arm-none-eabi-m4/compiler.yml b/compiler/arm-none-eabi-m4/compiler.yml
index 8cde544..29a9bcf 100644
--- a/compiler/arm-none-eabi-m4/compiler.yml
+++ b/compiler/arm-none-eabi-m4/compiler.yml
@@ -24,7 +24,7 @@ compiler.path.objcopy: arm-none-eabi-objcopy
 
 compiler.flags.default: -mcpu=cortex-m4 -mthumb-interwork -mthumb -Wall -Werror -fno-exceptions
 compiler.flags.optimized: [compiler.flags.default, -Os -ggdb] 
-compiler.flags.debug: [compiler.flags.default, -O1 -ggdb]
+compiler.flags.debug: [compiler.flags.default, -O0 -ggdb]
 
 compiler.ld.flags: -static -lgcc 
 compiler.ld.resolve_circular_deps: true

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 18ee5cd..f8375d5 100644
--- a/net/nimble/host/include/host/ble_att.h
+++ b/net/nimble/host/include/host/ble_att.h
@@ -1,21 +1,42 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef H_BLE_ATT_
 #define H_BLE_ATT_
 
-#define BLE_ATT_OP_ERROR_RSP             0x01
-#define BLE_ATT_OP_MTU_REQ               0x02
-#define BLE_ATT_OP_MTU_RSP               0x03
-#define BLE_ATT_OP_FIND_INFO_REQ         0x04
-#define BLE_ATT_OP_FIND_INFO_RSP         0x05
-#define BLE_ATT_OP_FIND_TYPE_VALUE_REQ   0x06
-#define BLE_ATT_OP_FIND_TYPE_VALUE_RSP   0x07
-#define BLE_ATT_OP_READ_TYPE_REQ         0x08
-#define BLE_ATT_OP_READ_TYPE_RSP         0x09
-#define BLE_ATT_OP_READ_REQ              0x0a
-#define BLE_ATT_OP_READ_RSP              0x0b
-#define BLE_ATT_OP_READ_GROUP_TYPE_REQ   0x10
-#define BLE_ATT_OP_READ_GROUP_TYPE_RSP   0x11
-#define BLE_ATT_OP_WRITE_REQ             0x12
-#define BLE_ATT_OP_WRITE_RSP             0x13
+#define BLE_ATT_UUID_PRIMARY_SERVICE        0x2800
+#define BLE_ATT_UUID_SECONDARY_SERVICE      0x2801
+#define BLE_ATT_UUID_INCLUDE                0x2802
+#define BLE_ATT_UUID_CHARACTERISTIC         0x2803
+
+#define BLE_ATT_OP_ERROR_RSP                0x01
+#define BLE_ATT_OP_MTU_REQ                  0x02
+#define BLE_ATT_OP_MTU_RSP                  0x03
+#define BLE_ATT_OP_FIND_INFO_REQ            0x04
+#define BLE_ATT_OP_FIND_INFO_RSP            0x05
+#define BLE_ATT_OP_FIND_TYPE_VALUE_REQ      0x06
+#define BLE_ATT_OP_FIND_TYPE_VALUE_RSP      0x07
+#define BLE_ATT_OP_READ_TYPE_REQ            0x08
+#define BLE_ATT_OP_READ_TYPE_RSP            0x09
+#define BLE_ATT_OP_READ_REQ                 0x0a
+#define BLE_ATT_OP_READ_RSP                 0x0b
+#define BLE_ATT_OP_READ_GROUP_TYPE_REQ      0x10
+#define BLE_ATT_OP_READ_GROUP_TYPE_RSP      0x11
+#define BLE_ATT_OP_WRITE_REQ                0x12
+#define BLE_ATT_OP_WRITE_RSP                0x13
 
 union ble_att_svr_handle_arg {
     struct {
@@ -29,12 +50,12 @@ union ble_att_svr_handle_arg {
     } aha_write;
 };
 
-#define HA_FLAG_PERM_READ            (1 << 0)
-#define HA_FLAG_PERM_WRITE           (1 << 1) 
-#define HA_FLAG_PERM_RW              (1 << 2)
-#define HA_FLAG_ENC_REQ              (1 << 3)
-#define HA_FLAG_AUTHENTICATION_REQ   (1 << 4)
-#define HA_FLAG_AUTHORIZATION_REQ    (1 << 5)
+#define HA_FLAG_PERM_READ                   (1 << 0)
+#define HA_FLAG_PERM_WRITE                  (1 << 1)
+#define HA_FLAG_PERM_RW                     (1 << 2)
+#define HA_FLAG_ENC_REQ                     (1 << 3)
+#define HA_FLAG_AUTHENTICATION_REQ          (1 << 4)
+#define HA_FLAG_AUTHORIZATION_REQ           (1 << 5)
 
 struct ble_att_svr_entry;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 7ef6424..1398d39 100644
--- a/net/nimble/host/src/ble_att.c
+++ b/net/nimble/host/src/ble_att.c
@@ -16,6 +16,7 @@
 
 #include <stddef.h>
 #include <errno.h>
+#include "host/ble_hs.h"
 #include "ble_l2cap.h"
 #include "ble_att_cmd.h"
 #include "ble_att_priv.h"
@@ -41,6 +42,7 @@ static struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = {
     { BLE_ATT_OP_READ_TYPE_RSP,        ble_att_clt_rx_read_type },
     { BLE_ATT_OP_READ_REQ,             ble_att_svr_rx_read },
     { BLE_ATT_OP_READ_RSP,             ble_att_clt_rx_read },
+    { BLE_ATT_OP_READ_GROUP_TYPE_REQ,  ble_att_svr_rx_read_group_type },
     { BLE_ATT_OP_READ_GROUP_TYPE_RSP,  ble_att_clt_rx_read_group_type },
     { BLE_ATT_OP_WRITE_REQ,            ble_att_svr_rx_write },
 };
@@ -121,3 +123,22 @@ ble_att_create_chan(void)
 
     return chan;
 }
+
+/**
+ * Allocates an mbuf for use as an ATT request or response.
+ */
+struct os_mbuf *
+ble_att_get_pkthdr(void)
+{
+    struct os_mbuf *om;
+
+    om = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    /* Make room in the buffer for various headers.  XXX Check this number. */
+    om->om_data += 8;
+
+    return om;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 e78b337..ae90413 100644
--- a/net/nimble/host/src/ble_att_clt.c
+++ b/net/nimble/host/src/ble_att_clt.c
@@ -37,15 +37,12 @@ ble_att_clt_prep_req(struct ble_hs_conn *conn, struct ble_l2cap_chan **chan,
     *chan = ble_hs_conn_chan_find(conn, BLE_L2CAP_CID_ATT);
     assert(*chan != NULL);
 
-    *txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    *txom = ble_att_get_pkthdr();
     if (*txom == NULL) {
         rc = ENOMEM;
         goto err;
     }
 
-    /* Make room in the buffer for various headers.  XXX Check this number. */
-    (*txom)->om_data += 8;
-
     buf = os_mbuf_extend(*txom, initial_sz);
     if (buf == NULL) {
         rc = ENOMEM;
@@ -358,54 +355,6 @@ done:
 }
 
 int
-ble_att_clt_tx_read_group_type(struct ble_hs_conn *conn,
-                               struct ble_att_read_group_type_req *req,
-                               void *uuid128)
-{
-    struct ble_l2cap_chan *chan;
-    struct os_mbuf *txom;
-    int rc;
-
-    txom = NULL;
-
-    if (req->bagq_start_handle == 0 ||
-        req->bagq_start_handle > req->bagq_end_handle) {
-
-        rc = EINVAL;
-        goto err;
-    }
-
-    rc = ble_att_clt_prep_req(conn, &chan, &txom,
-                              BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ);
-    if (rc != 0) {
-        goto err;
-    }
-
-    rc = ble_att_read_group_type_req_write(txom->om_data, txom->om_len,
-                                              req);
-    if (rc != 0) {
-        goto err;
-    }
-
-    rc = ble_hs_uuid_append(txom, uuid128);
-    if (rc != 0) {
-        goto err;
-    }
-
-    rc = ble_l2cap_tx(conn, chan, txom);
-    txom = NULL;
-    if (rc != 0) {
-        goto err;
-    }
-
-    return 0;
-
-err:
-    os_mbuf_free_chain(txom);
-    return rc;
-}
-
-int
 ble_att_clt_tx_read(struct ble_hs_conn *conn, struct ble_att_read_req *req)
 {
     struct ble_l2cap_chan *chan;
@@ -475,10 +424,62 @@ done:
     return rc;
 }
 
+int
+ble_att_clt_tx_read_group_type(struct ble_hs_conn *conn,
+                               struct ble_att_read_group_type_req *req,
+                               void *uuid128)
+{
+    struct ble_l2cap_chan *chan;
+    struct os_mbuf *txom;
+    int rc;
+
+    txom = NULL;
+
+    if (req->bagq_start_handle == 0 ||
+        req->bagq_start_handle > req->bagq_end_handle) {
+
+        rc = EINVAL;
+        goto err;
+    }
+
+    rc = ble_att_clt_prep_req(conn, &chan, &txom,
+                              BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_att_read_group_type_req_write(txom->om_data, txom->om_len,
+                                              req);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_hs_uuid_append(txom, uuid128);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_l2cap_tx(conn, chan, txom);
+    txom = NULL;
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    os_mbuf_free_chain(txom);
+    return rc;
+}
+
 static int
 ble_att_clt_parse_group_attribute_data(struct os_mbuf **om, int data_len,
-                                 struct ble_att_clt_adata *adata)
+                                       struct ble_att_clt_adata *adata)
 {
+    if (data_len < BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 1) {
+        return EMSGSIZE;
+    }
+
     *om = os_mbuf_pullup(*om, data_len);
     if (*om == NULL) {
         return ENOMEM;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/net/nimble/host/src/ble_att_cmd.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_att_cmd.h b/net/nimble/host/src/ble_att_cmd.h
index cd757d6..499aebf 100644
--- a/net/nimble/host/src/ble_att_cmd.h
+++ b/net/nimble/host/src/ble_att_cmd.h
@@ -175,6 +175,8 @@ struct ble_att_read_group_type_rsp {
 };
 
 #define BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ   4
+#define BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16     6
+#define BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128    20
 
 /**
  * | Parameter                          | Size (octets)     |

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 f8d7539..b8bcec2 100644
--- a/net/nimble/host/src/ble_att_priv.h
+++ b/net/nimble/host/src/ble_att_priv.h
@@ -72,6 +72,7 @@ SLIST_HEAD(ble_att_clt_entry_list, ble_att_clt_entry);
 /*** @gen */
 struct ble_l2cap_chan *ble_att_create_chan(void);
 void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
+struct os_mbuf *ble_att_get_pkthdr(void);
 
 /*** @svr */
 int ble_att_svr_rx_mtu(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
@@ -85,6 +86,9 @@ int ble_att_svr_rx_find_type_value(struct ble_hs_conn *conn,
 int ble_att_svr_rx_read_type(struct ble_hs_conn *conn,
                              struct ble_l2cap_chan *chan,
                              struct os_mbuf **rxom);
+int ble_att_svr_rx_read_group_type(struct ble_hs_conn *conn,
+                                   struct ble_l2cap_chan *chan,
+                                   struct os_mbuf **rxom);
 int ble_att_svr_rx_read(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
                         struct os_mbuf **rxom);
 int ble_att_svr_rx_write(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 611c0e9..7b688d3 100644
--- a/net/nimble/host/src/ble_att_svr.c
+++ b/net/nimble/host/src/ble_att_svr.c
@@ -273,7 +273,7 @@ ble_att_svr_tx_error_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     void *dst;
     int rc;
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -318,7 +318,7 @@ ble_att_svr_tx_mtu_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     assert(op == BLE_ATT_OP_MTU_REQ || op == BLE_ATT_OP_MTU_RSP);
     assert(mtu >= BLE_ATT_MTU_DFLT);
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -528,7 +528,7 @@ ble_att_svr_rx_find_info(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
         goto err;
     }
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -815,7 +815,7 @@ ble_att_svr_rx_find_type_value(struct ble_hs_conn *conn,
         goto err;
     }
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -868,7 +868,7 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn,
     int attr_len;
     int rc;
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -1017,7 +1017,7 @@ ble_att_svr_tx_read_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     uint8_t op;
     int rc;
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;
@@ -1109,13 +1109,300 @@ err:
 }
 
 static int
+ble_att_svr_is_valid_group_type(uint8_t *uuid128)
+{
+    uint16_t uuid16;
+
+    uuid16 = ble_hs_uuid_16bit(uuid128);
+
+    return uuid16 == BLE_ATT_UUID_PRIMARY_SERVICE ||
+           uuid16 == BLE_ATT_UUID_SECONDARY_SERVICE;
+}
+
+static int
+ble_att_svr_is_valid_group_member(uint8_t *uuid128)
+{
+    uint16_t uuid16;
+
+    /* Assumes the group type is primary or secondary service. */
+
+    uuid16 = ble_hs_uuid_16bit(uuid128);
+
+    return uuid16 == BLE_ATT_UUID_INCLUDE ||
+           uuid16 == BLE_ATT_UUID_CHARACTERISTIC;
+}
+
+static int
+ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16,
+                         uint8_t *uuid128)
+{
+    union ble_att_svr_handle_arg arg;
+    int rc;
+
+    rc = entry->ha_fn(entry, BLE_ATT_OP_READ_REQ, &arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    switch (arg.aha_read.attr_len) {
+    case 16:
+        *uuid16 = 0;
+        memcpy(uuid128, arg.aha_read.attr_data, 16);
+        return 0;
+
+    case 2:
+        *uuid16 = le16toh(arg.aha_read.attr_data);
+        if (*uuid16 == 0) {
+            return EINVAL;
+        }
+        return 0;
+
+    default:
+        return EINVAL;
+    }
+}
+
+static int
+ble_att_svr_read_group_type_entry_write(struct os_mbuf *om, uint16_t mtu,
+                                        uint16_t start_group_handle,
+                                        uint16_t end_group_handle,
+                                        uint16_t service_uuid16,
+                                        uint8_t *service_uuid128)
+{
+    uint8_t *buf;
+    int len;
+
+    if (service_uuid16 != 0) {
+        len = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16;
+    } else {
+        len = BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128;
+    }
+    if (OS_MBUF_PKTLEN(om) + len > mtu) {
+        return EMSGSIZE;
+    }
+
+    buf = os_mbuf_extend(om, len);
+    if (buf == NULL) {
+        return ENOMEM;
+    }
+
+    htole16(buf + 0, start_group_handle);
+    htole16(buf + 2, end_group_handle);
+    if (service_uuid16 != 0) {
+        htole16(buf + 4, service_uuid16);
+    } else {
+        memcpy(buf + 4, service_uuid128, 16);
+    }
+
+    return 0;
+}
+
+static int
+ble_att_svr_tx_read_group_type(struct ble_hs_conn *conn,
+                               struct ble_l2cap_chan *chan,
+                               struct ble_att_read_group_type_req *req,
+                               uint8_t *group_uuid128, uint16_t *err_handle)
+{
+    struct ble_att_read_group_type_rsp rsp;
+    struct ble_att_svr_entry *entry;
+    struct os_mbuf *txom;
+    uint16_t start_group_handle;
+    uint16_t end_group_handle;
+    uint16_t service_uuid16;
+    uint8_t service_uuid128[16];
+    void *rsp_buf;
+    int rc;
+
+    *err_handle = req->bagq_start_handle;
+
+    txom = ble_att_get_pkthdr();
+    if (txom == NULL) {
+        rc = BLE_ATT_ERR_INSUFFICIENT_RES;
+        goto done;
+    }
+
+    /* Reserve space for the response base. */
+    rsp_buf = os_mbuf_extend(txom, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ);
+    if (rsp_buf == NULL) {
+        rc = BLE_ATT_ERR_INSUFFICIENT_RES;
+        goto done;
+    }
+
+    start_group_handle = 0;
+    rsp.bagp_length = 0;
+    STAILQ_FOREACH(entry, &ble_att_svr_list, ha_next) {
+        if (entry->ha_handle_id < req->bagq_start_handle) {
+            continue;
+        }
+        if (entry->ha_handle_id > req->bagq_end_handle) {
+            /* The full input range has been searched. */
+            rc = 0;
+            goto done;
+        }
+
+        if (start_group_handle != 0) {
+            /* We have already found the start of a group. */
+            if (ble_att_svr_is_valid_group_member(entry->ha_uuid)) {
+                /* This attribute is part of the current group. */ 
+                end_group_handle = entry->ha_handle_id;
+            } else {
+                /* This attribute marks the end of the group.  Write an entry
+                 * representing the group to the response.
+                 */
+                rc = ble_att_svr_read_group_type_entry_write(
+                    txom, ble_l2cap_chan_mtu(chan),
+                    start_group_handle, end_group_handle,
+                    service_uuid16, service_uuid128);
+                start_group_handle = 0;
+                end_group_handle = 0;
+                if (rc != 0) {
+                    *err_handle = entry->ha_handle_id;
+                    goto done;
+                }
+            }
+        }
+
+        if (start_group_handle == 0) {
+            /* We are looking for the start of a group. */
+            if (memcmp(entry->ha_uuid, group_uuid128, 16) == 0) {
+                /* Found a group start.  Read the group UUID. */
+                rc = ble_att_svr_service_uuid(entry, &service_uuid16,
+                                              service_uuid128);
+                if (rc != 0) {
+                    *err_handle = entry->ha_handle_id;
+                    rc = BLE_ATT_ERR_UNLIKELY;
+                    goto done;
+                }
+
+                /* Make sure the group UUID lengths are consistent.  If this
+                 * group has a different length UUID, then cut the response
+                 * short.
+                 */
+                switch (rsp.bagp_length) {
+                case 0:
+                    if (service_uuid16 != 0) {
+                        rsp.bagp_length =
+                            BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 2;
+                    } else {
+                        rsp.bagp_length =
+                            BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 16;
+                    }
+                    break;
+
+                case BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 2:
+                    if (service_uuid16 == 0) {
+                        rc = 0;
+                        goto done;
+                    }
+                    break;
+
+                case BLE_ATT_READ_GROUP_TYPE_ADATA_BASE_SZ + 16:
+                    if (service_uuid16 != 0) {
+                        rc = 0;
+                        goto done;
+                    }
+                    break;
+
+                default:
+                    assert(0);
+                    goto done;
+                }
+
+                start_group_handle = entry->ha_handle_id;
+                end_group_handle = entry->ha_handle_id;
+            }
+        }
+    }
+
+    rc = 0;
+
+done:
+    if (rc == 0) {
+        if (start_group_handle != 0) {
+            /* A group was being processed.  Add its corresponding entry to the
+             * response.
+             */
+            rc = ble_att_svr_read_group_type_entry_write(
+                txom, ble_l2cap_chan_mtu(chan),
+                start_group_handle, end_group_handle,
+                service_uuid16, service_uuid128);
+        } else {
+            rc = BLE_ATT_ERR_ATTR_NOT_FOUND;
+        }
+    }
+
+    if (rc == 0 || rc == EMSGSIZE) {
+        rc = ble_att_read_group_type_rsp_write(
+            rsp_buf, BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, &rsp);
+        assert(rc == 0);
+
+        rc = ble_l2cap_tx(conn, chan, txom);
+    } else {
+        os_mbuf_free_chain(txom);
+    }
+
+    return rc;
+}
+
+
+int
+ble_att_svr_rx_read_group_type(struct ble_hs_conn *conn,
+                               struct ble_l2cap_chan *chan,
+                               struct os_mbuf **rxom)
+{
+    struct ble_att_read_group_type_req req;
+    uint16_t err_handle;
+    uint8_t uuid128[16];
+    int rc;
+
+    err_handle = 0;
+
+    *rxom = os_mbuf_pullup(*rxom, OS_MBUF_PKTLEN(*rxom));
+    if (*rxom == NULL) {
+        rc = ENOMEM;
+        goto err;
+    }
+
+    rc = ble_att_read_group_type_req_parse((*rxom)->om_data, (*rxom)->om_len,
+                                           &req);
+    if (rc != 0) {
+        goto err;
+    }
+    err_handle = req.bagq_start_handle;
+
+    rc = ble_hs_uuid_extract(*rxom, BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ,
+                             uuid128);
+    if (rc != 0) {
+        goto err;
+    }
+
+    if (!ble_att_svr_is_valid_group_type(uuid128)) {
+        rc = EINVAL; // XXX
+        goto err;
+    }
+
+    rc = ble_att_svr_tx_read_group_type(conn, chan, &req, uuid128,
+                                        &err_handle);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    ble_att_svr_tx_error_rsp(conn, chan, BLE_ATT_OP_READ_GROUP_TYPE_REQ,
+                             err_handle, rc);
+    return rc;
+}
+
+static int
 ble_att_svr_tx_write_rsp(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
 {
     struct os_mbuf *txom;
     uint8_t *dst;
     int rc;
 
-    txom = os_mbuf_get_pkthdr(&ble_hs_mbuf_pool, 0);
+    txom = ble_att_get_pkthdr();
     if (txom == NULL) {
         rc = BLE_ATT_ERR_INSUFFICIENT_RES;
         goto err;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/net/nimble/host/src/ble_gatt.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gatt.c b/net/nimble/host/src/ble_gatt.c
index d8575c4..55e4b0b 100644
--- a/net/nimble/host/src/ble_gatt.c
+++ b/net/nimble/host/src/ble_gatt.c
@@ -28,9 +28,6 @@
 #include "ble_att_cmd.h"
 #include "ble_att_priv.h"
 
-#define BLE_ATT_UUID_PRIMARY_SERVICE    0x2800
-#define BLE_ATT_UUID_CHARACTERISTIC     0x2803
-
 struct ble_gatt_entry {
     STAILQ_ENTRY(ble_gatt_entry) next;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 b6800e3..b196f78 100644
--- a/net/nimble/host/src/ble_hs.c
+++ b/net/nimble/host/src/ble_hs.c
@@ -39,7 +39,7 @@
 static struct os_task ble_hs_task;
 static os_stack_t ble_hs_stack[BLE_HS_STACK_SIZE];
 
-#define HCI_CMD_BUFS        (8)
+#define HCI_CMD_BUFS        (6)
 #define HCI_CMD_BUF_SIZE    (260)       /* XXX: temporary, Fix later */
 struct os_mempool g_hci_cmd_pool;
 static os_membuf_t g_hci_cmd_buf[OS_MEMPOOL_BYTES(HCI_CMD_BUFS,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/net/nimble/host/src/ble_hs_uuid.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_uuid.c b/net/nimble/host/src/ble_hs_uuid.c
index fe2dfae..eb3d943 100644
--- a/net/nimble/host/src/ble_hs_uuid.c
+++ b/net/nimble/host/src/ble_hs_uuid.c
@@ -114,7 +114,7 @@ ble_hs_uuid_extract(struct os_mbuf *om, int off, void *uuid128)
     int remlen;
     int rc;
 
-    remlen = OS_MBUF_PKTHDR(om)->omp_len;
+    remlen = OS_MBUF_PKTHDR(om)->omp_len - off;
     switch (remlen) {
     case 2:
         rc = os_mbuf_copydata(om, off, 2, &uuid16);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 2a4e81b..f75e91d 100644
--- a/net/nimble/host/src/ble_l2cap.c
+++ b/net/nimble/host/src/ble_l2cap.c
@@ -147,7 +147,8 @@ ble_l2cap_rx(struct ble_hs_conn *conn,
     int rc;
 
     /* XXX: HCI-fragmentation unsupported. */
-    assert(BLE_HCI_DATA_PB(hci_hdr->hdh_handle_pb_bc) == BLE_HCI_PB_FULL);
+    assert(BLE_HCI_DATA_PB(hci_hdr->hdh_handle_pb_bc) ==
+                           BLE_HCI_PB_FIRST_FLUSH);
 
     rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr);
     if (rc != 0) {
@@ -196,6 +197,7 @@ ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
     }
 
     rc = host_hci_data_tx(conn, om);
+    om = NULL;
     if (rc != 0) {
         goto err;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 67d3def..7ff42de 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -413,6 +413,19 @@ host_hci_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *hdr)
     return 0;
 }
 
+static void
+host_hci_log_pkt(struct os_mbuf *om)
+{
+    uint8_t u8;
+    int i;
+
+    for (i = 0; i < OS_MBUF_PKTLEN(om); i++) {
+        os_mbuf_copydata(om, i, 1, &u8);
+        console_printf("0x%02x ", u8);
+    }
+    console_printf("\n");
+}
+
 /**
  * Called when a data packet is received from the controller.  This function
  * consumes the supplied mbuf, regardless of the outcome.
@@ -430,6 +443,9 @@ host_hci_data_rx(struct os_mbuf *om)
     uint16_t handle;
     int rc;
 
+    console_printf("host_hci_data_rx(): ");
+    host_hci_log_pkt(om);
+
     rc = host_hci_data_hdr_strip(om, &hci_hdr);
     if (rc != 0) {
         goto done;
@@ -501,11 +517,14 @@ host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om)
      * requirements.  For now, never fragment.
      */
     om = host_hci_data_hdr_prepend(om, connection->bhc_handle,
-                                   BLE_HCI_PB_FULL);
+                                   BLE_HCI_PB_FIRST_NON_FLUSH);
     if (om == NULL) {
         return ENOMEM;
     }
 
+    console_printf("host_hci_data_tx(): ");
+    host_hci_log_pkt(om);
+
     rc = ble_hs_tx_data(om);
     if (rc != 0) {
         return rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 488e0d4..d7b6d3c 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -142,7 +142,8 @@ ble_hs_test_util_l2cap_rx_payload_flat(struct ble_hs_conn *conn,
     TEST_ASSERT_FATAL(om != NULL);
 
     hci_hdr.hdh_handle_pb_bc =
-        host_hci_handle_pb_bc_join(conn->bhc_handle, BLE_HCI_PB_FULL, 0);
+        host_hci_handle_pb_bc_join(conn->bhc_handle,
+                                   BLE_HCI_PB_FIRST_FLUSH, 0);
     hci_hdr.hdh_len = OS_MBUF_PKTHDR(om)->omp_len;
 
     rc = ble_l2cap_rx(conn, &hci_hdr, om);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/c1ac77ce/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 48fb259..a1fe064 100644
--- a/net/nimble/host/src/test/ble_l2cap_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_test.c
@@ -39,7 +39,7 @@ TEST_CASE(l2cap_test_bad_header)
     TEST_ASSERT_FATAL(conn != NULL);
 
     hci_hdr.hdh_handle_pb_bc =
-        host_hci_handle_pb_bc_join(0, BLE_HCI_PB_FULL, 0);
+        host_hci_handle_pb_bc_join(0, BLE_HCI_PB_FIRST_FLUSH, 0);
     hci_hdr.hdh_len = 10;
 
     /*** HCI header indicates a length of 10, but L2CAP header has a length