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/29 02:07:24 UTC

[1/3] incubator-mynewt-larva git commit: testutil bug fix: Stop OS upon system reset.

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 14b5ded6d -> d67865a8f


testutil bug fix: Stop OS upon system reset.


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

Branch: refs/heads/master
Commit: 81e00be2e247f4c61d7f793ad5ccb312056a1881
Parents: 14b5ded
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Dec 28 16:20:22 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Mon Dec 28 17:06:50 2015 -0800

----------------------------------------------------------------------
 libs/testutil/src/arch/sim/testutil_arch_sim.c | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/81e00be2/libs/testutil/src/arch/sim/testutil_arch_sim.c
----------------------------------------------------------------------
diff --git a/libs/testutil/src/arch/sim/testutil_arch_sim.c b/libs/testutil/src/arch/sim/testutil_arch_sim.c
index 1b5ff49..dbb39b4 100644
--- a/libs/testutil/src/arch/sim/testutil_arch_sim.c
+++ b/libs/testutil/src/arch/sim/testutil_arch_sim.c
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#include "os/os.h"
 #include "os/os_test.h"
 #include "testutil_priv.h"
 
 void
 tu_arch_restart(void)
 {
+    g_os_started = 0;
     tu_case_abort();
 }


[3/3] incubator-mynewt-larva git commit: Add some GATT server unit tests.

Posted by cc...@apache.org.
Add some GATT server unit tests.


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

Branch: refs/heads/master
Commit: d67865a8f8614b5ed7c9dcac96706d325bce5f93
Parents: 10480cf
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Dec 28 17:06:12 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Mon Dec 28 17:07:07 2015 -0800

----------------------------------------------------------------------
 net/nimble/host/src/test/ble_gatts_reg_test.c | 490 +++++++++++++++++++++
 1 file changed, 490 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/d67865a8/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
