summaryrefslogtreecommitdiff
path: root/src/device.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2022-05-11 15:33:27 -0700
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2022-05-18 15:35:45 -0700
commit02017e320b4d503b2686e08188a41644c87faac0 (patch)
tree09db4bcad4cdb39e79bca2e151fd6e3607271b6a /src/device.c
parentc159d790e8786581cfa5e5a9e7bd71458a343e44 (diff)
downloadbluez-02017e320b4d503b2686e08188a41644c87faac0.tar.gz
settings: Add btd_settings_gatt_db_{store,load}
This adds helper functions to store and load from/to file so they can get reused by the likes of gatt-database.c and btmon.
Diffstat (limited to 'src/device.c')
-rw-r--r--src/device.c497
1 files changed, 10 insertions, 487 deletions
diff --git a/src/device.c b/src/device.c
index 638bad061..0d7c62c9c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -63,6 +63,7 @@
#include "textfile.h"
#include "storage.h"
#include "eir.h"
+#include "settings.h"
#define DISCONNECT_TIMER 2
#define DISCOVERY_TIMER 1
@@ -74,11 +75,6 @@
#define RSSI_THRESHOLD 8
-#define GATT_PRIM_SVC_UUID_STR "2800"
-#define GATT_SND_SVC_UUID_STR "2801"
-#define GATT_INCLUDE_UUID_STR "2802"
-#define GATT_CHARAC_UUID_STR "2803"
-
static DBusConnection *dbus_conn = NULL;
static unsigned service_state_cb_id;
@@ -2517,171 +2513,10 @@ static void store_services(struct btd_device *device)
g_key_file_free(key_file);
}
-struct gatt_saver {
- struct btd_device *device;
- uint16_t ext_props;
- GKeyFile *key_file;
-};
-
-static void db_hash_read_value_cb(struct gatt_db_attribute *attrib,
- int err, const uint8_t *value,
- size_t length, void *user_data)
-{
- const uint8_t **hash = user_data;
-
- if (err || (length != 16))
- return;
-
- *hash = value;
-}
-
-static void store_desc(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gatt_saver *saver = user_data;
- GKeyFile *key_file = saver->key_file;
- char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
- const bt_uuid_t *uuid;
- bt_uuid_t ext_uuid;
- uint16_t handle_num;
-
- handle_num = gatt_db_attribute_get_handle(attr);
- sprintf(handle, "%04hx", handle_num);
-
- uuid = gatt_db_attribute_get_type(attr);
- bt_uuid_to_string(uuid, uuid_str, sizeof(uuid_str));
-
- bt_uuid16_create(&ext_uuid, GATT_CHARAC_EXT_PROPER_UUID);
- if (!bt_uuid_cmp(uuid, &ext_uuid) && saver->ext_props)
- sprintf(value, "%04hx:%s", saver->ext_props, uuid_str);
- else
- sprintf(value, "%s", uuid_str);
-
- g_key_file_set_string(key_file, "Attributes", handle, value);
-}
-
-static void store_chrc(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gatt_saver *saver = user_data;
- GKeyFile *key_file = saver->key_file;
- char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
- uint16_t handle_num, value_handle;
- uint8_t properties;
- bt_uuid_t uuid, hash_uuid;
-
- if (!gatt_db_attribute_get_char_data(attr, &handle_num, &value_handle,
- &properties, &saver->ext_props,
- &uuid)) {
- warn("Error storing characteristic - can't get data");
- return;
- }
-
- sprintf(handle, "%04hx", handle_num);
- bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
-
- /* Store Database Hash value if available */
- bt_uuid16_create(&hash_uuid, GATT_CHARAC_DB_HASH);
- if (!bt_uuid_cmp(&uuid, &hash_uuid)) {
- const uint8_t *hash = NULL;
-
- attr = gatt_db_get_attribute(saver->device->db, value_handle);
-
- gatt_db_attribute_read(attr, 0, BT_ATT_OP_READ_REQ, NULL,
- db_hash_read_value_cb, &hash);
- if (hash)
- sprintf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hhx:"
- "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
- "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
- "%02hhx%02hhx:%s", value_handle, properties,
- hash[0], hash[1], hash[2], hash[3],
- hash[4], hash[5], hash[6], hash[7],
- hash[8], hash[9], hash[10], hash[11],
- hash[12], hash[13], hash[14], hash[15],
- uuid_str);
- else
- sprintf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hhx:%s",
- value_handle, properties, uuid_str);
-
- } else
- sprintf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hhx:%s",
- value_handle, properties, uuid_str);
-
- g_key_file_set_string(key_file, "Attributes", handle, value);
-
- gatt_db_service_foreach_desc(attr, store_desc, saver);
-}
-
-static void store_incl(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gatt_saver *saver = user_data;
- GKeyFile *key_file = saver->key_file;
- struct gatt_db_attribute *service;
- char handle[6], value[100], uuid_str[MAX_LEN_UUID_STR];
- uint16_t handle_num, start, end;
- bt_uuid_t uuid;
-
- if (!gatt_db_attribute_get_incl_data(attr, &handle_num, &start, &end)) {
- warn("Error storing included service - can't get data");
- return;
- }
-
- service = gatt_db_get_attribute(saver->device->db, start);
- if (!service) {
- warn("Error storing included service - can't find it");
- return;
- }
-
- sprintf(handle, "%04hx", handle_num);
-
- gatt_db_attribute_get_service_uuid(service, &uuid);
- bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
- sprintf(value, GATT_INCLUDE_UUID_STR ":%04hx:%04hx:%s", start,
- end, uuid_str);
-
- g_key_file_set_string(key_file, "Attributes", handle, value);
-}
-
-static void store_service(struct gatt_db_attribute *attr, void *user_data)
-{
- struct gatt_saver *saver = user_data;
- GKeyFile *key_file = saver->key_file;
- char uuid_str[MAX_LEN_UUID_STR], handle[6], value[256];
- uint16_t start, end;
- bt_uuid_t uuid;
- bool primary;
- char *type;
-
- if (!gatt_db_attribute_get_service_data(attr, &start, &end, &primary,
- &uuid)) {
- warn("Error storing service - can't get data");
- return;
- }
-
- sprintf(handle, "%04hx", start);
-
- bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
-
- if (primary)
- type = GATT_PRIM_SVC_UUID_STR;
- else
- type = GATT_SND_SVC_UUID_STR;
-
- sprintf(value, "%s:%04hx:%s", type, end, uuid_str);
-
- g_key_file_set_string(key_file, "Attributes", handle, value);
-
- gatt_db_service_foreach_incl(attr, store_incl, saver);
- gatt_db_service_foreach_char(attr, store_chrc, saver);
-}
-
static void store_gatt_db(struct btd_device *device)
{
char filename[PATH_MAX];
char dst_addr[18];
- GKeyFile *key_file;
- GError *gerr = NULL;
- char *data;
- gsize length = 0;
- struct gatt_saver saver;
if (device_address_is_private(device)) {
DBG("Can't store GATT db for private addressed device %s",
@@ -2699,33 +2534,9 @@ static void store_gatt_db(struct btd_device *device)
dst_addr);
create_file(filename, 0600);
- key_file = g_key_file_new();
- if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) {
- error("Unable to load key file from %s: (%s)", filename,
- gerr->message);
- g_clear_error(&gerr);
- }
-
- /* Remove current attributes since it might have changed */
- g_key_file_remove_group(key_file, "Attributes", NULL);
-
- saver.key_file = key_file;
- saver.device = device;
-
- gatt_db_foreach_service(device->db, NULL, store_service, &saver);
-
- data = g_key_file_to_data(key_file, &length, NULL);
- if (!g_file_set_contents(filename, data, length, &gerr)) {
- error("Unable set contents for %s: (%s)", filename,
- gerr->message);
- g_error_free(gerr);
- }
-
- g_free(data);
- g_key_file_free(key_file);
+ btd_settings_gatt_db_store(device->db, filename);
}
-
static void browse_request_complete(struct browse_req *req, uint8_t type,
uint8_t bdaddr_type, int err)
{
@@ -3797,288 +3608,11 @@ static void add_primary(struct gatt_db_attribute *attr, void *user_data)
*new_services = g_slist_append(*new_services, prim);
}
-static void load_desc_value(struct gatt_db_attribute *attrib,
- int err, void *user_data)
-{
- if (err)
- warn("loading descriptor value to db failed");
-}
-
-static ssize_t str2val(const char *str, uint8_t *val, size_t len)
-{
- const char *pos = str;
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (sscanf(pos, "%2hhx", &val[i]) != 1)
- break;
- pos += 2;
- }
-
- return i;
-}
-
-static int load_desc(char *handle, char *value,
- struct gatt_db_attribute *service)
-{
- char uuid_str[MAX_LEN_UUID_STR];
- struct gatt_db_attribute *att;
- uint16_t handle_int;
- uint16_t val;
- bt_uuid_t uuid, ext_uuid;
-
- if (sscanf(handle, "%04hx", &handle_int) != 1)
- return -EIO;
-
- /* Check if there is any value stored, otherwise it is just the UUID */
- if (sscanf(value, "%04hx:%36s", &val, uuid_str) != 2) {
- if (sscanf(value, "%36s", uuid_str) != 1)
- return -EIO;
- val = 0;
- }
-
- DBG("loading descriptor handle: 0x%04x, value: 0x%04x, value uuid: %s",
- handle_int, val, uuid_str);
-
- bt_string_to_uuid(&uuid, uuid_str);
- bt_uuid16_create(&ext_uuid, GATT_CHARAC_EXT_PROPER_UUID);
-
- /* If it is CEP then it must contain the value */
- if (!bt_uuid_cmp(&uuid, &ext_uuid) && !val) {
- warn("cannot load CEP descriptor without value");
- return -EIO;
- }
-
- att = gatt_db_service_insert_descriptor(service, handle_int, &uuid,
- 0, NULL, NULL, NULL);
- if (!att || gatt_db_attribute_get_handle(att) != handle_int) {
- warn("loading descriptor to db failed");
- return -EIO;
- }
-
- if (val) {
- if (!gatt_db_attribute_write(att, 0, (uint8_t *)&val,
- sizeof(val), 0, NULL,
- load_desc_value, NULL))
- return -EIO;
- }
-
- return 0;
-}
-
-static int load_chrc(char *handle, char *value,
- struct gatt_db_attribute *service)
-{
- uint16_t properties, value_handle, handle_int;
- char uuid_str[MAX_LEN_UUID_STR];
- struct gatt_db_attribute *att;
- char val_str[33];
- uint8_t val[16];
- size_t val_len;
- bt_uuid_t uuid;
-
- if (sscanf(handle, "%04hx", &handle_int) != 1)
- return -EIO;
-
- /* Check if there is any value stored */
- if (sscanf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hx:%32s:%36s",
- &value_handle, &properties, val_str, uuid_str) != 4) {
- if (sscanf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hx:%36s",
- &value_handle, &properties, uuid_str) != 3)
- return -EIO;
- val_len = 0;
- } else
- val_len = str2val(val_str, val, sizeof(val));
-
- bt_string_to_uuid(&uuid, uuid_str);
-
- /* Log debug message. */
- DBG("loading characteristic handle: 0x%04x, value handle: 0x%04x,"
- " properties 0x%04x value: %s uuid: %s",
- handle_int, value_handle, properties,
- val_len ? val_str : "", uuid_str);
-
- att = gatt_db_service_insert_characteristic(service, value_handle,
- &uuid, 0, properties,
- NULL, NULL, NULL);
- if (!att || gatt_db_attribute_get_handle(att) != value_handle) {
- warn("loading characteristic to db failed");
- return -EIO;
- }
-
- if (val_len) {
- if (!gatt_db_attribute_write(att, 0, val, val_len, 0, NULL,
- load_desc_value, NULL))
- return -EIO;
- }
-
- return 0;
-}
-
-static int load_incl(struct gatt_db *db, char *handle, char *value,
- struct gatt_db_attribute *service)
-{
- char uuid_str[MAX_LEN_UUID_STR];
- struct gatt_db_attribute *att;
- uint16_t start, end;
-
- if (sscanf(handle, "%04hx", &start) != 1)
- return -EIO;
-
- if (sscanf(value, GATT_INCLUDE_UUID_STR ":%04hx:%04hx:%36s", &start,
- &end, uuid_str) != 3)
- return -EIO;
-
- /* Log debug message. */
- DBG("loading included service: 0x%04x, end: 0x%04x, uuid: %s", start,
- end, uuid_str);
-
- att = gatt_db_get_attribute(db, start);
- if (!att) {
- warn("loading included service to db failed - no such service");
- return -EIO;
- }
-
- att = gatt_db_service_add_included(service, att);
- if (!att) {
- warn("loading included service to db failed");
- return -EIO;
- }
-
- return 0;
-}
-
-static int load_service(struct gatt_db *db, char *handle, char *value)
-{
- struct gatt_db_attribute *att;
- uint16_t start, end;
- char type[MAX_LEN_UUID_STR], uuid_str[MAX_LEN_UUID_STR];
- bt_uuid_t uuid;
- bool primary;
-
- if (sscanf(handle, "%04hx", &start) != 1)
- return -EIO;
-
- if (sscanf(value, "%[^:]:%04hx:%36s", type, &end, uuid_str) != 3)
- return -EIO;
-
- if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR))
- primary = true;
- else if (g_str_equal(type, GATT_SND_SVC_UUID_STR))
- primary = false;
- else
- return -EIO;
-
- bt_string_to_uuid(&uuid, uuid_str);
-
- /* Log debug message. */
- DBG("loading service: 0x%04x, end: 0x%04x, uuid: %s",
- start, end, uuid_str);
-
- att = gatt_db_insert_service(db, start, &uuid, primary,
- end - start + 1);
- if (!att) {
- error("Unable load service into db!");
- return -EIO;
- }
-
- return 0;
-}
-
-static int load_gatt_db_impl(GKeyFile *key_file, char **keys,
- struct gatt_db *db)
-{
- struct gatt_db_attribute *current_service;
- char **handle, *value, type[MAX_LEN_UUID_STR];
- int ret;
-
- /* first load service definitions */
- for (handle = keys; *handle; handle++) {
- value = g_key_file_get_string(key_file, "Attributes", *handle,
- NULL);
-
- if (sscanf(value, "%[^:]:", type) != 1) {
- warn("Missing Type in attribute definition");
- g_free(value);
- return -EIO;
- }
-
- if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR) ||
- g_str_equal(type, GATT_SND_SVC_UUID_STR)) {
- ret = load_service(db, *handle, value);
- if (ret) {
- g_free(value);
- return ret;
- }
- }
-
- g_free(value);
- }
-
- current_service = NULL;
- /* then fill them with data*/
- for (handle = keys; *handle; handle++) {
- value = g_key_file_get_string(key_file, "Attributes", *handle,
- NULL);
-
- if (sscanf(value, "%[^:]:", type) != 1) {
- warn("Missing Type in attribute definition");
- g_free(value);
- return -EIO;
- }
-
- if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR) ||
- g_str_equal(type, GATT_SND_SVC_UUID_STR)) {
- uint16_t tmp;
- uint16_t start, end;
- bool primary;
- bt_uuid_t uuid;
- char uuid_str[MAX_LEN_UUID_STR];
-
- if (sscanf(*handle, "%04hx", &tmp) != 1) {
- warn("Unable to parse attribute handle");
- g_free(value);
- return -EIO;
- }
-
- if (current_service)
- gatt_db_service_set_active(current_service,
- true);
-
- current_service = gatt_db_get_attribute(db, tmp);
-
- gatt_db_attribute_get_service_data(current_service,
- &start, &end,
- &primary, &uuid);
-
- bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
- } else if (g_str_equal(type, GATT_INCLUDE_UUID_STR)) {
- ret = load_incl(db, *handle, value, current_service);
- } else if (g_str_equal(type, GATT_CHARAC_UUID_STR)) {
- ret = load_chrc(*handle, value, current_service);
- } else {
- ret = load_desc(*handle, value, current_service);
- }
-
- g_free(value);
- if (ret) {
- gatt_db_clear(db);
- return ret;
- }
- }
-
- if (current_service)
- gatt_db_service_set_active(current_service, true);
-
- return 0;
-}
-
static void load_gatt_db(struct btd_device *device, const char *local,
const char *peer)
{
- char **keys, filename[PATH_MAX];
- GKeyFile *key_file;
- GError *gerr = NULL;
+ char filename[PATH_MAX];
+ int err;
if (!gatt_cache_is_enabled(device))
return;
@@ -4087,26 +3621,15 @@ static void load_gatt_db(struct btd_device *device, const char *local,
create_filename(filename, PATH_MAX, "/%s/cache/%s", local, peer);
- key_file = g_key_file_new();
- if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) {
- error("Unable to load key file from %s: (%s)", filename,
- gerr->message);
- g_error_free(gerr);
- }
- keys = g_key_file_get_keys(key_file, "Attributes", NULL, NULL);
+ err = btd_settings_gatt_db_load(device->db, filename);
+ if (err < 0) {
+ if (err == -ENOENT)
+ return;
- if (!keys) {
- warn("No cache for %s", peer);
- g_key_file_free(key_file);
- return;
+ warn("Error loading db from cache for %s: %s (%d)", peer,
+ strerror(-err), err);
}
- if (load_gatt_db_impl(key_file, keys, device->db))
- warn("Unable to load gatt db from file for %s", peer);
-
- g_strfreev(keys);
- g_key_file_free(key_file);
-
g_slist_free_full(device->primaries, g_free);
device->primaries = NULL;
gatt_db_foreach_service(device->db, NULL, add_primary,