From b501a6fab756360b0ac357817eeccfbc73850b56 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 29 Jan 2013 12:37:08 -0600 Subject: [PATCH] core: Stop passive scanning before connecting LE Many controllers do not support creating LE connections at the same time as doing scanning so stop the scanning before attempting to connect. --- src/adapter.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/src/adapter.c b/src/adapter.c index 93cb269ed..9141773b7 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -164,6 +164,7 @@ struct btd_adapter { GSList *devices; /* Devices structure pointers */ GSList *connect_list; /* Devices to connect when found */ bool passive_scanning; /* Passive (LE) scanning enabled */ + struct btd_device *connect_le; /* LE device waiting to be connected */ sdp_list_t *services; /* Services associated to adapter */ bool toggle_discoverable; /* discoverable needs to be changed */ @@ -1058,6 +1059,9 @@ static void adapter_remove_device(struct btd_adapter *adapter, adapter->connections = g_slist_remove(adapter->connections, dev); + if (adapter->connect_le == dev) + adapter->connect_le = NULL; + l = adapter->auths->head; while (l != NULL) { struct service_auth *auth = l->data; @@ -3979,6 +3983,36 @@ static void confirm_name(struct btd_adapter *adapter, const bdaddr_t *bdaddr, confirm_name_timeout, adapter); } +static void stop_passive_scanning_complete(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + struct btd_adapter *adapter = user_data; + struct btd_device *dev; + int err; + + dev = adapter->connect_le; + adapter->connect_le = NULL; + + if (status != MGMT_STATUS_SUCCESS) { + error("Stopping passive scanning failed: %s", + mgmt_errstr(status)); + return; + } + + if (!dev) { + DBG("Device removed while stopping passive scanning"); + trigger_passive_scanning(adapter); + return; + } + + err = device_connect_le(dev); + if (err < 0) { + error("LE auto connection failed: %s (%d)", + strerror(-err), -err); + trigger_passive_scanning(adapter); + } +} + static void update_found_devices(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t bdaddr_type, int8_t rssi, @@ -4079,12 +4113,21 @@ done: if (!adapter->passive_scanning) return; + /* + * If this is an LE device that's not connected and part of the + * connect_list stop passive scanning so that a connection + * attempt to it can be made + */ if (device_is_le(dev) && !device_is_connected(dev) && g_slist_find(adapter->connect_list, dev)) { - err = device_connect_le(dev); - if (err < 0) - error("LE auto connection failed: %s (%d)", - strerror(-err), -err); + struct mgmt_cp_stop_discovery cp; + + adapter->connect_le = dev; + + cp.type = adapter->discovery_type; + mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY, + adapter->dev_id, sizeof(cp), &cp, + stop_passive_scanning_complete, adapter, NULL); } } @@ -4929,6 +4972,11 @@ static void dev_disconnected(struct btd_adapter *adapter, bonding_complete(adapter, &addr->bdaddr, addr->type, MGMT_STATUS_DISCONNECTED); + + /* If this device should be connected through passive scanning + * add it back to the connect_list */ + if (device && device_get_auto_connect(device)) + adapter_connect_list_add(adapter, device); } static void disconnect_complete(uint8_t status, uint16_t length, @@ -5511,6 +5559,19 @@ static void connected_callback(uint16_t index, uint16_t length, } eir_data_free(&eir_data); + + /* + * If this was an LE device being connected through passive + * scanning remove the device from the connect_list and give the + * passive scanning another chance to be restarted in case + * there are other devices in the connect_list. + */ + if (device == adapter->connect_le) { + adapter->connect_le = NULL; + adapter->connect_list = g_slist_remove(adapter->connect_list, + device); + trigger_passive_scanning(adapter); + } } static void device_blocked_callback(uint16_t index, uint16_t length, @@ -5578,6 +5639,12 @@ static void connect_failed_callback(uint16_t index, uint16_t length, device_bonding_failed(device, ev->status); if (device_is_temporary(device)) adapter_remove_device(adapter, device, TRUE); + if (device_is_le(device)) { + if (device == adapter->connect_le) + adapter->connect_le = NULL; + if (device_get_auto_connect(device)) + adapter_connect_list_add(adapter, device); + } } /* In the case of security mode 3 devices */ -- 2.11.0