new file mode 100644
index 0000000..4e7e09f
--- /dev/null
+++ b/net/nimble/host/src/test/ble_gatts_reg_test.c
@@ -0,0 +1,490 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "testutil/testutil.h"
+#include "nimble/ble.h"
+#include "ble_hs_priv.h"
+#include "host/ble_uuid.h"
+#include "host/ble_hs_test.h"
+#include "ble_gatt_priv.h"
+#include "ble_hs_test_util.h"
+
+#define BLE_GATTS_REG_TEST_MAX_ENTRIES  256
+
+struct ble_gatts_reg_test_entry {
+    uint8_t op;
+    uint8_t uuid128[16];
+};
+
+static struct ble_gatts_reg_test_entry
+ble_gatts_reg_test_entries[BLE_GATTS_REG_TEST_MAX_ENTRIES];
+
+static int ble_gatts_reg_test_num_entries;
+
+static void
+ble_gatts_reg_test_init(void)
+{
+    ble_hs_test_util_init();
+    ble_gatts_reg_test_num_entries = 0;
+}
+
+static void
+ble_gatts_reg_test_misc_reg_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt,
+                               void *arg)
+{
+    struct ble_gatts_reg_test_entry *entry;
+
+    TEST_ASSERT_FATAL(ble_gatts_reg_test_num_entries <
+                      BLE_GATTS_REG_TEST_MAX_ENTRIES);
+
+    entry = ble_gatts_reg_test_entries + ble_gatts_reg_test_num_entries++;
+
+    entry->op = op;
+    switch (op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        memcpy(entry->uuid128, ctxt->svc_reg.svc->uuid128, 16);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        memcpy(entry->uuid128, ctxt->chr_reg.chr->uuid128, 16);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        memcpy(entry->uuid128, ctxt->dsc_reg.dsc->uuid128, 16);
+        break;
+
+    default:
+        TEST_ASSERT(0);
+        break;
+    }
+}
+
+static void
+ble_gatts_reg_test_misc_verify_entry(uint8_t op, uint8_t *uuid128)
+{
+    struct ble_gatts_reg_test_entry *entry;
+    int i;
+
+    for (i = 0; i < ble_gatts_reg_test_num_entries; i++) {
+        entry = ble_gatts_reg_test_entries + i;
+        if (entry->op == op && memcmp(entry->uuid128, uuid128, 16) == 0) {
+            return;
+        }
+    }
+
+    TEST_ASSERT(0);
+}
+
+static int
+ble_gatts_reg_test_misc_dummy_access(uint16_t handle_id, uint8_t op,
+                                     union ble_gatt_access_ctxt *ctxt,
+                                     void *arg)
+{
+    return 0;
+}
+
+TEST_CASE(ble_gatts_reg_test_svc_return)
+{
+    int rc;
+
+    ble_gatts_reg_test_init();
+
+    /*** Missing type. */
+    struct ble_gatt_svc_def svcs_no_type[] = { {
+        .uuid128 = BLE_UUID16(0x1234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_no_type, NULL, NULL);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+
+    /*** Missing UUID. */
+    struct ble_gatt_svc_def svcs_no_uuid[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_no_uuid, NULL, NULL);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+
+    /*** Circular dependency. */
+    struct ble_gatt_svc_def svcs_circ[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .includes = (struct ble_gatt_svc_def*[]) { svcs_circ + 1, NULL },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_SECONDARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .includes = (struct ble_gatt_svc_def*[]) { svcs_circ + 0, NULL },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_circ, NULL, NULL);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+
+    /*** Success. */
+    struct ble_gatt_svc_def svcs_good[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .includes = (struct ble_gatt_svc_def*[]) { svcs_good + 1, NULL },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_SECONDARY,
+        .uuid128 = BLE_UUID16(0x1234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_good, NULL, NULL);
+    TEST_ASSERT(rc == 0);
+}
+
+TEST_CASE(ble_gatts_reg_test_chr_return)
+{
+    int rc;
+
+    ble_gatts_reg_test_init();
+
+    /*** Missing callback. */
+    struct ble_gatt_svc_def svcs_no_chr_cb[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .properties = BLE_GATT_CHR_PROP_READ,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_no_chr_cb, NULL, NULL);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+
+    /*** Success. */
+    struct ble_gatt_svc_def svcs_good[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_good, NULL, NULL);
+    TEST_ASSERT(rc == 0);
+}
+
+TEST_CASE(ble_gatts_reg_test_dsc_return)
+{
+    int rc;
+
+    ble_gatts_reg_test_init();
+
+    /*** Missing callback. */
+    struct ble_gatt_svc_def svcs_no_dsc_cb[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                .uuid128 = BLE_UUID16(0x8888),
+                .att_flags = 5,
+            }, {
+                .uuid128 = NULL,
+            } },
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_no_dsc_cb, NULL, NULL);
+    TEST_ASSERT(rc == BLE_HS_EINVAL);
+
+    /*** Success. */
+    struct ble_gatt_svc_def svcs_good[] = { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                .uuid128 = BLE_UUID16(0x8888),
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+                .att_flags = 5,
+            }, {
+                .uuid128 = NULL,
+            } },
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } };
+
+    rc = ble_gatts_register_services(svcs_good, NULL, NULL);
+    TEST_ASSERT(rc == 0);
+}
+
+static void
+ble_gatts_reg_test_misc_svcs(struct ble_gatt_svc_def *svcs)
+{
+    struct ble_gatt_svc_def *svc;
+    struct ble_gatt_chr_def *chr;
+    struct ble_gatt_dsc_def *dsc;
+    int rc;
+
+    ble_gatts_reg_test_init();
+
+    /* Register all the attributes. */
+    rc = ble_gatts_register_services(svcs, ble_gatts_reg_test_misc_reg_cb,
+                                     NULL);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    /* Verify that the appropriate callbacks were executed. */
+    for (svc = svcs; svc->type != BLE_GATT_SVC_TYPE_END; svc++) {
+        ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_SVC,
+                                             svc->uuid128);
+
+        if (svc->characteristics != NULL) {
+            for (chr = svc->characteristics; chr->uuid128 != NULL; chr++) {
+                ble_gatts_reg_test_misc_verify_entry(BLE_GATT_REGISTER_OP_CHR,
+                                                     chr->uuid128);
+
+                if (chr->descriptors != NULL) {
+                    for (dsc = chr->descriptors; dsc->uuid128 != NULL; dsc++) {
+                        ble_gatts_reg_test_misc_verify_entry(
+                            BLE_GATT_REGISTER_OP_DSC, dsc->uuid128);
+                    }
+                }
+            }
+        }
+    }
+}
+
+TEST_CASE(ble_gatts_reg_test_svc_cb)
+{
+    /*** 1 primary. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+
+    /*** 3 primary. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x2234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x3234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+
+
+    /*** 1 primary, 1 secondary. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_SECONDARY,
+        .uuid128 = BLE_UUID16(0x2222),
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+
+    /*** 1 primary, 1 secondary, 1 include. */
+    struct ble_gatt_svc_def svcs[] = {
+        [0] = {
+            .type = BLE_GATT_SVC_TYPE_PRIMARY,
+            .uuid128 = BLE_UUID16(0x1234),
+            .includes = (struct ble_gatt_svc_def*[]) { svcs + 1, NULL, },
+        },
+        [1] = {
+            .type = BLE_GATT_SVC_TYPE_SECONDARY,
+            .uuid128 = BLE_UUID16(0x2222),
+        }, {
+            .type = BLE_GATT_SVC_TYPE_END,
+        }
+    };
+    ble_gatts_reg_test_misc_svcs(svcs);
+}
+
+TEST_CASE(ble_gatts_reg_test_chr_cb)
+{
+    /*** 1 characteristic. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+
+    /*** 3 characteristics. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+        }, {
+            .uuid128 = BLE_UUID16(0x2222),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_WRITE,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_SECONDARY,
+        .uuid128 = BLE_UUID16(0x5678),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x3333),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+}
+
+TEST_CASE(ble_gatts_reg_test_dsc_cb)
+{
+    /*** 1 descriptor. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                .uuid128 = BLE_UUID16(0xaaaa),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = NULL,
+            } },
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+
+    /*** 5 descriptors. */
+    ble_gatts_reg_test_misc_svcs((struct ble_gatt_svc_def[]) { {
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid128 = BLE_UUID16(0x1234),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x1111),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                .uuid128 = BLE_UUID16(0xaaaa),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = NULL,
+            } },
+        }, {
+            .uuid128 = BLE_UUID16(0x2222),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_WRITE,
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_SECONDARY,
+        .uuid128 = BLE_UUID16(0x5678),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            .uuid128 = BLE_UUID16(0x3333),
+            .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            .properties = BLE_GATT_CHR_PROP_READ,
+            .descriptors = (struct ble_gatt_dsc_def[]) { {
+                .uuid128 = BLE_UUID16(0xaaab),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = BLE_UUID16(0xaaac),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = BLE_UUID16(0xaaad),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = BLE_UUID16(0xaaae),
+                .att_flags = 5,
+                .access_cb = ble_gatts_reg_test_misc_dummy_access,
+            }, {
+                .uuid128 = NULL,
+            } },
+        }, {
+            .uuid128 = NULL,
+        } },
+    }, {
+        .type = BLE_GATT_SVC_TYPE_END,
+    } });
+}
+
+TEST_SUITE(ble_gatts_suite)
+{
+    ble_gatts_reg_test_svc_return();
+    ble_gatts_reg_test_chr_return();
+    ble_gatts_reg_test_dsc_return();
+
+    ble_gatts_reg_test_svc_cb();
+    ble_gatts_reg_test_chr_cb();
+    ble_gatts_reg_test_dsc_cb();
+}
+
+int
+ble_gatts_reg_test_all(void)
+{
+    ble_gatts_suite();
+
+    return tu_any_failed;
+}


[2/3] incubator-mynewt-larva git commit: Read / write descriptors.

Posted by cc...@apache.org.
Read / write descriptors.


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

Branch: refs/heads/master
Commit: 10480cfc988399590bc0f59d00277a49955b1bf4
Parents: 81e00be
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Dec 28 16:22:10 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Mon Dec 28 17:07:07 2015 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_att.h      |   7 +-
 net/nimble/host/include/host/ble_gatt.h     |  47 +++--
 net/nimble/host/include/host/ble_hs_test.h  |   1 +
 net/nimble/host/src/ble_att_priv.h          |   1 +
 net/nimble/host/src/ble_att_svr.c           |  39 ++--
 net/nimble/host/src/ble_gatt.c              |   4 +-
 net/nimble/host/src/ble_gatt_priv.h         |   3 +-
 net/nimble/host/src/ble_gatts.c             | 246 +++++++++++++++--------
 net/nimble/host/src/test/ble_att_svr_test.c |  28 +--
 net/nimble/host/src/test/ble_hs_test.c      |   1 +
 project/prphtest/src/main.c                 |  24 +--
 11 files changed, 248 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 8a0cc17..ac5ba61 100644
