diff --git a/src/gatt-database.c b/src/gatt-database.c
index db21d49..8cca422 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
uint8_t props;
uint8_t ext_props;
struct gatt_db_attribute *attrib;
+ struct gatt_db_attribute *ccc;
struct queue *pending_reads;
struct queue *pending_writes;
+ unsigned int ntfy_cnt;
};
struct pending_op {
return;
}
- /*
- * TODO: Determine descriptors count to add based on special
- * characteristic properties (e.g. extended properties).
- */
+ if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+ chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
+ !incr_attr_count(service, 1)) {
+ error("Failed to increment attribute count for CCC");
+ service->failed = true;
+ return;
+ }
queue_push_tail(service->chrcs, chrc);
} else
return perm;
}
+static uint8_t ccc_write_cb(uint16_t value, void *user_data)
+{
+ struct external_chrc *chrc = user_data;
+
+ DBG("External CCC write received with value: 0x%04x", value);
+
+ /* Notifications/indications disabled */
+ if (!value) {
+ if (!chrc->ntfy_cnt)
+ return 0;
+
+ if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
+ return 0;
+
+ /*
+ * Send request to stop notifying. This is best-effort
+ * operation, so simply ignore the return the value.
+ */
+ g_dbus_proxy_method_call(chrc->proxy, "StopNotify", NULL,
+ NULL, NULL, NULL);
+ return 0;
+ }
+
+ /*
+ * TODO: All of the errors below should fall into the so called
+ * "Application Error" range. Since there is no well defined error for
+ * these, we return a generic ATT protocol error for now.
+ */
+
+ if (chrc->ntfy_cnt == UINT_MAX) {
+ /* Maximum number of per-device CCC descriptors configured */
+ return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+ }
+
+ /* Don't support undefined CCC values yet */
+ if (value > 2 ||
+ (value == 1 && !(chrc->props & BT_GATT_CHRC_PROP_NOTIFY)) ||
+ (value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
+ return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+ /*
+ * Always call StartNotify for an incoming enable and ignore the return
+ * value for now.
+ */
+ if (g_dbus_proxy_method_call(chrc->proxy,
+ "StartNotify", NULL, NULL,
+ NULL, NULL) == FALSE)
+ return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+ __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
+
+ return 0;
+}
+
+static bool database_add_ccc(struct external_service *service,
+ struct external_chrc *chrc)
+{
+ chrc->ccc = service_add_ccc(service->attrib, service->database,
+ ccc_write_cb, chrc, NULL);
+ if (!chrc->ccc) {
+ error("Failed to create CCC entry for characteristic");
+ return false;
+ }
+
+ return true;
+}
+
static bool database_add_chrc(struct external_service *service,
struct external_chrc *chrc)
{
&uuid, perm,
chrc->props, chrc_read_cb,
chrc_write_cb, chrc);
+ if (!chrc->attrib) {
+ error("Failed to create characteristic entry in database");
+ return false;
+ }
- /* TODO: Create descriptor entries */
+ if (chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+ chrc->props & BT_GATT_CHRC_PROP_INDICATE)
+ return database_add_ccc(service, chrc);
- return chrc->attrib != NULL;
+ return true;
}
static bool create_service_entry(struct external_service *service)