diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2022-05-11 15:33:27 -0700 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2022-05-18 15:35:45 -0700 |
commit | 02017e320b4d503b2686e08188a41644c87faac0 (patch) | |
tree | 09db4bcad4cdb39e79bca2e151fd6e3607271b6a /src/device.c | |
parent | c159d790e8786581cfa5e5a9e7bd71458a343e44 (diff) | |
download | bluez-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.c | 497 |
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, |