diff --git a/android/bluetooth.c b/android/bluetooth.c
index 1f4315d..4b2b1a2 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
bool le;
bool bredr;
- int bond_state;
+ bool pairing;
+
+ bool bredr_paired;
+ bool le_paired;
char *name;
char *friendly_name;
dev->le_seen = time(NULL);
}
- dev->bond_state = HAL_BOND_STATE_NONE;
-
/*
* Use address for name, will be change if one is present
* eg. in EIR or set by set_property.
HAL_EV_BOND_STATE_CHANGED, sizeof(ev), &ev);
}
-static void set_device_bond_state(struct device *dev, uint8_t status,
- int state)
+static void update_bredr_state(struct device *dev, bool pairing, bool paired)
{
- if (dev->bond_state == state)
+ if (pairing == dev->pairing && paired == dev->bredr_paired)
return;
- switch (state) {
- case HAL_BOND_STATE_NONE:
- if (dev->bond_state == HAL_BOND_STATE_BONDED) {
- bonded_devices = g_slist_remove(bonded_devices, dev);
- remove_device_info(dev, DEVICES_FILE);
- cache_device(dev);
- }
- break;
- case HAL_BOND_STATE_BONDED:
+ /* avoid unpairing device on incoming pairing request */
+ if (pairing && dev->bredr_paired)
+ goto done;
+
+ /* avoid unpairing device if pairing failed */
+ if (!pairing && !paired && dev->pairing && dev->bredr_paired)
+ goto done;
+
+ if (paired && !dev->le_paired) {
cached_devices = g_slist_remove(cached_devices, dev);
bonded_devices = g_slist_prepend(bonded_devices, dev);
remove_device_info(dev, CACHE_FILE);
store_device_info(dev, DEVICES_FILE);
- break;
- case HAL_BOND_STATE_BONDING:
- default:
- break;
+ } else if (!paired && !dev->le_paired) {
+ bonded_devices = g_slist_remove(bonded_devices, dev);
+ remove_device_info(dev, DEVICES_FILE);
+ cache_device(dev);
+ }
+
+ dev->bredr_paired = paired;
+
+done:
+ dev->pairing = pairing;
+}
+
+static void update_le_state(struct device *dev, bool pairing, bool paired)
+{
+ if (pairing == dev->pairing && paired == dev->le_paired)
+ return;
+
+ /* avoid unpairing device on incoming pairing request */
+ if (pairing && dev->le_paired)
+ goto done;
+
+ /* avoid unpairing device if pairing failed */
+ if (!pairing && !paired && dev->pairing && dev->le_paired)
+ goto done;
+
+ if (paired && !dev->bredr_paired) {
+ cached_devices = g_slist_remove(cached_devices, dev);
+ bonded_devices = g_slist_prepend(bonded_devices, dev);
+ remove_device_info(dev, CACHE_FILE);
+ store_device_info(dev, DEVICES_FILE);
+ } else if (!paired && !dev->bredr_paired) {
+ bonded_devices = g_slist_remove(bonded_devices, dev);
+ remove_device_info(dev, DEVICES_FILE);
+ cache_device(dev);
}
- dev->bond_state = state;
+ dev->le_paired = paired;
+
+done:
+ dev->pairing = pairing;
+}
+
+static uint8_t device_bond_state(struct device *dev)
+{
+ if (dev->pairing)
+ return HAL_BOND_STATE_BONDING;
+
+ if (dev->bredr_paired || dev->le_paired)
+ return HAL_BOND_STATE_BONDED;
+
+ return HAL_BOND_STATE_NONE;
+}
+
+static void update_device_state(struct device *dev, uint8_t addr_type,
+ uint8_t status, bool pairing, bool paired)
+{
+ uint8_t old_bond, new_bond;
+
+ old_bond = device_bond_state(dev);
+
+ if (addr_type == BDADDR_BREDR)
+ update_bredr_state(dev, pairing, paired);
+ else
+ update_le_state(dev, pairing, paired);
- send_bond_state_change(&dev->bdaddr, status, state);
+ new_bond = device_bond_state(dev);
+
+ if (old_bond != new_bond)
+ send_bond_state_change(&dev->bdaddr, status, new_bond);
}
static void send_device_property(const bdaddr_t *bdaddr, uint8_t type,
g_slist_free_full(dev->uuids, g_free);
dev->uuids = uuids;
- if (dev->bond_state == HAL_BOND_STATE_BONDED)
+ if (dev->le_paired || dev->bredr_paired)
store_device_info(dev, DEVICES_FILE);
else
store_device_info(dev, CACHE_FILE);
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDED);
+ update_device_state(dev, ev->key.addr.type, HAL_STATUS_SUCCESS, false,
+ true);
if (ev->store_hint) {
const struct mgmt_link_key_info *key = &ev->key;
*/
get_device_name(dev);
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDING);
+ update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, true,
+ false);
DBG("%s type %u secure %u", dst, ev->addr.type, ev->secure);
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDING);
+ update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, true,
+ false);
if (ev->confirm_hint)
send_ssp_request(dev, HAL_SSP_VARIANT_CONSENT, 0);
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDING);
+ update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, true,
+ false);
send_ssp_request(dev, HAL_SSP_VARIANT_ENTRY, 0);
}
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDING);
+ update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, true,
+ false);
send_ssp_request(dev, HAL_SSP_VARIANT_NOTIF, ev->passkey);
}
if (dev->found)
return false;
- if (dev->bond_state == HAL_BOND_STATE_BONDED)
+ if (dev->bredr_paired || dev->le_paired)
return false;
if (dev->bdaddr_type != BDADDR_BREDR &&
discoverable);
}
- if (dev->bond_state != HAL_BOND_STATE_BONDED)
+ if (!dev->bredr_paired && !dev->le_paired)
cache_device(dev);
if (confirm) {
* bonding, if so update bond state
*/
- if (dev->bond_state != HAL_BOND_STATE_BONDING)
+ if (!dev->pairing)
return;
- set_device_bond_state(dev, status_mgmt2hal(ev->status),
- HAL_BOND_STATE_NONE);
+ update_device_state(dev, ev->addr.type, status_mgmt2hal(ev->status),
+ false, false);
}
static void mgmt_auth_failed_event(uint16_t index, uint16_t length,
if (!dev)
return;
- if (dev->bond_state != HAL_BOND_STATE_BONDING)
+ if (!dev->pairing)
return;
- set_device_bond_state(dev, status_mgmt2hal(ev->status),
- HAL_BOND_STATE_NONE);
+ update_device_state(dev, ev->addr.type, status_mgmt2hal(ev->status),
+ false, false);
}
static void mgmt_device_unpaired_event(uint16_t index, uint16_t length,
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_NONE);
+ update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, false,
+ false);
}
static void store_ltk(const bdaddr_t *dst, uint8_t bdaddr_type, bool master,
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDED);
+ update_device_state(dev, ev->key.addr.type, HAL_STATUS_SUCCESS, false,
+ true);
if (ev->store_hint) {
const struct mgmt_ltk_info *key = &ev->key;
str = g_key_file_get_string(key_file, peer, "LinkKey", NULL);
if (str) {
g_free(str);
- dev->bond_state = HAL_BOND_STATE_BONDED;
+ dev->bredr_paired = true;
}
str = g_key_file_get_string(key_file, peer, "LongTermKey", NULL);
if (str) {
g_free(str);
- dev->bond_state = HAL_BOND_STATE_BONDED;
+ dev->le_paired = true;
}
str = g_key_file_get_string(key_file, peer, "SlaveLongTermKey", NULL);
if (str) {
g_free(str);
- dev->bond_state = HAL_BOND_STATE_BONDED;
+ dev->le_paired = true;
}
str = g_key_file_get_string(key_file, peer, "Name", NULL);
if (!dev)
return;
- set_device_bond_state(dev, status_mgmt2hal(status),
- HAL_BOND_STATE_NONE);
+ update_device_state(dev, rp->addr.type, status_mgmt2hal(status), false,
+ false);
}
static uint8_t select_device_bearer(struct device *dev)
return dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
}
+static bool device_is_paired(struct device *dev, uint8_t addr_type)
+{
+ if (addr_type == BDADDR_BREDR)
+ return dev->bredr_paired;
+
+ return dev->le_paired;
+}
+
static void handle_create_bond_cmd(const void *buf, uint16_t len)
{
const struct hal_cmd_create_bond *cmd = buf;
/* type is used only as fallback when device is not in cache */
dev = get_device(&cp.addr.bdaddr, BDADDR_BREDR);
- if (dev->bond_state != HAL_BOND_STATE_NONE) {
+ cp.addr.type = select_device_bearer(dev);
+
+ if (device_is_paired(dev, cp.addr.type)) {
status = HAL_STATUS_FAILED;
goto fail;
}
- cp.addr.type = select_device_bearer(dev);
-
if (mgmt_send(mgmt_if, MGMT_OP_PAIR_DEVICE, adapter.index, sizeof(cp),
&cp, pair_device_complete, NULL, NULL) == 0) {
status = HAL_STATUS_FAILED;
status = HAL_STATUS_SUCCESS;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_BONDING);
+ update_device_state(dev, cp.addr.type, HAL_STATUS_SUCCESS, true, false);
fail:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CREATE_BOND,
if (!dev)
return;
- set_device_bond_state(dev, HAL_STATUS_SUCCESS, HAL_BOND_STATE_NONE);
+ update_device_state(dev, rp->addr.type, HAL_STATUS_SUCCESS, false,
+ false);
}
static void handle_remove_bond_cmd(const void *buf, uint16_t len)
g_free(dev->friendly_name);
dev->friendly_name = g_strndup((const char *) val, len);
- if (dev->bond_state == HAL_BOND_STATE_BONDED)
+ if (dev->bredr_paired || dev->le_paired)
store_device_info(dev, DEVICES_FILE);
else
store_device_info(dev, CACHE_FILE);