--- a/net/nimble/host/include/host/ble_att.h
+++ b/net/nimble/host/include/host/ble_att.h
@@ -62,12 +62,7 @@ union ble_att_svr_access_ctxt {
     struct {
         void *attr_data;
         int attr_len;
-    } ahc_read;
-
-    struct {
-        void *attr_data;
-        int attr_len;
-    } ahc_write;
+    } rw;
 };
 
 #define HA_FLAG_PERM_READ                   (1 << 0)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 cc54db6..7c7a232 100644
--- a/net/nimble/host/include/host/ble_gatt.h
+++ b/net/nimble/host/include/host/ble_gatt.h
@@ -73,8 +73,19 @@ int ble_gatt_init(void);
 
 /*** @server. */
 
+#define BLE_GATT_CHR_PROP_BROADCAST         0x01
+#define BLE_GATT_CHR_PROP_READ              0x02
+#define BLE_GATT_CHR_PROP_WRITE_NO_RSP      0x04
+#define BLE_GATT_CHR_PROP_WRITE             0x08
+#define BLE_GATT_CHR_PROP_NOTIFY            0x10
+#define BLE_GATT_CHR_PROP_INDICATE          0x20
+#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE   0x40
+#define BLE_GATT_CHR_PROP_EXTENDED          0x80
+
 #define BLE_GATT_ACCESS_OP_READ_CHR         0
 #define BLE_GATT_ACCESS_OP_WRITE_CHR        1
+#define BLE_GATT_ACCESS_OP_READ_DSC         2
+#define BLE_GATT_ACCESS_OP_WRITE_DSC        3
 /* XXX: Notify, listen. */
 
 union ble_gatt_access_ctxt;
@@ -89,9 +100,9 @@ struct ble_gatt_chr_def {
     uint8_t properties;
 };
 
-#define BLE_GATT_SVC_TYPE_END       0
 #define BLE_GATT_SVC_TYPE_PRIMARY   1
 #define BLE_GATT_SVC_TYPE_SECONDARY 2
+#define BLE_GATT_SVC_TYPE_END       3
 
 struct ble_gatt_svc_def {
     uint8_t type;
@@ -103,53 +114,55 @@ struct ble_gatt_svc_def {
 union ble_gatt_access_ctxt {
     struct {
         const struct ble_gatt_chr_def *chr;
-        void *chr_data;
-        int chr_len;
-    } bgc_read;
+        void *data;
+        int len;
+    } chr_access;
 
     struct {
-        const struct ble_gatt_chr_def *chr;
-        void *chr_data;
-        int chr_len;
-    } bgc_write;
+        const struct ble_gatt_dsc_def *dsc;
+        void *data;
+        int len;
+    } dsc_access;
 };
 
 struct ble_gatt_dsc_def {
     uint8_t *uuid128;
     uint8_t att_flags;
-    ble_att_svr_access_fn *access_cb;
+    ble_gatt_access_fn *access_cb;
     void *arg;
 };
 
-#define BLE_GATT_REGISTER_OP_SVC    0
-#define BLE_GATT_REGISTER_OP_CHR    1
-#define BLE_GATT_REGISTER_OP_DSC    2
+#define BLE_GATT_REGISTER_OP_SVC    1
+#define BLE_GATT_REGISTER_OP_CHR    2
+#define BLE_GATT_REGISTER_OP_DSC    3
 
 union ble_gatt_register_ctxt;
 typedef void ble_gatt_register_fn(uint8_t op,
-                                  union ble_gatt_register_ctxt *ctxt);
+                                  union ble_gatt_register_ctxt *ctxt,
+                                  void *arg);
 
 int ble_gatt_register_services(const struct ble_gatt_svc_def *svcs,
-                               ble_gatt_register_fn *register_cb);
+                               ble_gatt_register_fn *register_cb,
+                               void *cb_arg);
 
 union ble_gatt_register_ctxt {
     struct {
         uint16_t handle;
         const struct ble_gatt_svc_def *svc;
-    } bgr_svc;
+    } svc_reg;
 
     struct {
         uint16_t def_handle;
         uint16_t val_handle;
         const struct ble_gatt_chr_def *chr;
-    } bgr_chr;
+    } chr_reg;
 
     struct {
         uint16_t dsc_handle;
         const struct ble_gatt_dsc_def *dsc;
         uint16_t chr_def_handle;
         const struct ble_gatt_chr_def *chr;
-    } bgr_dsc;
+    } dsc_reg;
 };
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/net/nimble/host/include/host/ble_hs_test.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_hs_test.h b/net/nimble/host/include/host/ble_hs_test.h
index 4e69726..7aebbbc 100644
--- a/net/nimble/host/include/host/ble_hs_test.h
+++ b/net/nimble/host/include/host/ble_hs_test.h
@@ -36,5 +36,6 @@ int ble_gatt_read_test_all(void);
 int ble_gatt_write_test_all(void);
 int ble_gatt_conn_test_all(void);
 int ble_hs_adv_test_all(void);
+int ble_gatts_reg_test_all(void);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 9de76ad..5cc4220 100644
--- a/net/nimble/host/src/ble_att_priv.h
+++ b/net/nimble/host/src/ble_att_priv.h
@@ -93,6 +93,7 @@ void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
 struct os_mbuf *ble_att_get_pkthdr(void);
 
 /*** @svr */
