From e0e4bd6e2609377776ff73072d36373a476338ed Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 13 Aug 2010 11:32:20 -0300 Subject: [PATCH] Add BR/EDR LE interleaved discovery According to the general discovery procedure should interleave the general discovery procedure over BR/EDR with the general discovery procedure over LE. LE Scanning is reporting found remote devices using DeviceFound signals. Currently, only the Bluetooth address is extracted from the Advertising event. Step 1: BR/EDR discovery for TGAP(100)/2 sec Step 2: LE discovery for TGAP(100)/2 sec --- plugins/hciops.c | 4 +-- src/adapter.c | 75 ++++++++++++++++++++++++++++++++++++------------ src/adapter.h | 3 +- src/dbus-hci.c | 34 ++++++++++++++++++++-- src/dbus-hci.h | 1 + src/security.c | 16 +++++++++-- 6 files changed, 107 insertions(+), 26 deletions(-) diff --git a/plugins/hciops.c b/plugins/hciops.c index ab486fea7..a2b8eacaf 100644 --- a/plugins/hciops.c +++ b/plugins/hciops.c @@ -577,7 +577,7 @@ static int hciops_start_discovery(int index, gboolean periodic) memcpy(&cp.lap, lap, 3); cp.max_period = htobs(24); cp.min_period = htobs(16); - cp.length = 0x08; + cp.length = 0x04; cp.num_rsp = 0x00; err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_PERIODIC_INQUIRY, @@ -587,7 +587,7 @@ static int hciops_start_discovery(int index, gboolean periodic) memset(&inq_cp, 0, sizeof(inq_cp)); memcpy(&inq_cp.lap, lap, 3); - inq_cp.length = 0x08; + inq_cp.length = 0x04; inq_cp.num_rsp = 0x00; err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_INQUIRY, diff --git a/src/adapter.c b/src/adapter.c index dcb4901fb..d5cfd0fa5 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -1232,9 +1232,32 @@ struct btd_device *adapter_get_device(DBusConnection *conn, return adapter_create_device(conn, adapter, address); } -static int adapter_start_inquiry(struct btd_adapter *adapter) +static gboolean stop_inquiry(gpointer user_data) { + struct btd_adapter *adapter = user_data; + + DBG(""); + + adapter_ops->stop_discovery(adapter->dev_id); + + return FALSE; +} + +static gboolean stop_scanning(gpointer user_data) +{ + struct btd_adapter *adapter = user_data; + + adapter_ops->stop_scanning(adapter->dev_id); + + return FALSE; +} + +static int start_discovery(struct btd_adapter *adapter) +{ + struct hci_dev *dev = &adapter->dev; gboolean periodic = TRUE; + GSourceFunc stop; + int err; /* Do not start if suspended */ if (adapter->state & SUSPENDED_INQUIRY) @@ -1245,7 +1268,23 @@ static int adapter_start_inquiry(struct btd_adapter *adapter) pending_remote_name_cancel(adapter); - return adapter_ops->start_discovery(adapter->dev_id, periodic); + /* BR/EDR only? */ + if (!(dev->features[4] & LMP_LE)) + return adapter_ops->start_discovery(adapter->dev_id, periodic); + + /* Dual mode or LE only */ + if (dev->features[4] & LMP_NO_BREDR) { + err = adapter_ops->start_scanning(adapter->dev_id); + stop = stop_scanning; + } else { + err = adapter_ops->start_discovery(adapter->dev_id, FALSE); + stop = stop_inquiry; + } + + if (err == 0) + g_timeout_add(5120, stop, adapter); + + return err; } static DBusMessage *adapter_start_discovery(DBusConnection *conn, @@ -1271,7 +1310,7 @@ static DBusMessage *adapter_start_discovery(DBusConnection *conn, if (main_opts.name_resolv) adapter->state |= RESOLVE_NAME; - err = adapter_start_inquiry(adapter); + err = start_discovery(adapter); if (err < 0) return failed_strerror(msg, -err); @@ -1376,7 +1415,7 @@ static DBusMessage *get_properties(DBusConnection *conn, DBUS_TYPE_UINT32, &adapter->pairable_timeout); - if (adapter->state & PERIODIC_INQUIRY || adapter->state & STD_INQUIRY) + if (adapter->state & (PERIODIC_INQUIRY | STD_INQUIRY | LE_SCAN)) value = TRUE; else value = FALSE; @@ -2391,12 +2430,6 @@ static void reply_pending_requests(struct btd_adapter *adapter) device_cancel_bonding(device, HCI_OE_USER_ENDED_CONNECTION); } - - if (adapter->state & STD_INQUIRY || adapter->state & PERIODIC_INQUIRY) { - /* Cancel inquiry initiated by D-Bus client */ - if (adapter->disc_sessions) - adapter_ops->stop_discovery(adapter->dev_id); - } } static void unload_drivers(struct btd_adapter *adapter) @@ -2626,18 +2659,24 @@ void adapter_set_state(struct btd_adapter *adapter, int state) if (adapter->state == state) return; - if (state & PERIODIC_INQUIRY || state & STD_INQUIRY) - discov_active = TRUE; + if (adapter->state & STD_INQUIRY) { + if (adapter_ops->start_scanning(adapter->dev_id) < 0) + return; + + g_timeout_add(5120, stop_scanning, adapter); + } + + discov_active = state & (PERIODIC_INQUIRY | STD_INQUIRY | LE_SCAN) + ? TRUE : FALSE; + + if (discov_active == FALSE) + adapter_update_oor_devices(adapter); else if (adapter->disc_sessions && main_opts.discov_interval) adapter->scheduler_id = g_timeout_add_seconds( main_opts.discov_interval, - (GSourceFunc) adapter_start_inquiry, + (GSourceFunc) start_discovery, adapter); - /* Send out of range */ - if (!discov_active) - adapter_update_oor_devices(adapter); - emit_property_changed(connection, path, ADAPTER_INTERFACE, "Discovering", DBUS_TYPE_BOOLEAN, &discov_active); @@ -3146,7 +3185,7 @@ void adapter_resume_discovery(struct btd_adapter *adapter) DBG("Resuming discovery"); adapter->state &= ~SUSPENDED_INQUIRY; - adapter_start_inquiry(adapter); + start_discovery(adapter); } int btd_register_adapter_driver(struct btd_adapter_driver *driver) diff --git a/src/adapter.h b/src/adapter.h index 1da2fedd6..7b686ad9d 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -35,7 +35,8 @@ #define DISCOVER_TYPE_NONE 0x00 #define STD_INQUIRY 0x01 #define PERIODIC_INQUIRY 0x02 -#define SUSPENDED_INQUIRY 0x04 +#define LE_SCAN 0x04 +#define SUSPENDED_INQUIRY 0x08 /* Actions executed after inquiry complete */ #define RESOLVE_NAME 0x10 diff --git a/src/dbus-hci.c b/src/dbus-hci.c index f81160434..bb16fc905 100644 --- a/src/dbus-hci.c +++ b/src/dbus-hci.c @@ -388,7 +388,9 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, struct remote_dev_info *dev, match; uint8_t name_type = 0x00; name_status_t name_status; +#if 0 int state; +#endif dbus_bool_t legacy; unsigned char features[8]; @@ -404,7 +406,8 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, if (data) write_remote_eir(local, peer, data); - +#if 0 + /* FIXME: Use HCI flags to identify this scenario */ /* * workaround to identify situation when the daemon started and * a standard inquiry or periodic inquiry was already running @@ -415,7 +418,7 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, state |= PERIODIC_INQUIRY; adapter_set_state(adapter, state); } - +#endif memset(&match, 0, sizeof(struct remote_dev_info)); bacpy(&match.bdaddr, peer); match.name_status = NAME_SENT; @@ -730,6 +733,33 @@ void hcid_dbus_setscan_enable_complete(bdaddr_t *local) btd_adapter_read_scan_enable(adapter); } +void hcid_dbus_le_set_scan_enable_complete(bdaddr_t *local, uint8_t status) +{ + struct btd_adapter *adapter; + int state; + + adapter = manager_find_adapter(local); + if (!adapter) { + error("No matching adapter found"); + return; + } + + if (status) { + error("Can't enabled/disable LE scan"); + return; + } + + state = adapter_get_state(adapter); + + /* Enabling or disabling ? */ + if (state == LE_SCAN) + state &= ~LE_SCAN; + else + state |= LE_SCAN; + + adapter_set_state(adapter, state); +} + void hcid_dbus_read_simple_pairing_mode_complete(bdaddr_t *local, void *ptr) { read_simple_pairing_mode_rp *rp = ptr; diff --git a/src/dbus-hci.h b/src/dbus-hci.h index 52526b431..4a5284321 100644 --- a/src/dbus-hci.h +++ b/src/dbus-hci.h @@ -32,6 +32,7 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status); void hcid_dbus_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status); void hcid_dbus_setscan_enable_complete(bdaddr_t *local); +void hcid_dbus_le_set_scan_enable_complete(bdaddr_t *local, uint8_t status); void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local); void hcid_dbus_read_simple_pairing_mode_complete(bdaddr_t *local, void *ptr); void hcid_dbus_returned_link_key(bdaddr_t *local, bdaddr_t *peer); diff --git a/src/security.c b/src/security.c index b9ffe61a4..2b79ae618 100644 --- a/src/security.c +++ b/src/security.c @@ -586,6 +586,8 @@ static void start_inquiry(bdaddr_t *local, uint8_t status, gboolean periodic) state = adapter_get_state(adapter); + DBG("adapter->state %#x", state); + /* Disable name resolution for non D-Bus clients */ if (!adapter_has_discov_sessions(adapter)) state &= ~RESOLVE_NAME; @@ -638,17 +640,22 @@ static void inquiry_complete(bdaddr_t *local, uint8_t status, gboolean periodic) * * Keep in mind that non D-Bus requests can arrive. */ + + state = adapter_get_state(adapter); + DBG("adapter->state %#x", state); + if (periodic) { - state = adapter_get_state(adapter); state &= ~PERIODIC_INQUIRY; adapter_set_state(adapter, state); return; } + state &= ~STD_INQUIRY; + adapter_set_state(adapter, state); + if (adapter_resolve_names(adapter) == 0) return; - state = adapter_get_state(adapter); /* * workaround to identify situation when there is no devices around * but periodic inquiry is active. @@ -718,6 +725,9 @@ static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr) case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): inquiry_complete(sba, status, FALSE); break; + case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE): + hcid_dbus_le_set_scan_enable_complete(sba, status); + break; case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): adapter_setname_complete(sba, status); break; @@ -986,7 +996,7 @@ static inline void le_metaevent(int dev, bdaddr_t *sba, void *ptr) info = (le_advertising_info *) (meta->data + 1); ba2str(&info->bdaddr, addr); - DBG("%s\n", addr); + hcid_dbus_inquiry_result(sba, &info->bdaddr, 0, 0, NULL); } static void delete_channel(GIOChannel *chan)