diff --git a/src/gatt-database.c b/src/gatt-database.c
index cca70c9..c86f247 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
struct queue *ccc_callbacks;
struct gatt_db_attribute *svc_chngd;
struct gatt_db_attribute *svc_chngd_ccc;
+ struct gatt_db_attribute *cli_feat;
+ struct gatt_db_attribute *db_hash;
struct queue *apps;
struct queue *profiles;
};
bdaddr_t bdaddr;
uint8_t bdaddr_type;
unsigned int disc_id;
+ uint8_t cli_feat[1];
struct queue *ccc_states;
struct notify *pending;
};
return ccc;
}
+static void cli_feat_read_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct btd_gatt_database *database = user_data;
+ struct device_state *state;
+ uint8_t ecode = 0;
+ const uint8_t *value = NULL;
+ size_t len = 0;
+
+ DBG("Client Features read");
+
+ state = get_device_state(database, att);
+ if (!state) {
+ ecode = BT_ATT_ERROR_UNLIKELY;
+ goto done;
+ }
+
+ len = sizeof(state->cli_feat) - offset;
+ value = len ? &state->cli_feat[offset] : NULL;
+
+done:
+ gatt_db_attribute_read_result(attrib, id, ecode, value, len);
+}
+
+static void cli_feat_write_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct btd_gatt_database *database = user_data;
+ struct device_state *state;
+ uint8_t ecode = 0;
+
+ DBG("Client Features write");
+
+ state = get_device_state(database, att);
+ if (!state) {
+ ecode = BT_ATT_ERROR_UNLIKELY;
+ goto done;
+ }
+
+ if (!value || !len) {
+ ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+ goto done;
+ }
+
+ /* A client shall never clear a bit it has set.
+ * TODO: make it generic to any bits.
+ */
+ if (state->cli_feat[0] & BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING &&
+ !(value[0] & BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING)) {
+ ecode = BT_ATT_ERROR_VALUE_NOT_ALLOWED;
+ goto done;
+ }
+
+ /* Shall we reallocate the feat array if bigger? */
+ len = MIN(sizeof(state->cli_feat), len);
+ while (len) {
+ state->cli_feat[len - 1] |= value[len -1];
+ len--;
+ }
+
+done:
+ gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
+static void db_hash_read_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct btd_gatt_database *database = user_data;
+ const uint8_t *hash;
+
+ DBG("Database Hash read");
+
+ hash = gatt_db_get_hash(database->db);
+
+ gatt_db_attribute_read_result(attrib, id, 0, hash, 16);
+}
+
static void populate_gatt_service(struct btd_gatt_database *database)
{
bt_uuid_t uuid;
/* Add the GATT service */
bt_uuid16_create(&uuid, UUID_GATT);
- service = gatt_db_add_service(database->db, &uuid, true, 4);
+ service = gatt_db_add_service(database->db, &uuid, true, 8);
bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
NULL);
+ bt_uuid16_create(&uuid, GATT_CHARAC_CLI_FEAT);
+ database->cli_feat = gatt_db_service_add_characteristic(service,
+ &uuid, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ BT_GATT_CHRC_PROP_READ |
+ BT_GATT_CHRC_PROP_WRITE,
+ cli_feat_read_cb, cli_feat_write_cb,
+ database);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_DB_HASH);
+ database->db_hash = gatt_db_service_add_characteristic(service,
+ &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+ db_hash_read_cb, NULL, database);
+
gatt_db_service_set_active(service, true);
database_add_record(database, service);
}
+
static void register_core_services(struct btd_gatt_database *database)
{
populate_gap_service(database);