Authenticated Boolean True if the key is authenticated
+[ServiceChanged]
+
+ This section holds information related to Service Changed characteristic
+ of GATT core service.
+
+ CCC_LE Integer CCC value for LE transport
+ CCC_BR/EDR Integer CCC value for BR/EDR transport
+
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
[IdentityResolvingKey] group contains:
clear_blocked(adapter);
load_devices(adapter);
+ /* restore Service Changed CCC value for bonded devices */
+ btd_gatt_database_restore_svc_chng_ccc(adapter->database);
+
/* retrieve the active connections: address the scenario where
* the are active connections before the daemon've started */
if (adapter->current_settings & MGMT_SETTING_POWERED)
{
return &device->bdaddr;
}
+uint8_t device_get_le_address_type(struct btd_device *device)
+{
+ return device->bdaddr_type;
+}
const char *device_get_path(const struct btd_device *device)
{
DEVICE_INTERFACE, "LegacyPairing");
}
+void device_store_svc_chng_ccc(struct btd_device *device, uint8_t bdaddr_type,
+ uint16_t value)
+{
+ char filename[PATH_MAX];
+ char device_addr[18];
+ GKeyFile *key_file;
+ uint16_t old_value;
+ gsize length = 0;
+ char *str;
+
+ ba2str(&device->bdaddr, device_addr);
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
+ btd_adapter_get_storage_dir(device->adapter),
+ device_addr);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ /* for bonded devices this is done on every connection so limit writes
+ * to storage if no change needed
+ */
+ if (bdaddr_type == BDADDR_BREDR) {
+ old_value = g_key_file_get_integer(key_file, "ServiceChanged",
+ "CCC_BR/EDR", NULL);
+ if (old_value == value)
+ goto done;
+
+ g_key_file_set_integer(key_file, "ServiceChanged", "CCC_BR/EDR",
+ value);
+ } else {
+ old_value = g_key_file_get_integer(key_file, "ServiceChanged",
+ "CCC_LE", NULL);
+ if (old_value == value)
+ goto done;
+
+ g_key_file_set_integer(key_file, "ServiceChanged", "CCC_LE",
+ value);
+ }
+
+ create_file(filename, S_IRUSR | S_IWUSR);
+
+ str = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(filename, str, length, NULL);
+ g_free(str);
+
+done:
+ g_key_file_free(key_file);
+}
+void device_load_svc_chng_ccc(struct btd_device *device, uint16_t *ccc_le,
+ uint16_t *ccc_bredr)
+{
+ char filename[PATH_MAX];
+ char device_addr[18];
+ GKeyFile *key_file;
+
+ ba2str(&device->bdaddr, device_addr);
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
+ btd_adapter_get_storage_dir(device->adapter),
+ device_addr);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ if (ccc_le)
+ *ccc_le = g_key_file_get_integer(key_file, "ServiceChanged",
+ "CCC_LE", NULL);
+
+ if (ccc_bredr)
+ *ccc_bredr = g_key_file_get_integer(key_file, "ServiceChanged",
+ "CCC_BR/EDR", NULL);
+
+ g_key_file_free(key_file);
+}
+
void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi,
int8_t delta_threshold)
{
void device_remove_profile(gpointer a, gpointer b);
struct btd_adapter *device_get_adapter(struct btd_device *device);
const bdaddr_t *device_get_address(struct btd_device *device);
+uint8_t device_get_le_address_type(struct btd_device *device);
const char *device_get_path(const struct btd_device *device);
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
void device_set_remote_feature_flag(struct btd_device *device, int flags);
bool device_is_disconnecting(struct btd_device *device);
void device_set_ltk_enc_size(struct btd_device *device, uint8_t enc_size);
+void device_store_svc_chng_ccc(struct btd_device *device, uint8_t bdaddr_type,
+ uint16_t value);
+void device_load_svc_chng_ccc(struct btd_device *device, uint16_t *ccc_le,
+ uint16_t *ccc_bredr);
+
typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
void *user_data);
}
static struct device_state *device_state_create(struct btd_gatt_database *db,
- bdaddr_t *bdaddr,
+ const bdaddr_t *bdaddr,
uint8_t bdaddr_type)
{
struct device_state *dev_state;
if (!device)
goto remove;
- if (device_is_bonded(device, state->bdaddr_type))
+ if (device_is_bonded(device, state->bdaddr_type)) {
+ struct ccc_state *ccc;
+ uint16_t handle;
+
+ handle = gatt_db_attribute_get_handle(state->db->svc_chngd_ccc);
+
+ ccc = find_ccc_state(state, handle);
+ if (ccc)
+ device_store_svc_chng_ccc(device, state->bdaddr_type,
+ ccc->value[0]);
+
return;
+ }
remove:
/* Remove device state if device no longer exists or is not paired */
{
uint16_t start, end, old_start, old_end;
+ /* Cache this only for Service Changed */
if (notify->conf != service_changed_conf)
return;
free(state->pending);
state->pending = NULL;
}
+
+static void restore_ccc(struct btd_gatt_database *database,
+ const bdaddr_t *addr, uint8_t addr_type, uint16_t value)
+{
+ struct device_state *dev_state;
+ struct ccc_state *ccc;
+
+ dev_state = device_state_create(database, addr, addr_type);
+ queue_push_tail(database->device_states, dev_state);
+
+ ccc = new0(struct ccc_state, 1);
+ ccc->handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
+ memcpy(ccc->value, &value, sizeof(ccc->value));
+ queue_push_tail(dev_state->ccc_states, ccc);
+}
+
+static void restore_state(struct btd_device *device, void *data)
+{
+ struct btd_gatt_database *database = data;
+ uint16_t ccc_le, ccc_bredr;
+
+ device_load_svc_chng_ccc(device, &ccc_le, &ccc_bredr);
+
+ if (ccc_le) {
+ restore_ccc(database, device_get_address(device),
+ device_get_le_address_type(device), ccc_le);
+
+ DBG("%s LE", device_get_path(device));
+ }
+
+ if (ccc_bredr) {
+ restore_ccc(database, device_get_address(device),
+ BDADDR_BREDR, ccc_bredr);
+
+ DBG("%s BR/EDR", device_get_path(device));
+ }
+}
+
+void btd_gatt_database_restore_svc_chng_ccc(struct btd_gatt_database *database)
+{
+ uint8_t value[4];
+ uint16_t handle, ccc_handle;
+
+ handle = gatt_db_attribute_get_handle(database->svc_chngd);
+ ccc_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
+
+ if (!handle || !ccc_handle) {
+ error("Failed to obtain handles for \"Service Changed\""
+ " characteristic");
+ return;
+ }
+
+ /* restore states for bonded device that registered for Service Changed
+ * indication
+ */
+ btd_adapter_for_each_device(database->adapter, restore_state, database);
+
+ /* This needs to be updated (probably to 0x0001) if we ever change
+ * core services
+ *
+ * TODO we could also store this info (along with CCC value) and be able
+ * to send 0x0001-0xffff only once per device.
+ */
+ put_le16(0x000a, value);
+ put_le16(0xffff, value + 2);
+
+ send_notification_to_devices(database, handle, value, sizeof(value),
+ ccc_handle, service_changed_conf, NULL);
+}
struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database);
void btd_gatt_database_att_connected(struct btd_gatt_database *database,
struct bt_att *att);
+
+void btd_gatt_database_restore_svc_chng_ccc(struct btd_gatt_database *database);