From a9f523e0c3627ea2ea3c894c2d34b756ee533637 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 21 Feb 2014 15:07:35 +0200 Subject: [PATCH] core: Split LE and BR/EDR states for devices For dual mode devices there are several state variables that are independent for each bearer. This patch splits these states up into two separate variable groups in btd_device and tracks the values based on what kind of connection is in question. The information is also used to select which bearer to use with Device1.Connect and Device1.Pair. The basic rule is that the bearer that's not connected/paired is selected, or then the bearer over which the device was last seen is selected. --- plugins/neard.c | 2 +- profiles/gatt/gas.c | 4 +- src/adapter.c | 43 ++++-- src/attrib-server.c | 4 +- src/device.c | 329 +++++++++++++++++++++++++++++++------------- src/device.h | 18 +-- 6 files changed, 275 insertions(+), 125 deletions(-) diff --git a/plugins/neard.c b/plugins/neard.c index ba3b6680b..137d601c5 100644 --- a/plugins/neard.c +++ b/plugins/neard.c @@ -327,7 +327,7 @@ static int check_device(struct btd_device *device) return -ENOENT; /* If already paired */ - if (device_is_paired(device)) { + if (device_is_paired(device, BDADDR_BREDR)) { DBG("already paired"); return -EALREADY; } diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c index db1e29d89..c0526e52f 100644 --- a/profiles/gatt/gas.c +++ b/profiles/gatt/gas.c @@ -177,6 +177,7 @@ done: static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data) { + uint8_t bdaddr_type; struct gas *gas = user_data; uint16_t start, end, olen; size_t plen; @@ -197,7 +198,8 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data) olen = enc_confirmation(opdu, plen); g_attrib_send(gas->attrib, 0, opdu, olen, NULL, NULL, NULL); - if (device_is_bonded(gas->device) == FALSE) { + bdaddr_type = btd_device_get_bdaddr_type(gas->device); + if (!device_is_bonded(gas->device, bdaddr_type)) { DBG("Ignoring Service Changed: device is not bonded"); return; } diff --git a/src/adapter.c b/src/adapter.c index f5b03c3c3..bb2c017c4 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -2716,7 +2716,10 @@ static void load_devices(struct btd_adapter *adapter) device_exist: if (key_info || ltk_info) { device_set_paired(device, TRUE); - device_set_bonded(device, TRUE); + if (key_info) + device_set_bonded(device, BDADDR_BREDR); + if (ltk_info) + device_set_bonded(device, bdaddr_type); } free: @@ -2852,15 +2855,16 @@ void adapter_remove_profile(struct btd_adapter *adapter, gpointer p) } static void adapter_add_connection(struct btd_adapter *adapter, - struct btd_device *device) + struct btd_device *device, + uint8_t bdaddr_type) { + device_add_connection(device, bdaddr_type); + if (g_slist_find(adapter->connections, device)) { error("Device is already marked as connected"); return; } - device_add_connection(device); - adapter->connections = g_slist_append(adapter->connections, device); } @@ -2903,7 +2907,7 @@ static void get_connections_complete(uint8_t status, uint16_t length, device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type); if (device) - adapter_add_connection(adapter, device); + adapter_add_connection(adapter, device, addr->type); } } @@ -4432,7 +4436,8 @@ struct agent *adapter_get_agent(struct btd_adapter *adapter) } static void adapter_remove_connection(struct btd_adapter *adapter, - struct btd_device *device) + struct btd_device *device, + uint8_t bdaddr_type) { DBG(""); @@ -4441,13 +4446,17 @@ static void adapter_remove_connection(struct btd_adapter *adapter, return; } - device_remove_connection(device); - - adapter->connections = g_slist_remove(adapter->connections, device); + device_remove_connection(device, bdaddr_type); if (device_is_authenticating(device)) device_cancel_authentication(device, TRUE); + /* If another bearer is still connected */ + if (btd_device_is_connected(device)) + return; + + adapter->connections = g_slist_remove(adapter->connections, device); + if (device_is_temporary(device) && !device_is_retrying(device)) { const char *path = device_get_path(device); @@ -4479,7 +4488,11 @@ static void adapter_stop(struct btd_adapter *adapter) while (adapter->connections) { struct btd_device *device = adapter->connections->data; - adapter_remove_connection(adapter, device); + uint8_t addr_type = btd_device_get_bdaddr_type(device); + + adapter_remove_connection(adapter, device, BDADDR_BREDR); + if (addr_type != BDADDR_BREDR) + adapter_remove_connection(adapter, device, addr_type); } g_dbus_emit_property_changed(dbus_conn, adapter->path, @@ -5151,7 +5164,7 @@ static void bonding_complete(struct btd_adapter *adapter, device = btd_adapter_find_device(adapter, bdaddr); if (device != NULL) - device_bonding_complete(device, status); + device_bonding_complete(device, addr_type, status); resume_discovery(adapter); @@ -5336,7 +5349,7 @@ static void dev_disconnected(struct btd_adapter *adapter, device = btd_adapter_find_device(adapter, &addr->bdaddr); if (device) - adapter_remove_connection(adapter, device); + adapter_remove_connection(adapter, device, addr->type); bonding_attempt_complete(adapter, &addr->bdaddr, addr->type, MGMT_STATUS_DISCONNECTED); @@ -5475,7 +5488,7 @@ static void new_link_key_callback(uint16_t index, uint16_t length, store_link_key(adapter, device, key->val, key->type, key->pin_len); - device_set_bonded(device, TRUE); + device_set_bonded(device, BDADDR_BREDR); if (device_is_temporary(device)) btd_device_set_temporary(device, FALSE); @@ -5594,7 +5607,7 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length, key->type, key->enc_size, key->ediv, key->rand); - device_set_bonded(device, TRUE); + device_set_bonded(device, addr->type); if (device_is_temporary(device)) btd_device_set_temporary(device, FALSE); @@ -6027,7 +6040,7 @@ static void connected_callback(uint16_t index, uint16_t length, if (eir_data.class != 0) device_set_class(device, eir_data.class); - adapter_add_connection(adapter, device); + adapter_add_connection(adapter, device, ev->addr.type); if (eir_data.name != NULL) { device_store_cached_name(device, eir_data.name); diff --git a/src/attrib-server.c b/src/attrib-server.c index 351b7fe35..38938272f 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -1115,6 +1115,7 @@ guint attrib_channel_attach(GAttrib *attrib) struct gatt_channel *channel; GIOChannel *io; GError *gerr = NULL; + uint8_t bdaddr_type; uint16_t cid; guint mtu = 0; @@ -1125,6 +1126,7 @@ guint attrib_channel_attach(GAttrib *attrib) bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &channel->src, BT_IO_OPT_DEST_BDADDR, &channel->dst, + BT_IO_OPT_DEST_TYPE, &bdaddr_type, BT_IO_OPT_CID, &cid, BT_IO_OPT_IMTU, &mtu, BT_IO_OPT_INVALID); @@ -1154,7 +1156,7 @@ guint attrib_channel_attach(GAttrib *attrib) return 0; } - if (device_is_bonded(device) == FALSE) { + if (!device_is_bonded(device, bdaddr_type)) { char *filename; filename = btd_device_get_storage_path(device, "ccc"); diff --git a/src/device.c b/src/device.c index fcbc7aada..a73ba293c 100644 --- a/src/device.c +++ b/src/device.c @@ -85,6 +85,7 @@ struct bonding_req { DBusMessage *msg; guint listener_id; struct btd_device *device; + uint8_t bdaddr_type; struct agent *agent; struct btd_adapter_pin_cb_iter *cb_iter; uint8_t status; @@ -152,6 +153,14 @@ struct att_callbacks { gpointer user_data; }; +/* Per-bearer (LE or BR/EDR) device state */ +struct bearer_state { + bool paired; + bool bonded; + bool connected; + bool svc_resolved; +}; + struct btd_device { int ref_count; @@ -161,7 +170,6 @@ struct btd_device { bool bredr; bool le; bool pending_paired; /* "Paired" waiting for SDP */ - bool svc_resolved; bool svc_refreshed; GSList *svc_callbacks; GSList *eir_uuids; @@ -194,7 +202,8 @@ struct btd_device { GSList *attios_offline; guint attachid; /* Attrib server attach */ - gboolean connected; + struct bearer_state bredr_state; + struct bearer_state le_state; sdp_list_t *tmp_records; @@ -202,9 +211,7 @@ struct btd_device { time_t le_seen; gboolean trusted; - gboolean paired; gboolean blocked; - gboolean bonded; gboolean auto_connect; gboolean disable_auto_connect; gboolean general_connect; @@ -227,6 +234,15 @@ static const uint16_t uuid_list[] = { static int device_browse_primary(struct btd_device *device, DBusMessage *msg); static int device_browse_sdp(struct btd_device *device, DBusMessage *msg); +static struct bearer_state *get_state(struct btd_device *dev, + uint8_t bdaddr_type) +{ + if (bdaddr_type == BDADDR_BREDR) + return &dev->bredr_state; + else + return &dev->le_state; +} + static GSList *find_service_with_profile(GSList *list, struct btd_profile *p) { GSList *l; @@ -565,14 +581,18 @@ static void device_free(gpointer user_data) g_free(device); } -gboolean device_is_paired(struct btd_device *device) +bool device_is_paired(struct btd_device *device, uint8_t bdaddr_type) { - return device->paired; + struct bearer_state *state = get_state(device, bdaddr_type); + + return state->paired; } -gboolean device_is_bonded(struct btd_device *device) +bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type) { - return device->bonded; + struct bearer_state *state = get_state(device, bdaddr_type); + + return state->bonded; } gboolean device_is_trusted(struct btd_device *device) @@ -772,8 +792,13 @@ static gboolean dev_property_get_icon(const GDBusPropertyTable *property, static gboolean dev_property_get_paired(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { - struct btd_device *device = data; - gboolean val = device_is_paired(device); + struct btd_device *dev = data; + dbus_bool_t val; + + if (dev->bredr_state.paired || dev->le_state.paired) + val = TRUE; + else + val = FALSE; dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); @@ -909,10 +934,15 @@ static void dev_property_set_blocked(const GDBusPropertyTable *property, static gboolean dev_property_get_connected(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { - struct btd_device *device = data; + struct btd_device *dev = data; + dbus_bool_t connected; - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, - &device->connected); + if (dev->bredr_state.connected || dev->le_state.connected) + connected = TRUE; + else + connected = FALSE; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected); return TRUE; } @@ -920,19 +950,19 @@ static gboolean dev_property_get_connected(const GDBusPropertyTable *property, static gboolean dev_property_get_uuids(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { - struct btd_device *device = data; + struct btd_device *dev = data; DBusMessageIter entry; GSList *l; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &entry); - if (device->svc_resolved) - l = device->uuids; - else if (device->eir_uuids) - l = device->eir_uuids; + if (dev->bredr_state.svc_resolved || dev->le_state.svc_resolved) + l = dev->uuids; + else if (dev->eir_uuids) + l = dev->eir_uuids; else - l = device->uuids; + l = dev->uuids; for (; l != NULL; l = l->next) dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, @@ -976,13 +1006,18 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property, return TRUE; } -static gboolean do_disconnect(gpointer user_data) +static gboolean disconnect_all(gpointer user_data) { struct btd_device *device = user_data; device->disconn_timer = 0; - btd_adapter_disconnect_device(device->adapter, &device->bdaddr, + if (device->bredr_state.connected) + btd_adapter_disconnect_device(device->adapter, &device->bdaddr, + BDADDR_BREDR); + + if (device->le_state.connected) + btd_adapter_disconnect_device(device->adapter, &device->bdaddr, device->bdaddr_type); return FALSE; @@ -995,8 +1030,7 @@ int device_block(struct btd_device *device, gboolean update_only) if (device->blocked) return 0; - if (device->connected) - do_disconnect(device); + disconnect_all(device); while (device->services != NULL) { struct btd_service *service = device->services->data; @@ -1005,9 +1039,16 @@ int device_block(struct btd_device *device, gboolean update_only) service_remove(service); } - if (!update_only) - err = btd_adapter_block_address(device->adapter, - &device->bdaddr, device->bdaddr_type); + if (!update_only) { + if (device->le) + err = btd_adapter_block_address(device->adapter, + &device->bdaddr, + device->bdaddr_type); + if (!err && device->bredr) + err = btd_adapter_block_address(device->adapter, + &device->bdaddr, + BDADDR_BREDR); + } if (err < 0) return err; @@ -1090,7 +1131,7 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg) device->connect = NULL; } - if (device->connected && msg) + if (btd_device_is_connected(device) && msg) device->disconnects = g_slist_append(device->disconnects, dbus_message_ref(msg)); @@ -1118,14 +1159,15 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg) g_free(data); } - if (!device->connected) { + if (!btd_device_is_connected(device)) { if (msg) g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID); return; } device->disconn_timer = g_timeout_add_seconds(DISCONNECT_TIMER, - do_disconnect, device); + disconnect_all, + device); } static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg, @@ -1176,7 +1218,7 @@ static void device_profile_connected(struct btd_device *dev, if (dev->pending == NULL) return; - if (!dev->connected) { + if (!btd_device_is_connected(dev)) { switch (-err) { case EHOSTDOWN: /* page timeout */ case EHOSTUNREACH: /* adapter not powered */ @@ -1235,7 +1277,7 @@ void device_add_eir_uuids(struct btd_device *dev, GSList *uuids) GSList *l; bool added = false; - if (dev->svc_resolved) + if (dev->bredr_state.svc_resolved || dev->le_state.svc_resolved) return; for (l = uuids; l != NULL; l = l->next) { @@ -1313,9 +1355,10 @@ static GSList *create_pending_list(struct btd_device *dev, const char *uuid) return dev->pending; } -static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg, - const char *uuid) +static DBusMessage *connect_profiles(struct btd_device *dev, uint8_t bdaddr_type, + DBusMessage *msg, const char *uuid) { + struct bearer_state *state = get_state(dev, bdaddr_type); int err; DBG("%s %s, client %s", dev->path, uuid ? uuid : "(all)", @@ -1329,7 +1372,7 @@ static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg, btd_device_set_temporary(dev, FALSE); - if (!dev->svc_resolved) + if (!state->svc_resolved) goto resolve_services; dev->pending = create_pending_list(dev, uuid); @@ -1356,7 +1399,7 @@ static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg, resolve_services: DBG("Resolving services for %s", dev->path); - if (dev->bredr) + if (bdaddr_type == BDADDR_BREDR) err = device_browse_sdp(dev, msg); else err = device_browse_primary(dev, msg); @@ -1366,15 +1409,55 @@ resolve_services: return NULL; } +#define NVAL_TIME ((time_t) -1) +#define SEEN_TRESHHOLD 300 + +static uint8_t select_conn_bearer(struct btd_device *dev) +{ + time_t bredr_last = NVAL_TIME, le_last = NVAL_TIME; + time_t current = time(NULL); + + if (dev->bredr_seen) { + bredr_last = current - dev->bredr_seen; + if (bredr_last > SEEN_TRESHHOLD) + bredr_last = NVAL_TIME; + } + + if (dev->le_seen) { + le_last = current - dev->le_seen; + if (le_last > SEEN_TRESHHOLD) + le_last = NVAL_TIME; + } + + if (!dev->le || le_last == NVAL_TIME) + return BDADDR_BREDR; + + if (!dev->bredr || bredr_last == NVAL_TIME) + return dev->bdaddr_type; + + if (bredr_last < le_last) + return BDADDR_BREDR; + + return dev->bdaddr_type; +} + static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_device *dev = user_data; + uint8_t bdaddr_type; - if (dev->le) { + if (dev->bredr_state.connected) + bdaddr_type = dev->bdaddr_type; + else if (dev->le_state.connected) + bdaddr_type = BDADDR_BREDR; + else + bdaddr_type = select_conn_bearer(dev); + + if (bdaddr_type != BDADDR_BREDR) { int err; - if (btd_device_is_connected(dev)) + if (dev->le_state.connected) return dbus_message_new_method_return(msg); btd_device_set_temporary(dev, FALSE); @@ -1390,7 +1473,7 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, return NULL; } - return connect_profiles(dev, msg, NULL); + return connect_profiles(dev, bdaddr_type, msg, NULL); } static DBusMessage *connect_profile(DBusConnection *conn, DBusMessage *msg, @@ -1406,7 +1489,7 @@ static DBusMessage *connect_profile(DBusConnection *conn, DBusMessage *msg, return btd_error_invalid_args(msg); uuid = bt_name2string(pattern); - reply = connect_profiles(dev, msg, uuid); + reply = connect_profiles(dev, BDADDR_BREDR, msg, uuid); free(uuid); return reply; @@ -1471,21 +1554,23 @@ static DBusMessage *disconnect_profile(DBusConnection *conn, DBusMessage *msg, return btd_error_failed(msg, strerror(-err)); } -static void device_svc_resolved(struct btd_device *dev, int err) +static void device_svc_resolved(struct btd_device *dev, uint8_t bdaddr_type, + int err) { + struct bearer_state *state = get_state(dev, bdaddr_type); DBusMessage *reply; struct browse_req *req = dev->browse; DBG("%s err %d", dev->path, err); - dev->svc_resolved = true; + state->svc_resolved = true; dev->browse = NULL; /* Disconnection notification can happen before this function * gets called, so don't set svc_refreshed for a disconnected * device. */ - if (dev->connected) + if (state->connected) dev->svc_refreshed = true; g_slist_free_full(dev->eir_uuids, g_free); @@ -1542,6 +1627,7 @@ static void device_svc_resolved(struct btd_device *dev, int err) static struct bonding_req *bonding_request_new(DBusMessage *msg, struct btd_device *device, + uint8_t bdaddr_type, struct agent *agent) { struct bonding_req *bonding; @@ -1553,6 +1639,7 @@ static struct bonding_req *bonding_request_new(DBusMessage *msg, bonding = g_new0(struct bonding_req, 1); bonding->msg = dbus_message_ref(msg); + bonding->bdaddr_type = bdaddr_type; bonding->cb_iter = btd_adapter_pin_cb_iter_new(device->adapter); @@ -1628,6 +1715,8 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, { struct btd_device *device = data; struct btd_adapter *adapter = device->adapter; + struct bearer_state *state; + uint8_t bdaddr_type; const char *sender; struct agent *agent; struct bonding_req *bonding; @@ -1642,7 +1731,16 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, if (device->bonding) return btd_error_in_progress(msg); - if (device_is_bonded(device)) + if (device->bredr_state.bonded) + bdaddr_type = device->bdaddr_type; + else if (device->le_state.bonded) + bdaddr_type = BDADDR_BREDR; + else + bdaddr_type = select_conn_bearer(device); + + state = get_state(device, bdaddr_type); + + if (state->bonded) return btd_error_already_exists(msg); sender = dbus_message_get_sender(msg); @@ -1653,7 +1751,7 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, else io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT; - bonding = bonding_request_new(msg, device, agent); + bonding = bonding_request_new(msg, device, bdaddr_type, agent); if (agent) agent_unref(agent); @@ -1670,8 +1768,8 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, * channel first and only then start pairing (there's code for * this in the ATT connect callback) */ - if (device->le) { - if (!btd_device_is_connected(device)) + if (bdaddr_type != BDADDR_BREDR) { + if (!state->connected) err = device_connect_le(device); else err = adapter_create_bonding(adapter, &device->bdaddr, @@ -1822,38 +1920,54 @@ static const GDBusPropertyTable device_properties[] = { { } }; -gboolean btd_device_is_connected(struct btd_device *device) +uint8_t btd_device_get_bdaddr_type(struct btd_device *dev) { - return device->connected; + return dev->bdaddr_type; } -void device_add_connection(struct btd_device *device) +bool btd_device_is_connected(struct btd_device *dev) { - if (device->connected) { + return dev->bredr_state.connected || dev->le_state.connected; +} + +void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type) +{ + struct bearer_state *state = get_state(dev, bdaddr_type); + + if (state->connected) { char addr[18]; - ba2str(&device->bdaddr, addr); + ba2str(&dev->bdaddr, addr); error("Device %s is already connected", addr); return; } - device->connected = TRUE; + /* If this is the first connection over this bearer */ + if (bdaddr_type == BDADDR_BREDR) { + dev->bredr = true; + } else { + dev->le = true; + dev->bdaddr_type = bdaddr_type; + } - g_dbus_emit_property_changed(dbus_conn, device->path, - DEVICE_INTERFACE, "Connected"); + state->connected = true; + + if (dev->le_state.connected && dev->bredr_state.connected) + return; + + g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE, + "Connected"); } -void device_remove_connection(struct btd_device *device) +void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type) { - if (!device->connected) { - char addr[18]; - ba2str(&device->bdaddr, addr); - error("Device %s isn't connected", addr); + struct bearer_state *state = get_state(device, bdaddr_type); + + if (!state->connected) return; - } - device->connected = FALSE; - device->general_connect = FALSE; + state->connected = false; device->svc_refreshed = false; + device->general_connect = FALSE; if (device->disconn_timer > 0) { g_source_remove(device->disconn_timer); @@ -1868,8 +1982,12 @@ void device_remove_connection(struct btd_device *device) dbus_message_unref(msg); } - if (device_is_paired(device) && !device_is_bonded(device)) - device_set_paired(device, FALSE); + if (state->paired && !state->bonded) + btd_adapter_remove_bonding(device->adapter, &device->bdaddr, + bdaddr_type); + + if (device->bredr_state.connected || device->le_state.connected) + return; g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE, "Connected"); @@ -2050,7 +2168,7 @@ next: g_strfreev(uuids); /* Discovered services restored from storage */ - device->svc_resolved = true; + device->bredr_state.svc_resolved = true; } /* Load device id */ @@ -2415,7 +2533,6 @@ static void delete_folder_tree(const char *dirname) static void device_remove_stored(struct btd_device *device) { const bdaddr_t *src = btd_adapter_get_address(device->adapter); - uint8_t dst_type = device->bdaddr_type; char adapter_addr[18]; char device_addr[18]; char filename[PATH_MAX + 1]; @@ -2423,13 +2540,21 @@ static void device_remove_stored(struct btd_device *device) char *data; gsize length = 0; - if (device_is_bonded(device)) { - device->bonded = FALSE; - device->paired = FALSE; + if (device->bredr_state.bonded) { + device->bredr_state.bonded = false; + btd_adapter_remove_bonding(device->adapter, &device->bdaddr, + BDADDR_BREDR); + } + + if (device->le_state.bonded) { + device->le_state.bonded = false; btd_adapter_remove_bonding(device->adapter, &device->bdaddr, - dst_type); + device->bdaddr_type); } + device->bredr_state.paired = false; + device->le_state.paired = false; + if (device->blocked) device_unblock(device, TRUE, FALSE); @@ -2466,7 +2591,7 @@ void device_remove(struct btd_device *device, gboolean remove_stored) if (device->bonding) { uint8_t status; - if (device->connected) + if (device->bredr_state.connected) status = MGMT_STATUS_DISCONNECTED; else status = MGMT_STATUS_CONNECT_FAILED; @@ -2487,8 +2612,8 @@ void device_remove(struct btd_device *device, gboolean remove_stored) g_slist_free(device->pending); device->pending = NULL; - if (device->connected) - do_disconnect(device); + if (btd_device_is_connected(device)) + disconnect_all(device); if (device->store_id > 0) { g_source_remove(device->store_id); @@ -3003,7 +3128,7 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data) DEVICE_INTERFACE, "UUIDs"); send_reply: - device_svc_resolved(device, err); + device_svc_resolved(device, BDADDR_BREDR, err); if (!device->temporary) store_device_info(device); @@ -3201,7 +3326,7 @@ static void register_all_services(struct browse_req *req, GSList *services) g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE, "UUIDs"); - device_svc_resolved(device, 0); + device_svc_resolved(device, device->bdaddr_type, 0); store_services(device); @@ -3366,7 +3491,7 @@ done: } if (device->connect) { - if (!device->svc_resolved) + if (!device->le_state.svc_resolved) device_browse_primary(device, NULL); if (err < 0) @@ -3437,7 +3562,7 @@ int device_connect_le(struct btd_device *dev) attcb->success = att_success_cb; attcb->user_data = dev; - if (dev->paired) + if (dev->le_state.paired) sec_level = BT_IO_SEC_MEDIUM; else sec_level = BT_IO_SEC_LOW; @@ -3706,14 +3831,17 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted) DEVICE_INTERFACE, "Trusted"); } -void device_set_bonded(struct btd_device *device, gboolean bonded) +void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type) { if (!device) return; - DBG("bonded %d", bonded); + DBG(""); - device->bonded = bonded; + if (bdaddr_type == BDADDR_BREDR) + device->bredr_state.bonded = true; + else + device->le_state.bonded = true; } void device_set_legacy(struct btd_device *device, bool legacy) @@ -3807,22 +3935,20 @@ static gboolean start_discovery(gpointer user_data) return FALSE; } -void device_set_paired(struct btd_device *device, gboolean value) +void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type) { - if (device->paired == value) - return; - - if (!value) - btd_adapter_remove_bonding(device->adapter, &device->bdaddr, - device->bdaddr_type); + struct bearer_state *state = get_state(dev, bdaddr_type); - device->paired = value; + if (state->paired) + return; - if (device->paired && !device->svc_resolved) - device->pending_paired = true; - else - g_dbus_emit_property_changed(dbus_conn, device->path, + if (state->paired && !state->svc_resolved) + dev->pending_paired = true; + else if (dev->bredr_state.paired != dev->le_state.paired) + g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE, "Paired"); + + state->paired = true; } static void device_auth_req_free(struct btd_device *device) @@ -3840,10 +3966,12 @@ bool device_is_retrying(struct btd_device *device) return bonding && bonding->retry_timer > 0; } -void device_bonding_complete(struct btd_device *device, uint8_t status) +void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type, + uint8_t status) { struct bonding_req *bonding = device->bonding; struct authentication_req *auth = device->authr; + struct bearer_state *state = get_state(device, bdaddr_type); DBG("bonding %p status 0x%02x", bonding, status); @@ -3859,7 +3987,7 @@ void device_bonding_complete(struct btd_device *device, uint8_t status) device_auth_req_free(device); /* If we're already paired nothing more is needed */ - if (device->paired) + if (state->paired) return; device_set_paired(device, TRUE); @@ -3867,7 +3995,7 @@ void device_bonding_complete(struct btd_device *device, uint8_t status) /* If services are already resolved just reply to the pairing * request */ - if (device->svc_resolved && bonding) { + if (state->svc_resolved && bonding) { g_dbus_send_reply(dbus_conn, bonding->msg, DBUS_TYPE_INVALID); bonding_request_free(bonding); return; @@ -3886,13 +4014,13 @@ void device_bonding_complete(struct btd_device *device, uint8_t status) device->discov_timer = 0; } - if (device->bredr) + if (bdaddr_type == BDADDR_BREDR) device_browse_sdp(device, bonding->msg); else device_browse_primary(device, bonding->msg); bonding_request_free(bonding); - } else if (!device->svc_resolved) { + } else if (!state->svc_resolved) { if (!device->browse && !device->discov_timer && main_opts.reverse_sdp) { /* If we are not initiators and there is no currently @@ -3925,6 +4053,8 @@ unsigned int device_wait_for_svc_complete(struct btd_device *dev, device_svc_cb_t func, void *user_data) { + /* This API is only used for BR/EDR (for now) */ + struct bearer_state *state = &dev->bredr_state; static unsigned int id = 0; struct svc_callback *cb; @@ -3936,7 +4066,7 @@ unsigned int device_wait_for_svc_complete(struct btd_device *dev, dev->svc_callbacks = g_slist_prepend(dev->svc_callbacks, cb); - if (dev->svc_resolved || !main_opts.reverse_sdp) + if (state->svc_resolved || !main_opts.reverse_sdp) cb->idle_id = g_idle_add(svc_idle_cb, cb); else if (dev->discov_timer > 0) { g_source_remove(dev->discov_timer); @@ -4010,7 +4140,8 @@ static gboolean device_bonding_retry(gpointer data) err = adapter_bonding_attempt(adapter, &device->bdaddr, device->bdaddr_type, io_cap); if (err < 0) - device_bonding_complete(device, bonding->status); + device_bonding_complete(device, bonding->bdaddr_type, + bonding->status); return FALSE; } diff --git a/src/device.h b/src/device.h index 7ef0199d5..7add01747 100644 --- a/src/device.h +++ b/src/device.h @@ -67,18 +67,20 @@ struct btd_adapter *device_get_adapter(struct btd_device *device); const bdaddr_t *device_get_address(struct btd_device *device); const char *device_get_path(const struct btd_device *device); gboolean device_is_temporary(struct btd_device *device); -gboolean device_is_paired(struct btd_device *device); -gboolean device_is_bonded(struct btd_device *device); +bool device_is_paired(struct btd_device *device, uint8_t bdaddr_type); +bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type); gboolean device_is_trusted(struct btd_device *device); -void device_set_paired(struct btd_device *device, gboolean paired); +void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type); void btd_device_set_temporary(struct btd_device *device, gboolean temporary); void btd_device_set_trusted(struct btd_device *device, gboolean trusted); -void device_set_bonded(struct btd_device *device, gboolean bonded); +void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type); void device_set_legacy(struct btd_device *device, bool legacy); void device_set_rssi(struct btd_device *device, int8_t rssi); -gboolean btd_device_is_connected(struct btd_device *device); +bool btd_device_is_connected(struct btd_device *dev); +uint8_t btd_device_get_bdaddr_type(struct btd_device *dev); bool device_is_retrying(struct btd_device *device); -void device_bonding_complete(struct btd_device *device, uint8_t status); +void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type, + uint8_t status); gboolean device_is_bonding(struct btd_device *device, const char *sender); void device_bonding_attempt_failed(struct btd_device *device, uint8_t status); void device_bonding_failed(struct btd_device *device, uint8_t status); @@ -96,8 +98,8 @@ int device_notify_pincode(struct btd_device *device, gboolean secure, const char *pincode); void device_cancel_authentication(struct btd_device *device, gboolean aborted); gboolean device_is_authenticating(struct btd_device *device); -void device_add_connection(struct btd_device *device); -void device_remove_connection(struct btd_device *device); +void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type); +void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type); void device_request_disconnect(struct btd_device *device, DBusMessage *msg); typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal, -- 2.47.3