+uint16_t ble_att_svr_prev_handle(void);
 int ble_att_svr_rx_mtu(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
                        struct os_mbuf **rxom);
 int ble_att_svr_rx_find_info(struct ble_hs_conn *conn,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 f36b8d8..d596a91 100644
--- a/net/nimble/host/src/ble_att_svr.c
+++ b/net/nimble/host/src/ble_att_svr.c
@@ -36,7 +36,6 @@ static struct os_mutex ble_att_svr_list_mutex;
 static void *ble_att_svr_entry_mem;
 static struct os_mempool ble_att_svr_entry_pool;
 
-
 #define BLE_ATT_SVR_PREP_MBUF_BUF_SIZE         (128)
 #define BLE_ATT_SVR_PREP_MBUF_MEMBLOCK_SIZE                     \
     (BLE_ATT_SVR_PREP_MBUF_BUF_SIZE + sizeof(struct os_mbuf) +  \
@@ -178,6 +177,12 @@ ble_att_svr_register_uuid16(uint16_t uuid16, uint8_t flags,
     return 0;
 }
 
+uint16_t
+ble_att_svr_prev_handle(void)
+{
+    return ble_att_svr_id - 1;
+}
+
 /**
  * Walk the host attribute list, calling walk_func on each entry with argument.
  * If walk_func wants to stop iteration, it returns 1.  To continue iteration
@@ -813,8 +818,8 @@ ble_att_svr_fill_type_value(struct ble_att_find_type_value_req *req,
                 }
                 rc = os_mbuf_memcmp(rxom,
                                     BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ,
-                                    arg.ahc_read.attr_data,
-                                    arg.ahc_read.attr_len);
+                                    arg.rw.attr_data,
+                                    arg.rw.attr_len);
                 if (rc == 0) {
                     match = 1;
                 }
@@ -1038,10 +1043,10 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn,
                 goto done;
             }
 
-            if (arg.ahc_read.attr_len > ble_l2cap_chan_mtu(chan) - 4) {
+            if (arg.rw.attr_len > ble_l2cap_chan_mtu(chan) - 4) {
                 attr_len = ble_l2cap_chan_mtu(chan) - 4;
             } else {
-                attr_len = arg.ahc_read.attr_len;
+                attr_len = arg.rw.attr_len;
             }
 
             if (prev_attr_len == 0) {
@@ -1064,7 +1069,7 @@ ble_att_svr_tx_read_type_rsp(struct ble_hs_conn *conn,
             }
 
             htole16(dptr + 0, entry->ha_handle_id);
-            memcpy(dptr + 2, arg.ahc_read.attr_data, attr_len);
+            memcpy(dptr + 2, arg.rw.attr_data, attr_len);
             entry_written = 1;
         }
     }
@@ -1272,8 +1277,8 @@ ble_att_svr_rx_read(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
         goto err;
     }
 
-    rc = ble_att_svr_tx_read_rsp(conn, chan, arg.ahc_read.attr_data,
-                                 arg.ahc_read.attr_len, &att_err);
+    rc = ble_att_svr_tx_read_rsp(conn, chan, arg.rw.attr_data,
+                                 arg.rw.attr_len, &att_err);
     if (rc != 0) {
         err_handle = req.barq_handle;
         goto err;
@@ -1311,14 +1316,14 @@ ble_att_svr_service_uuid(struct ble_att_svr_entry *entry, uint16_t *uuid16,
         return rc;
     }
 
-    switch (arg.ahc_read.attr_len) {
+    switch (arg.rw.attr_len) {
     case 16:
         *uuid16 = 0;
-        memcpy(uuid128, arg.ahc_read.attr_data, 16);
+        memcpy(uuid128, arg.rw.attr_data, 16);
         return 0;
 
     case 2:
-        *uuid16 = le16toh(arg.ahc_read.attr_data);
+        *uuid16 = le16toh(arg.rw.attr_data);
         if (*uuid16 == 0) {
             return BLE_HS_EINVAL;
         }
@@ -1677,10 +1682,10 @@ ble_att_svr_rx_write(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan,
         goto err;
     }
 
-    arg.ahc_write.attr_data = ble_att_svr_flat_buf;
-    arg.ahc_write.attr_len = OS_MBUF_PKTLEN(*rxom);
-    os_mbuf_copydata(*rxom, 0, arg.ahc_write.attr_len,
-                     arg.ahc_write.attr_data);
+    arg.rw.attr_data = ble_att_svr_flat_buf;
+    arg.rw.attr_len = OS_MBUF_PKTLEN(*rxom);
+    os_mbuf_copydata(*rxom, 0, arg.rw.attr_len,
+                     arg.rw.attr_data);
     att_err = entry->ha_cb(entry->ha_handle_id, entry->ha_uuid,
                            BLE_ATT_ACCESS_OP_WRITE, &arg, entry->ha_cb_arg);
     if (att_err != 0) {
@@ -1846,8 +1851,8 @@ ble_att_svr_prep_write(struct ble_att_svr_conn *basc, uint16_t *err_handle)
                 return BLE_ATT_ERR_INVALID_HANDLE;
             }
 
-            arg.ahc_write.attr_data = ble_att_svr_flat_buf;
-            arg.ahc_write.attr_len = buf_off;
+            arg.rw.attr_data = ble_att_svr_flat_buf;
+            arg.rw.attr_len = buf_off;
             rc = attr->ha_cb(attr->ha_handle_id, attr->ha_uuid,
                              BLE_ATT_ACCESS_OP_WRITE, &arg, attr->ha_cb_arg);
             if (rc != 0) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 5af7e17..dc99bb4 100644
--- a/net/nimble/host/src/ble_gatt.c
+++ b/net/nimble/host/src/ble_gatt.c
@@ -63,9 +63,9 @@ ble_gatt_connection_broken(uint16_t conn_handle)
 
 int
 ble_gatt_register_services(const struct ble_gatt_svc_def *svcs,
-                           ble_gatt_register_fn *register_cb)
+                           ble_gatt_register_fn *register_cb, void *cb_arg)
 {
-    return ble_gatts_register_services(svcs, register_cb);
+    return ble_gatts_register_services(svcs, register_cb, cb_arg);
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 5271617..7ee73be 100644
--- a/net/nimble/host/src/ble_gatt_priv.h
+++ b/net/nimble/host/src/ble_gatt_priv.h
@@ -66,6 +66,7 @@ int ble_gattc_init(void);
 
 /*** @server. */
 int ble_gatts_register_services(const struct ble_gatt_svc_def *svcs,
-                                ble_gatt_register_fn *register_cb);
+                                ble_gatt_register_fn *register_cb,
+                                void *cb_arg);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 dd27b4e..8c8916c 100644
--- a/net/nimble/host/src/ble_gatts.c
+++ b/net/nimble/host/src/ble_gatts.c
@@ -20,6 +20,7 @@
 #include "nimble/ble.h"
 #include "host/ble_uuid.h"
 #include "ble_hs_priv.h"
+#include "ble_att_priv.h"
 #include "ble_gatt_priv.h"
 
 #define BLE_GATTS_INCLUDE_SZ    6
@@ -30,7 +31,7 @@
 struct ble_gatts_svc_entry {
     const struct ble_gatt_svc_def *svc;
     uint16_t handle;            /* 0 means unregistered. */
-    uint16_t end_group_handle;
+    uint16_t end_group_handle;  /* 0xffff means unset. */
 };
 
 static struct ble_gatts_svc_entry
@@ -46,8 +47,8 @@ ble_gatts_svc_access(uint16_t handle_id, uint8_t *uuid128, uint8_t op,
     assert(op == BLE_ATT_ACCESS_OP_READ);
 
     svc = arg;
-    ctxt->ahc_read.attr_data = svc->uuid128;
-    ctxt->ahc_read.attr_len = 16;
+    ctxt->rw.attr_data = svc->uuid128;
+    ctxt->rw.attr_len = 16;
 
     return 0;
 }
@@ -72,11 +73,11 @@ ble_gatts_inc_access(uint16_t handle_id, uint8_t *uuid128, uint8_t op,
     uuid16 = ble_uuid_128_to_16(entry->svc->uuid128);
     if (uuid16 != 0) {
         htole16(buf + 4, uuid16);
-        ctxt->ahc_read.attr_len = 6;
+        ctxt->rw.attr_len = 6;
     } else {
-        ctxt->ahc_read.attr_len = 4;
+        ctxt->rw.attr_len = 4;
     }
-    ctxt->ahc_read.attr_data = buf;
+    ctxt->rw.attr_data = buf;
 
     return 0;
 }
@@ -101,63 +102,45 @@ ble_gatts_chr_def_access(uint16_t handle_id, uint8_t *uuid128, uint8_t op,
     uuid16 = ble_uuid_128_to_16(chr->uuid128);
     if (uuid16 != 0) {
         htole16(buf + 3, uuid16);
-        ctxt->ahc_read.attr_len = 5;
+        ctxt->rw.attr_len = 5;
     } else {
         memcpy(buf + 3, chr->uuid128, 16);
-        ctxt->ahc_read.attr_len = 19;
+        ctxt->rw.attr_len = 19;
     }
-    ctxt->ahc_read.attr_data = buf;
+    ctxt->rw.attr_data = buf;
 
     return 0;
 }
 
-static void
-ble_gatts_ctxt_from_att_ctxt(uint8_t att_op,
-                             union ble_att_svr_access_ctxt *att_ctxt,
-                             uint8_t *out_gatt_op,
-                             union ble_gatt_access_ctxt *out_gatt_ctxt,
-                             void *att_arg)
+static int
+ble_gatts_chr_is_sane(const struct ble_gatt_chr_def *chr)
 {
-    switch (att_op) {
-    case BLE_ATT_ACCESS_OP_READ:
-        *out_gatt_op = BLE_GATT_ACCESS_OP_READ_CHR;
-        out_gatt_ctxt->bgc_read.chr = att_arg;
-        out_gatt_ctxt->bgc_read.chr_data = att_ctxt->ahc_read.attr_data;
-        out_gatt_ctxt->bgc_read.chr_len = att_ctxt->ahc_read.attr_len;
-        break;
-
-    case BLE_ATT_ACCESS_OP_WRITE:
-        *out_gatt_op = BLE_GATT_ACCESS_OP_WRITE_CHR;
-        out_gatt_ctxt->bgc_write.chr = att_arg;
-        out_gatt_ctxt->bgc_write.chr_data = att_ctxt->ahc_write.attr_data;
-        out_gatt_ctxt->bgc_write.chr_len = att_ctxt->ahc_write.attr_len;
-        break;
+    if (chr->uuid128 == NULL) {
+        return 0;
+    }
 
-    default:
-        assert(0);
-        break;
+    if (chr->access_cb == NULL) {
+        return 0;
     }
+
+    /* XXX: Check properties. */
+
+    return 1;
 }
 
-static void
-ble_gatts_ctxt_to_att_ctxt(uint8_t gatt_op,
-                           union ble_gatt_access_ctxt *gatt_ctxt,
-                           union ble_att_svr_access_ctxt *out_att_ctxt)
+static uint8_t
+ble_gatts_chr_op(uint8_t att_op)
 {
-    switch (gatt_op) {
-    case BLE_GATT_ACCESS_OP_READ_CHR:
-        out_att_ctxt->ahc_read.attr_data = gatt_ctxt->bgc_read.chr_data;
-        out_att_ctxt->ahc_read.attr_len = gatt_ctxt->bgc_read.chr_len;
-        break;
+    switch (att_op) {
+    case BLE_ATT_ACCESS_OP_READ:
+        return BLE_GATT_ACCESS_OP_READ_CHR;
 
-    case BLE_GATT_ACCESS_OP_WRITE_CHR:
-        out_att_ctxt->ahc_write.attr_data = gatt_ctxt->bgc_write.chr_data;
-        out_att_ctxt->ahc_write.attr_len = gatt_ctxt->bgc_write.chr_len;
-        break;
+    case BLE_ATT_ACCESS_OP_WRITE:
+        return BLE_GATT_ACCESS_OP_WRITE_CHR;
 
     default:
         assert(0);
-        break;
+        return BLE_GATT_ACCESS_OP_READ_CHR;
     }
 }
 
@@ -170,17 +153,20 @@ ble_gatts_chr_val_access(uint16_t handle_id, uint8_t *uuid128, uint8_t att_op,
     uint8_t gatt_op;
     int rc;
 
-    ble_gatts_ctxt_from_att_ctxt(att_op, att_ctxt, &gatt_op, &gatt_ctxt, arg);
-
     chr = arg;
     assert(chr != NULL && chr->access_cb != NULL);
 
+    gatt_op = ble_gatts_chr_op(att_op);
+    gatt_ctxt.chr_access.chr = chr;
+    gatt_ctxt.chr_access.data = att_ctxt->rw.attr_data;
+    gatt_ctxt.chr_access.len = att_ctxt->rw.attr_len;
+
     rc = chr->access_cb(handle_id, gatt_op, &gatt_ctxt, chr->arg);
     if (rc != 0) {
         return rc;
     }
 
-    ble_gatts_ctxt_to_att_ctxt(gatt_op, &gatt_ctxt, att_ctxt);
+    att_ctxt->rw.attr_len = gatt_ctxt.chr_access.len;
 
     return 0;
 }
@@ -203,17 +189,17 @@ ble_gatts_find_svc(const struct ble_gatt_svc_def *svc)
 static int
 ble_gatts_svc_incs_satisfied(const struct ble_gatt_svc_def *svc)
 {
-    const struct ble_gatt_svc_def *incl;
     int idx;
+    int i;
 
     if (svc->includes == NULL) {
         /* No included services. */
         return 1;
     }
 
-    for (incl = *svc->includes; incl != NULL; incl++) {
-        idx = ble_gatts_find_svc(incl);
-        if (idx == -1) {
+    for (i = 0; svc->includes[i] != NULL; i++) {
+        idx = ble_gatts_find_svc(svc->includes[i]);
+        if (idx == -1 || ble_gatts_svc_entries[idx].handle == 0) {
             return 0;
         }
     }
@@ -228,7 +214,7 @@ ble_gatts_register_inc(struct ble_gatts_svc_entry *entry)
     int rc;
 
     assert(entry->handle != 0);
-    assert(entry->end_group_handle != 0);
+    assert(entry->end_group_handle != 0xffff);
 
     rc = ble_att_svr_register(entry->svc->uuid128, HA_FLAG_PERM_READ,
                               &handle, ble_gatts_inc_access, entry);
@@ -239,28 +225,94 @@ ble_gatts_register_inc(struct ble_gatts_svc_entry *entry)
     return 0;
 }
 
+static uint8_t
+ble_gatts_dsc_op(uint8_t att_op)
+{
+    switch (att_op) {
+    case BLE_ATT_ACCESS_OP_READ:
+        return BLE_GATT_ACCESS_OP_READ_DSC;
+
+    case BLE_ATT_ACCESS_OP_WRITE:
+        return BLE_GATT_ACCESS_OP_WRITE_DSC;
+
+    default:
+        assert(0);
+        return BLE_GATT_ACCESS_OP_READ_DSC;
+    }
+}
+
+static int
+ble_gatts_dsc_access(uint16_t handle_id, uint8_t *uuid128, uint8_t att_op,
+                     union ble_att_svr_access_ctxt *att_ctxt, void *arg)
+{
+    const struct ble_gatt_dsc_def *dsc;
+    union ble_gatt_access_ctxt gatt_ctxt;
+    uint8_t gatt_op;
+    int rc;
+
+    dsc = arg;
+    assert(dsc != NULL && dsc->access_cb != NULL);
+
+    gatt_op = ble_gatts_dsc_op(att_op);
+    gatt_ctxt.dsc_access.dsc = dsc;
+    gatt_ctxt.dsc_access.data = att_ctxt->rw.attr_data;
+    gatt_ctxt.dsc_access.len = att_ctxt->rw.attr_len;
+
+    rc = dsc->access_cb(handle_id, gatt_op, &gatt_ctxt, dsc->arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    att_ctxt->rw.attr_len = gatt_ctxt.dsc_access.len;
+
+    rc = dsc->access_cb(handle_id, gatt_op, &gatt_ctxt, dsc->arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+ble_gatts_dsc_is_sane(const struct ble_gatt_dsc_def *dsc)
+{
+    if (dsc->uuid128 == NULL) {
+        return 0;
+    }
+
+    if (dsc->access_cb == NULL) {
+        return 0;
+    }
+
+    return 1;
+}
+
 static int
 ble_gatts_register_dsc(const struct ble_gatt_dsc_def *dsc,
                        const struct ble_gatt_chr_def *chr,
                        uint16_t chr_def_handle,
-                       ble_gatt_register_fn *register_cb)
+                       ble_gatt_register_fn *register_cb, void *cb_arg)
 {
     union ble_gatt_register_ctxt register_ctxt;
     uint16_t dsc_handle;
     int rc;
 
+    if (!ble_gatts_dsc_is_sane(dsc)) {
+        return BLE_HS_EINVAL;
+    }
+
     rc = ble_att_svr_register(dsc->uuid128, dsc->att_flags, &dsc_handle,
-                              dsc->access_cb, (void *)dsc->arg);
+                              ble_gatts_dsc_access, (void *)dsc);
     if (rc != 0) {
         return rc;
     }
 
     if (register_cb != NULL) {
-        register_ctxt.bgr_dsc.dsc_handle = dsc_handle;
-        register_ctxt.bgr_dsc.dsc = dsc;
-        register_ctxt.bgr_dsc.chr_def_handle = chr_def_handle;
-        register_ctxt.bgr_dsc.chr = chr;
-        register_cb(BLE_GATT_REGISTER_OP_DSC, &register_ctxt);
+        register_ctxt.dsc_reg.dsc_handle = dsc_handle;
+        register_ctxt.dsc_reg.dsc = dsc;
+        register_ctxt.dsc_reg.chr_def_handle = chr_def_handle;
+        register_ctxt.dsc_reg.chr = chr;
+        register_cb(BLE_GATT_REGISTER_OP_DSC, &register_ctxt, cb_arg);
     }
 
     return 0;
@@ -269,7 +321,7 @@ ble_gatts_register_dsc(const struct ble_gatt_dsc_def *dsc,
 
 static int
 ble_gatts_register_chr(const struct ble_gatt_chr_def *chr,
-                       ble_gatt_register_fn *register_cb)
+                       ble_gatt_register_fn *register_cb, void *cb_arg)
 {
     union ble_gatt_register_ctxt register_ctxt;
     struct ble_gatt_dsc_def *dsc;
@@ -277,6 +329,10 @@ ble_gatts_register_chr(const struct ble_gatt_chr_def *chr,
     uint16_t val_handle;
     int rc;
 
+    if (!ble_gatts_chr_is_sane(chr)) {
+        return BLE_HS_EINVAL;
+    }
+
     /* Register characteristic declaration attribute (cast away const on
      * callback arg).
      */
@@ -299,16 +355,17 @@ ble_gatts_register_chr(const struct ble_gatt_chr_def *chr,
     assert(val_handle == def_handle + 1);
 
     if (register_cb != NULL) {
-        register_ctxt.bgr_chr.def_handle = def_handle;
-        register_ctxt.bgr_chr.val_handle = val_handle;
-        register_ctxt.bgr_chr.chr = chr;
-        register_cb(BLE_GATT_REGISTER_OP_CHR, &register_ctxt);
+        register_ctxt.chr_reg.def_handle = def_handle;
+        register_ctxt.chr_reg.val_handle = val_handle;
+        register_ctxt.chr_reg.chr = chr;
+        register_cb(BLE_GATT_REGISTER_OP_CHR, &register_ctxt, cb_arg);
     }
 
     /* Register each descriptor. */
     if (chr->descriptors != NULL) {
         for (dsc = chr->descriptors; dsc->uuid128 != NULL; dsc++) {
-            rc = ble_gatts_register_dsc(dsc, chr, def_handle, register_cb);
+            rc = ble_gatts_register_dsc(dsc, chr, def_handle, register_cb,
+                                        cb_arg);
             if (rc != 0) {
                 return rc;
             }
@@ -336,26 +393,44 @@ ble_gatts_svc_type_to_uuid(uint8_t svc_type, uint16_t *out_uuid16)
 }
 
 static int
+ble_gatts_svc_is_sane(const struct ble_gatt_svc_def *svc)
+{
+    if (svc->type != BLE_GATT_SVC_TYPE_PRIMARY &&
+        svc->type != BLE_GATT_SVC_TYPE_SECONDARY) {
+
+        return 0;
+    }
+
+    if (svc->uuid128 == NULL) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static int
 ble_gatts_register_svc(const struct ble_gatt_svc_def *svc,
                        uint16_t *out_handle,
-                       ble_gatt_register_fn *register_cb)
+                       ble_gatt_register_fn *register_cb, void *cb_arg)
 {
-    const struct ble_gatt_svc_def *incl;
     const struct ble_gatt_chr_def *chr;
     union ble_gatt_register_ctxt register_ctxt;
     uint16_t uuid16;
     int idx;
     int rc;
+    int i;
 
     if (!ble_gatts_svc_incs_satisfied(svc)) {
         return BLE_HS_EAGAIN;
     }
 
-    rc = ble_gatts_svc_type_to_uuid(svc->type, &uuid16);
-    if (rc != 0) {
-        return rc;
+    if (!ble_gatts_svc_is_sane(svc)) {
+        return BLE_HS_EINVAL;
     }
 
+    rc = ble_gatts_svc_type_to_uuid(svc->type, &uuid16);
+    assert(rc == 0);
+
     /* Register service definition attribute (cast away const on callback
      * arg).
      */
@@ -366,15 +441,15 @@ ble_gatts_register_svc(const struct ble_gatt_svc_def *svc,
     }
 
     if (register_cb != NULL) {
-        register_ctxt.bgr_svc.handle = *out_handle;
-        register_ctxt.bgr_svc.svc = svc;
-        register_cb(BLE_GATT_REGISTER_OP_SVC, &register_ctxt);
+        register_ctxt.svc_reg.handle = *out_handle;
+        register_ctxt.svc_reg.svc = svc;
+        register_cb(BLE_GATT_REGISTER_OP_SVC, &register_ctxt, cb_arg);
     }
 
     /* Register each include. */
     if (svc->includes != NULL) {
-        for (incl = *svc->includes; incl != NULL; incl++) {
-            idx = ble_gatts_find_svc(incl);
+        for (i = 0; svc->includes[i] != NULL; i++) {
+            idx = ble_gatts_find_svc(svc->includes[i]);
             assert(idx != -1);
 
             rc = ble_gatts_register_inc(ble_gatts_svc_entries + idx);
@@ -387,19 +462,19 @@ ble_gatts_register_svc(const struct ble_gatt_svc_def *svc,
     /* Register each characteristic. */
     if (svc->characteristics != NULL) {
         for (chr = svc->characteristics; chr->uuid128 != NULL; chr++) {
-            rc = ble_gatts_register_chr(chr, register_cb);
+            rc = ble_gatts_register_chr(chr, register_cb, cb_arg);
             if (rc != 0) {
                 return rc;
             }
         }
-
     }
 
     return 0;
 }
 
 static int
-ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb)
+ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb,
+                         void *cb_arg)
 {
     struct ble_gatts_svc_entry *entry;
     uint16_t handle;
@@ -411,11 +486,12 @@ ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb)
         entry = ble_gatts_svc_entries + i;
 
         if (entry->handle == 0) {
-            rc = ble_gatts_register_svc(entry->svc, &handle, cb);
+            rc = ble_gatts_register_svc(entry->svc, &handle, cb, cb_arg);
             switch (rc) {
             case 0:
                 /* Service successfully registered. */
                 entry->handle = handle;
+                entry->end_group_handle = ble_att_svr_prev_handle();
                 (*out_num_registered)++;
                 break;
 
@@ -432,7 +508,8 @@ ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb)
     }
 
     if (*out_num_registered == 0) {
-        return BLE_HS_EAPP; // XXX
+        /* There is a circular dependency. */
+        return BLE_HS_EINVAL;
     }
 
     return 0;
@@ -440,7 +517,7 @@ ble_gatts_register_round(int *out_num_registered, ble_gatt_register_fn *cb)
 
 int
 ble_gatts_register_services(const struct ble_gatt_svc_def *svcs,
-                            ble_gatt_register_fn *cb)
+                            ble_gatt_register_fn *cb, void *cb_arg)
 {
     int total_registered;
     int cur_registered;
@@ -450,12 +527,13 @@ ble_gatts_register_services(const struct ble_gatt_svc_def *svcs,
     for (i = 0; svcs[i].type != BLE_GATT_SVC_TYPE_END; i++) {
         ble_gatts_svc_entries[i].svc = svcs + i;
         ble_gatts_svc_entries[i].handle = 0;
+        ble_gatts_svc_entries[i].end_group_handle = 0xffff;
     }
     ble_gatts_num_svc_entries = i;
 
     total_registered = 0;
     while (total_registered < ble_gatts_num_svc_entries) {
-        rc = ble_gatts_register_round(&cur_registered, cb);
+        rc = ble_gatts_register_round(&cur_registered, cb, cb_arg);
         if (rc != 0) {
             return rc;
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/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 1492349..efcbe75 100644
--- a/net/nimble/host/src/test/ble_att_svr_test.c
+++ b/net/nimble/host/src/test/ble_att_svr_test.c
@@ -64,8 +64,8 @@ ble_att_svr_test_misc_attr_fn_r_1(uint16_t handle_id, uint8_t *uuid128,
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_READ:
-        ctxt->ahc_read.attr_data = ble_att_svr_test_attr_r_1;
-        ctxt->ahc_read.attr_len = ble_att_svr_test_attr_r_1_len;
+        ctxt->rw.attr_data = ble_att_svr_test_attr_r_1;
+        ctxt->rw.attr_len = ble_att_svr_test_attr_r_1_len;
         return 0;
 
     default:
@@ -81,8 +81,8 @@ ble_att_svr_test_misc_attr_fn_r_2(uint16_t handle_id, uint8_t *uuid128,
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_READ:
-        ctxt->ahc_read.attr_data = ble_att_svr_test_attr_r_2;
-        ctxt->ahc_read.attr_len = ble_att_svr_test_attr_r_2_len;
+        ctxt->rw.attr_data = ble_att_svr_test_attr_r_2;
+        ctxt->rw.attr_len = ble_att_svr_test_attr_r_2_len;
         return 0;
 
     default:
@@ -130,11 +130,11 @@ ble_att_svr_test_misc_attr_fn_r_group(uint16_t handle_id, uint8_t *uuid128,
 
     TEST_ASSERT_FATAL(handle_id >= 1 && handle_id <= 22);
 
-    ctxt->ahc_read.attr_data = vals + handle_id;
-    if (memcmp(ctxt->ahc_read.attr_data + 2, zeros, 14) == 0) {
-        ctxt->ahc_read.attr_len = 2;
+    ctxt->rw.attr_data = vals + handle_id;
+    if (memcmp(ctxt->rw.attr_data + 2, zeros, 14) == 0) {
+        ctxt->rw.attr_len = 2;
     } else {
-        ctxt->ahc_read.attr_len = 16;
+        ctxt->rw.attr_len = 16;
     }
 
     return 0;
@@ -228,9 +228,9 @@ ble_att_svr_test_misc_attr_fn_w_1(uint16_t handle_id, uint8_t *uuid128,
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_WRITE:
-        memcpy(ble_att_svr_test_attr_w_1, ctxt->ahc_write.attr_data,
-               ctxt->ahc_write.attr_len);
-        ble_att_svr_test_attr_w_1_len = ctxt->ahc_write.attr_len;
+        memcpy(ble_att_svr_test_attr_w_1, ctxt->rw.attr_data,
+               ctxt->rw.attr_len);
+        ble_att_svr_test_attr_w_1_len = ctxt->rw.attr_len;
         return 0;
 
     default:
@@ -246,9 +246,9 @@ ble_att_svr_test_misc_attr_fn_w_2(uint16_t handle_id, uint8_t *uuid128,
 {
     switch (op) {
     case BLE_ATT_ACCESS_OP_WRITE:
-        memcpy(ble_att_svr_test_attr_w_2, ctxt->ahc_write.attr_data,
-               ctxt->ahc_write.attr_len);
-        ble_att_svr_test_attr_w_2_len = ctxt->ahc_write.attr_len;
+        memcpy(ble_att_svr_test_attr_w_2, ctxt->rw.attr_data,
+               ctxt->rw.attr_len);
+        ble_att_svr_test_attr_w_2_len = ctxt->rw.attr_len;
         return 0;
 
     default:

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/net/nimble/host/src/test/ble_hs_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test.c b/net/nimble/host/src/test/ble_hs_test.c
index 100594b..01ed329 100644
--- a/net/nimble/host/src/test/ble_hs_test.c
+++ b/net/nimble/host/src/test/ble_hs_test.c
@@ -62,6 +62,7 @@ main(void)
     ble_gatt_write_test_all();
     ble_gatt_conn_test_all();
     ble_hs_adv_test_all();
+    ble_gatts_reg_test_all();
 
     return tu_any_failed;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/10480cfc/project/prphtest/src/main.c
----------------------------------------------------------------------
diff --git a/project/prphtest/src/main.c b/project/prphtest/src/main.c
index 3646305..7aeec49 100755
--- a/project/prphtest/src/main.c
+++ b/project/prphtest/src/main.c
@@ -128,24 +128,24 @@ prphtest_gatt_cb(uint16_t handle_id, uint8_t op,
 
     assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
 
-    uuid16 = ble_uuid_128_to_16(ctxt->bgc_read.chr->uuid128);
+    uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
     switch (uuid16) {
     case PRPHTEST_CHR1_UUID:
         console_printf("reading characteristic1 value");
         memcpy(buf, "char1", 5);
-        ctxt->bgc_read.chr_len = 5;
+        ctxt->chr_access.len = 5;
         break;
 
     case PRPHTEST_CHR2_UUID:
         console_printf("reading characteristic2 value");
         memcpy(buf, "char2", 5);
-        ctxt->bgc_read.chr_len = 5;
+        ctxt->chr_access.len = 5;
         break;
 
     case PRPHTEST_CHR3_UUID:
         console_printf("reading characteristic3 value");
         memcpy(buf, "char3", 5);
-        ctxt->bgc_read.chr_len = 5;
+        ctxt->chr_access.len = 5;
         break;
 
     default:
@@ -153,31 +153,31 @@ prphtest_gatt_cb(uint16_t handle_id, uint8_t op,
         break;
     }
 
-    ctxt->bgc_read.chr_data = buf;
+    ctxt->chr_access.data = buf;
 
     return 0;
 }
 
 static void
-prphtest_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt)
+prphtest_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg)
 {
     uint16_t uuid16;
 
     switch (op) {
     case BLE_GATT_REGISTER_OP_SVC:
-        uuid16 = ble_uuid_128_to_16(ctxt->bgr_svc.svc->uuid128);
+        uuid16 = ble_uuid_128_to_16(ctxt->svc_reg.svc->uuid128);
         assert(uuid16 != 0);
         console_printf("registered service 0x%04x with handle=%d\n",
-                       uuid16, ctxt->bgr_svc.handle);
+                       uuid16, ctxt->svc_reg.handle);
         break;
 
     case BLE_GATT_REGISTER_OP_CHR:
-        uuid16 = ble_uuid_128_to_16(ctxt->bgr_chr.chr->uuid128);
+        uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128);
         assert(uuid16 != 0);
         console_printf("registering characteristic 0x%04x with def_handle=%d "
                        "val_handle=%d\n",
-                       uuid16, ctxt->bgr_chr.def_handle,
-                       ctxt->bgr_chr.val_handle);
+                       uuid16, ctxt->chr_reg.def_handle,
+                       ctxt->chr_reg.val_handle);
         break;
 
     default:
@@ -191,7 +191,7 @@ prphtest_register_attrs(void)
 {
     int rc;
 
-    rc = ble_gatt_register_services(prphtest_svcs, prphtest_register_cb);
+    rc = ble_gatt_register_services(prphtest_svcs, prphtest_register_cb, NULL);
     assert(rc == 0);
 }