diff --git a/plugins/hciops.c b/plugins/hciops.c
index 50bf254..b82d32d 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
#define DISCOV_HALTED 0
#define DISCOV_INQ 1
#define DISCOV_SCAN 2
+#define DISCOV_NAMES 3
#define TIMEOUT_BR_LE_SCAN 5120 /* TGAP(100)/2 */
#define TIMEOUT_LE_SCAN 10240 /* TGAP(gen_disc_scan_min) */
#define LENGTH_BR_INQ 0x08
#define LENGTH_BR_LE_INQ 0x04
-static int hciops_start_scanning(int index, int timeout);
+static int start_scanning(int index, int timeout);
static int child_pipe[2] = { -1, -1 };
uint8_t randomizer[16];
};
+enum name_state {
+ NAME_UNKNOWN,
+ NAME_NEEDED,
+ NAME_NOT_NEEDED,
+ NAME_PENDING,
+};
+
+struct found_dev {
+ bdaddr_t bdaddr;
+ int8_t rssi;
+ enum name_state name_state;
+};
+
static int max_dev = -1;
static struct dev_info {
int id;
GSList *connections;
+ GSList *found_devs;
+ GSList *need_name;
+
guint stop_scan_id;
} *devs = NULL;
-static inline int get_state(int index)
+static int found_dev_rssi_cmp(gconstpointer a, gconstpointer b)
{
- struct dev_info *dev = &devs[index];
+ const struct found_dev *d1 = a, *d2 = b;
+ int rssi1, rssi2;
+
+ if (d2->name_state == NAME_NOT_NEEDED)
+ return -1;
+
+ rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
+ rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
+
+ return rssi1 - rssi2;
+}
+
+static int found_dev_bda_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct found_dev *d1 = a, *d2 = b;
+
+ return bacmp(&d1->bdaddr, &d2->bdaddr);
+}
+
+static void found_dev_cleanup(struct dev_info *info)
+{
+ g_slist_free_full(info->found_devs, g_free);
+ info->found_devs = NULL;
+
+ g_slist_free_full(info->need_name, g_free);
+ info->need_name = NULL;
+}
+
+static int resolve_name(struct dev_info *info, bdaddr_t *bdaddr)
+{
+ remote_name_req_cp cp;
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+ DBG("hci%d dba %s", info->id, addr);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, bdaddr);
+ cp.pscan_rep_mode = 0x02;
+
+ if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
+ REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
+ return -errno;
- return dev->discov_state;
+ return 0;
}
-static inline gboolean is_resolvname_enabled(void)
+static int resolve_names(struct dev_info *info, struct btd_adapter *adapter)
{
- return main_opts.name_resolv ? TRUE : FALSE;
+ struct found_dev *dev;
+
+ DBG("found_dev %u need_name %u", g_slist_length(info->found_devs),
+ g_slist_length(info->need_name));
+
+ if (g_slist_length(info->need_name) == 0)
+ return -ENOENT;
+
+ dev = info->need_name->data;
+ resolve_name(info, &dev->bdaddr);
+ dev->name_state = NAME_PENDING;
+
+ return 0;
}
static void set_state(int index, int state)
switch (dev->discov_state) {
case DISCOV_HALTED:
- if (adapter_get_state(adapter) == STATE_SUSPENDED)
- return;
-
- adapter_set_state(adapter, STATE_IDLE);
+ found_dev_cleanup(dev);
+ adapter_set_discovering(adapter, FALSE);
break;
case DISCOV_INQ:
case DISCOV_SCAN:
- adapter_set_state(adapter, STATE_DISCOV);
+ adapter_set_discovering(adapter, TRUE);
+ break;
+ case DISCOV_NAMES:
+ if (resolve_names(dev, adapter) < 0)
+ set_state(index, DISCOV_HALTED);
break;
}
}
adapter_type = get_adapter_type(index);
if (adapter_type == BR_EDR_LE &&
- adapter_has_discov_sessions(adapter)) {
- int err = hciops_start_scanning(index, TIMEOUT_BR_LE_SCAN);
- if (err < 0)
- set_state(index, DISCOV_HALTED);
- } else {
- set_state(index, DISCOV_HALTED);
- }
+ start_scanning(index, TIMEOUT_BR_LE_SCAN) == 0)
+ return;
+
+ set_state(index, DISCOV_NAMES);
}
static inline void cc_inquiry_cancel(int index, uint8_t status)
static inline void cc_le_set_scan_enable(int index, uint8_t status)
{
- int state;
+ struct dev_info *info = &devs[index];
if (status) {
error("LE Set Scan Enable Failed with status 0x%02x", status);
return;
}
- state = get_state(index);
- if (state == DISCOV_SCAN)
+ if (info->discov_state == DISCOV_SCAN)
set_state(index, DISCOV_HALTED);
else
set_state(index, DISCOV_SCAN);
{
struct dev_info *dev = &devs[index];
evt_remote_name_req_complete *evt = ptr;
+ struct btd_adapter *adapter;
char name[MAX_NAME_LENGTH + 1];
+ struct found_dev *found;
+
+ GSList *match;
DBG("hci%d status %u", index, evt->status);
memset(name, 0, sizeof(name));
- if (!evt->status)
+ if (evt->status == 0) {
memcpy(name, evt->name, MAX_NAME_LENGTH);
+ btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, name);
+ }
+
+ adapter = manager_find_adapter_by_id(index);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ match = g_slist_find_custom(dev->need_name, &evt->bdaddr,
+ found_dev_bda_cmp);
+ if (match == NULL)
+ return;
+
+ found = match->data;
+ found->name_state = NAME_NOT_NEEDED;
+
+ dev->need_name = g_slist_remove_link(dev->need_name, match);
- btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, evt->status, name);
+ match->next = dev->found_devs;
+ dev->found_devs = match;
+ dev->found_devs = g_slist_sort(dev->found_devs, found_dev_rssi_cmp);
+
+ if (resolve_names(dev, adapter) < 0)
+ set_state(index, DISCOV_HALTED);
}
static inline void remote_version_information(int index, void *ptr)
btohs(evt->lmp_subver));
}
+static void dev_found(struct dev_info *info, bdaddr_t *dba, addr_type_t type,
+ uint8_t cod, int8_t rssi, uint8_t cfm_name,
+ uint8_t *eir, uint8_t eir_len)
+{
+ struct found_dev *dev;
+ GSList *match;
+
+ match = g_slist_find_custom(info->found_devs, dba, found_dev_bda_cmp);
+ if (match != NULL) {
+ cfm_name = 0;
+ goto event;
+ }
+
+ dev = g_new0(struct found_dev, 1);
+ bacpy(&dev->bdaddr, dba);
+ dev->rssi = rssi;
+ if (cfm_name)
+ dev->name_state = NAME_UNKNOWN;
+ else
+ dev->name_state = NAME_NOT_NEEDED;
+
+ info->found_devs = g_slist_prepend(info->found_devs, dev);
+
+event:
+ btd_event_device_found(&info->bdaddr, dba, type, cod, rssi, cfm_name,
+ NULL, 0);
+}
+
static inline void inquiry_result(int index, int plen, void *ptr)
{
struct dev_info *dev = &devs[index];
uint8_t num = *(uint8_t *) ptr++;
int i;
- /* Skip if it is not in Inquiry state */
- if (get_state(index) != DISCOV_INQ)
- return;
-
for (i = 0; i < num; i++) {
inquiry_info *info = ptr;
uint32_t class = info->dev_class[0] |
(info->dev_class[1] << 8) |
(info->dev_class[2] << 16);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- ADDR_TYPE_BREDR, class, 0, 0, NULL, 0);
+ dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class, 0, 1,
+ NULL, 0);
ptr += INQUIRY_INFO_SIZE;
}
}
| (info->dev_class[1] << 8)
| (info->dev_class[2] << 16);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- ADDR_TYPE_BREDR, class,
- info->rssi, 0, NULL, 0);
+ dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+ info->rssi, 1, NULL, 0);
ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
}
} else {
| (info->dev_class[1] << 8)
| (info->dev_class[2] << 16);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- ADDR_TYPE_BREDR, class,
- info->rssi, 0, NULL, 0);
+ dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+ info->rssi, 1, NULL, 0);
ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
}
}
| (info->dev_class[1] << 8)
| (info->dev_class[2] << 16);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- ADDR_TYPE_BREDR, class, info->rssi,
- 0, info->data, HCI_MAX_EIR_LENGTH);
+ dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+ info->rssi, 1, info->data, HCI_MAX_EIR_LENGTH);
ptr += EXTENDED_INQUIRY_INFO_SIZE;
}
}
info = (le_advertising_info *) &meta->data[1];
rssi = *(info->data + info->length);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- le_addr_type(info->bdaddr_type), 0, rssi, 0,
- info->data, info->length);
+ dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), 0, rssi,
+ 0, info->data, info->length);
num_reports--;
RSSI_SIZE);
rssi = *(info->data + info->length);
- btd_event_device_found(&dev->bdaddr, &info->bdaddr,
- le_addr_type(info->bdaddr_type),
- 0, rssi, 0, info->data, info->length);
+ dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
+ 0, rssi, 0, info->data, info->length);
}
}
return err;
}
-static int hciops_start_inquiry(int index, uint8_t length)
+static int start_inquiry(int index, uint8_t length)
{
struct dev_info *dev = &devs[index];
uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
return FALSE;
}
-static int hciops_start_scanning(int index, int timeout)
+static int start_scanning(int index, int timeout)
{
struct dev_info *dev = &devs[index];
le_set_scan_parameters_cp cp;
return le_set_scan_enable(index, 0);
}
-static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
-{
- struct dev_info *dev = &devs[index];
- remote_name_req_cp cp;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
- cp.pscan_rep_mode = 0x02;
-
- if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
- REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
static int hciops_set_name(int index, const char *name)
{
struct dev_info *dev = &devs[index];
return 0;
}
-static int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
+static int cancel_resolve_name(int index)
{
- struct dev_info *dev = &devs[index];
+ struct dev_info *info = &devs[index];
+ struct found_dev *dev;
remote_name_req_cancel_cp cp;
- char addr[18];
+ struct btd_adapter *adapter;
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
+ DBG("hci%d", index);
+
+ if (g_slist_length(info->need_name) == 0)
+ return 0;
+
+ dev = info->need_name->data;
+ if (dev->name_state != NAME_PENDING)
+ return 0;
memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
+ bacpy(&cp.bdaddr, &dev->bdaddr);
+
+ adapter = manager_find_adapter_by_id(index);
+ if (adapter)
+ adapter_set_discovering(adapter, FALSE);
+
+ found_dev_cleanup(info);
- if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
+ if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp) < 0)
return -errno;
{
int adapter_type = get_adapter_type(index);
+ DBG("hci%u", index);
+
switch (adapter_type) {
case BR_EDR_LE:
- return hciops_start_inquiry(index, LENGTH_BR_LE_INQ);
+ return start_inquiry(index, LENGTH_BR_LE_INQ);
case BR_EDR:
- return hciops_start_inquiry(index, LENGTH_BR_INQ);
+ return start_inquiry(index, LENGTH_BR_INQ);
case LE_ONLY:
- return hciops_start_scanning(index, TIMEOUT_LE_SCAN);
+ return start_scanning(index, TIMEOUT_LE_SCAN);
default:
return -EINVAL;
}
return hciops_stop_inquiry(index);
case DISCOV_SCAN:
return hciops_stop_scanning(index);
+ case DISCOV_NAMES:
+ cancel_resolve_name(index);
default:
return -EINVAL;
}
static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
gboolean name_known)
{
- return -ENOSYS;
+ struct dev_info *info = &devs[index];
+ struct found_dev *dev;
+ GSList *match;
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+ DBG("hci%u %s name_known %u", index, addr, name_known);
+
+ match = g_slist_find_custom(info->found_devs, bdaddr,
+ found_dev_bda_cmp);
+ if (match == NULL)
+ return -ENOENT;
+
+ dev = match->data;
+
+ if (name_known) {
+ dev->name_state = NAME_NOT_NEEDED;
+ info->found_devs = g_slist_sort(info->found_devs,
+ found_dev_rssi_cmp);
+ return 0;
+ }
+
+ dev->name_state = NAME_NEEDED;
+ info->found_devs = g_slist_remove_link(info->found_devs, match);
+
+ match->next = info->need_name;
+ info->need_name = match;
+ info->need_name = g_slist_sort(info->need_name, found_dev_rssi_cmp);
+
+ return 0;
}
static struct btd_adapter_ops hci_ops = {
.set_limited_discoverable = hciops_set_limited_discoverable,
.start_discovery = hciops_start_discovery,
.stop_discovery = hciops_stop_discovery,
- .resolve_name = hciops_resolve_name,
- .cancel_resolve_name = hciops_cancel_resolve_name,
.set_name = hciops_set_name,
.set_dev_class = hciops_set_dev_class,
.set_fast_connectable = hciops_set_fast_connectable,
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 94b721f..864f433 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
ba2str(&ev->bdaddr, addr);
DBG("hci%u addr %s, name %s", index, addr, ev->name);
- btd_event_remote_name(&info->bdaddr, &ev->bdaddr, 0, (char *) ev->name);
+ btd_event_remote_name(&info->bdaddr, &ev->bdaddr, (char *) ev->name);
}
static void mgmt_discovering(int sk, uint16_t index, void *buf, size_t len)
struct mgmt_mode *ev = buf;
struct controller_info *info;
struct btd_adapter *adapter;
- int state;
if (len < sizeof(*ev)) {
error("Too small discovering event");
if (!adapter)
return;
- if (ev->val)
- state = STATE_DISCOV;
- else
- state = STATE_IDLE;
-
- adapter_set_state(adapter, state);
+ adapter_set_discovering(adapter, ev->val);
}
static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
return 0;
}
-static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
-{
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("index %d addr %s", index, addr);
-
- return -ENOSYS;
-}
-
static int mgmt_set_name(int index, const char *name)
{
char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_local_name)];
return 0;
}
-static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
-{
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("index %d addr %s", index, addr);
-
- return -ENOSYS;
-}
-
static int mgmt_set_fast_connectable(int index, gboolean enable)
{
char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
.set_limited_discoverable = mgmt_set_limited_discoverable,
.start_discovery = mgmt_start_discovery,
.stop_discovery = mgmt_stop_discovery,
- .resolve_name = mgmt_resolve_name,
- .cancel_resolve_name = mgmt_cancel_resolve_name,
.set_name = mgmt_set_name,
.set_dev_class = mgmt_set_dev_class,
.set_fast_connectable = mgmt_set_fast_connectable,
diff --git a/src/adapter.c b/src/adapter.c
index 2d9e368..8a3608c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
GSList *devices; /* Devices structure pointers */
GSList *mode_sessions; /* Request Mode sessions */
GSList *disc_sessions; /* Discovery sessions */
- guint scheduler_id; /* Scheduler handle */
+ guint discov_id; /* Discovery timer */
+ gboolean discovering; /* Discovery active */
+ gboolean discov_suspended; /* Discovery suspended */
guint auto_timeout_id; /* Automatic connections timeout */
sdp_list_t *services; /* Services associated to adapter */
GSList *loaded_drivers;
};
-static int found_device_cmp(const struct remote_dev_info *d1,
- const struct remote_dev_info *d2)
-{
- int ret;
-
- if (bacmp(&d2->bdaddr, BDADDR_ANY)) {
- ret = bacmp(&d1->bdaddr, &d2->bdaddr);
- if (ret)
- return ret;
- }
-
- if (d2->name_status != NAME_ANY) {
- ret = (d1->name_status - d2->name_status);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static void dev_info_free(void *data)
{
struct remote_dev_info *dev = data;
return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
}
-static int pending_remote_name_cancel(struct btd_adapter *adapter)
-{
- struct remote_dev_info *dev, match;
- int err;
-
- /* find the pending remote name request */
- memset(&match, 0, sizeof(struct remote_dev_info));
- bacpy(&match.bdaddr, BDADDR_ANY);
- match.name_status = NAME_REQUESTED;
-
- dev = adapter_search_found_devices(adapter, &match);
- if (!dev) /* no pending request */
- return -ENODATA;
-
- err = adapter_ops->cancel_resolve_name(adapter->dev_id, &dev->bdaddr);
- if (err < 0)
- error("Remote name cancel failed: %s(%d)",
- strerror(errno), errno);
-
- adapter_set_state(adapter, STATE_IDLE);
-
- return err;
-}
-
-static int adapter_resolve_names(struct btd_adapter *adapter)
-{
- struct remote_dev_info *dev, match;
- int err;
-
- /* Do not attempt to resolve more names if on suspended state */
- if (adapter->state == STATE_SUSPENDED)
- return 0;
-
- memset(&match, 0, sizeof(struct remote_dev_info));
- bacpy(&match.bdaddr, BDADDR_ANY);
- match.name_status = NAME_REQUIRED;
-
- dev = adapter_search_found_devices(adapter, &match);
- if (!dev)
- return -ENODATA;
-
- /* send at least one request or return failed if the list is empty */
- do {
- /* flag to indicate the current remote name requested */
- dev->name_status = NAME_REQUESTED;
-
- err = adapter_ops->resolve_name(adapter->dev_id, &dev->bdaddr);
-
- if (!err)
- break;
-
- error("Unable to send HCI remote name req: %s (%d)",
- strerror(errno), errno);
-
- /* if failed, request the next element */
- /* remove the element from the list */
- adapter_remove_found_device(adapter, &dev->bdaddr);
-
- /* get the next element */
- dev = adapter_search_found_devices(adapter, &match);
- } while (dev);
-
- return err;
-}
-
static const char *mode2str(uint8_t mode)
{
switch(mode) {
return le;
}
+/* Called when a session gets removed or the adapter is stopped */
static void stop_discovery(struct btd_adapter *adapter)
{
- pending_remote_name_cancel(adapter);
-
adapter->found_devices = remove_bredr(adapter->found_devices);
if (adapter->oor_devices) {
}
/* Reset if suspended, otherwise remove timer (software scheduler)
- or request inquiry to stop */
- if (adapter->state == STATE_SUSPENDED) {
- adapter_set_state(adapter, STATE_IDLE);
+ * or request inquiry to stop */
+ if (adapter->discov_suspended) {
+ adapter->discov_suspended = FALSE;
return;
}
- if (adapter->scheduler_id) {
- g_source_remove(adapter->scheduler_id);
- adapter->scheduler_id = 0;
+ if (adapter->discov_id > 0) {
+ g_source_remove(adapter->discov_id);
+ adapter->discov_id = 0;
return;
}
ADDR_TYPE_BREDR);
}
-static int start_discovery(struct btd_adapter *adapter)
-{
- /* Do not start if suspended */
- if (adapter->state == STATE_SUSPENDED)
- return 0;
-
- /* Postpone discovery if still resolving names */
- if (adapter->state == STATE_RESOLVNAME)
- return -EINPROGRESS;
-
- pending_remote_name_cancel(adapter);
-
- return adapter_ops->start_discovery(adapter->dev_id);
-}
-
static gboolean discovery_cb(gpointer user_data)
{
struct btd_adapter *adapter = user_data;
int err;
- err = start_discovery(adapter);
- if (err == -EINPROGRESS)
- return TRUE;
- else if (err < 0)
+ adapter->discov_id = 0;
+
+ err = adapter_ops->start_discovery(adapter->dev_id);
+ if (err < 0)
error("start_discovery: %s (%d)", strerror(-err), -err);
return FALSE;
g_slist_free(adapter->oor_devices);
adapter->oor_devices = NULL;
- err = start_discovery(adapter);
- if (err < 0 && err != -EINPROGRESS)
+ if (adapter->discov_suspended)
+ goto done;
+
+ err = adapter_ops->start_discovery(adapter->dev_id);
+ if (err < 0)
return btd_error_failed(msg, strerror(-err));
done:
DBUS_TYPE_UINT32, &adapter->pairable_timeout);
- if (adapter->state == STATE_DISCOV)
- value = TRUE;
- else
- value = FALSE;
-
/* Discovering */
- dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN, &value);
+ dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN,
+ &adapter->discovering);
/* Devices */
devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
struct btd_adapter *adapter,
const char *address, int *err)
{
- struct remote_dev_info *dev, match;
+ struct remote_dev_info *dev;
struct btd_device *device;
+ bdaddr_t addr;
addr_type_t type;
- memset(&match, 0, sizeof(struct remote_dev_info));
- str2ba(address, &match.bdaddr);
- match.name_status = NAME_ANY;
+ str2ba(address, &addr);
- dev = adapter_search_found_devices(adapter, &match);
+ dev = adapter_search_found_devices(adapter, &addr);
if (dev)
type = dev->type;
else
adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
}
-static void update_oor_devices(struct btd_adapter *adapter)
-{
- g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
- g_slist_free_full(adapter->oor_devices, dev_info_free);
- adapter->oor_devices = g_slist_copy(adapter->found_devices);
-}
-
void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
uint8_t *on_mode, gboolean *pairable)
{
adapter->up = TRUE;
adapter->discov_timeout = get_discoverable_timeout(address);
adapter->pairable_timeout = get_pairable_timeout(address);
- adapter->state = STATE_IDLE;
adapter->mode = MODE_CONNECTABLE;
adapter->off_timer = 0;
ADAPTER_INTERFACE, "Pairable",
DBUS_TYPE_BOOLEAN, &prop_false);
- if (adapter->state != STATE_IDLE)
+ if (adapter->discovering)
emit_property_changed(connection, adapter->path,
ADAPTER_INTERFACE, "Discovering",
DBUS_TYPE_BOOLEAN, &prop_false);
adapter->up = FALSE;
adapter->scan_mode = SCAN_DISABLED;
adapter->mode = MODE_OFF;
- adapter->state = STATE_IDLE;
adapter->off_requested = FALSE;
call_adapter_powered_callbacks(adapter, FALSE);
adapter->allow_name_changes = allow_name_changes;
}
-static inline void suspend_discovery(struct btd_adapter *adapter)
+void adapter_set_discovering(struct btd_adapter *adapter,
+ gboolean discovering)
{
- if (adapter->state != STATE_SUSPENDED)
- return;
+ const char *path = adapter->path;
- if (adapter->oor_devices) {
- g_slist_free(adapter->oor_devices);
- adapter->oor_devices = NULL;
- }
+ adapter->discovering = discovering;
- if (adapter->scheduler_id) {
- g_source_remove(adapter->scheduler_id);
- adapter->scheduler_id = 0;
- }
+ emit_property_changed(connection, path,
+ ADAPTER_INTERFACE, "Discovering",
+ DBUS_TYPE_BOOLEAN, &discovering);
- adapter_ops->stop_discovery(adapter->dev_id);
-}
+ if (discovering)
+ return;
-void adapter_set_state(struct btd_adapter *adapter, int state)
-{
- const char *path = adapter->path;
- gboolean discov_active;
+ g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
+ g_slist_free_full(adapter->oor_devices, dev_info_free);
+ adapter->oor_devices = g_slist_copy(adapter->found_devices);
- if (adapter->state == state)
+ if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
return;
- adapter->state = state;
-
- DBG("hci%d: new state %d", adapter->dev_id, adapter->state);
+ DBG("hci%u enabling timer, disc_sessions %u", adapter->dev_id,
+ g_slist_length(adapter->disc_sessions));
- switch (adapter->state) {
- case STATE_IDLE:
- if (main_opts.name_resolv &&
- adapter_has_discov_sessions(adapter) &&
- adapter_resolve_names(adapter) == 0) {
- adapter->state = STATE_RESOLVNAME;
- return;
- }
+ adapter->discov_id = g_timeout_add_seconds(main_opts.discov_interval,
+ discovery_cb, adapter);
+}
- update_oor_devices(adapter);
+static void suspend_discovery(struct btd_adapter *adapter)
+{
+ if (adapter->disc_sessions == NULL || adapter->discov_suspended)
+ return;
- discov_active = FALSE;
- emit_property_changed(connection, path,
- ADAPTER_INTERFACE, "Discovering",
- DBUS_TYPE_BOOLEAN, &discov_active);
+ DBG("Suspending discovery");
- if (adapter_has_discov_sessions(adapter)) {
- adapter->scheduler_id = g_timeout_add_seconds(
- main_opts.discov_interval,
- discovery_cb, adapter);
- }
- break;
- case STATE_DISCOV:
- discov_active = TRUE;
- emit_property_changed(connection, path,
- ADAPTER_INTERFACE, "Discovering",
- DBUS_TYPE_BOOLEAN, &discov_active);
- break;
- case STATE_SUSPENDED:
- suspend_discovery(adapter);
- break;
+ if (adapter->oor_devices) {
+ g_slist_free(adapter->oor_devices);
+ adapter->oor_devices = NULL;
}
+
+ adapter->discov_suspended = TRUE;
+
+ if (adapter->discov_id > 0) {
+ g_source_remove(adapter->discov_id);
+ adapter->discov_id = 0;
+ } else
+ adapter_ops->stop_discovery(adapter->dev_id);
}
-int adapter_get_state(struct btd_adapter *adapter)
+static int found_device_cmp(gconstpointer a, gconstpointer b)
{
- return adapter->state;
+ const struct remote_dev_info *d = a;
+ const bdaddr_t *bdaddr = b;
+
+ if (bacmp(bdaddr, BDADDR_ANY) == 0)
+ return 0;
+
+ return bacmp(&d->bdaddr, bdaddr);
}
struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
- struct remote_dev_info *match)
+ bdaddr_t *bdaddr)
{
GSList *l;
- l = g_slist_find_custom(adapter->found_devices, match,
- (GCompareFunc) found_device_cmp);
+ l = g_slist_find_custom(adapter->found_devices, bdaddr,
+ found_device_cmp);
if (l)
return l->data;
static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr,
addr_type_t type, const char *name,
const char *alias, uint32_t class,
- gboolean legacy, name_status_t status,
- int flags)
+ gboolean legacy, int flags)
{
struct remote_dev_info *dev;
dev->alias = g_strdup(alias);
dev->class = class;
dev->legacy = legacy;
- dev->name_status = status;
if (flags >= 0)
dev->flags = flags;
uint8_t confirm_name,
uint8_t *data, uint8_t data_len)
{
- struct remote_dev_info *dev, match;
+ struct remote_dev_info *dev;
struct eir_data eir_data;
char *alias, *name;
- gboolean legacy;
- name_status_t name_status;
+ gboolean legacy, name_known;
int err;
memset(&eir_data, 0, sizeof(eir_data));
if (eir_data.name != NULL && eir_data.name_complete)
write_device_name(&adapter->bdaddr, bdaddr, eir_data.name);
- /* Device already seen in the discovery session ? */
- memset(&match, 0, sizeof(struct remote_dev_info));
- bacpy(&match.bdaddr, bdaddr);
- match.name_status = NAME_ANY;
-
- dev = adapter_search_found_devices(adapter, &match);
+ dev = adapter_search_found_devices(adapter, bdaddr);
if (dev) {
adapter->oor_devices = g_slist_remove(adapter->oor_devices,
dev);
if (!name && main_opts.name_resolv &&
adapter_has_discov_sessions(adapter))
- name_status = NAME_REQUIRED;
+ name_known = FALSE;
else
- name_status = NAME_NOT_REQUIRED;
+ name_known = TRUE;
} else {
legacy = FALSE;
- name_status = NAME_NOT_REQUIRED;
+ name_known = TRUE;
}
- if (confirm_name) {
- gboolean name_known;
-
- if (name_status == NAME_REQUIRED)
- name_known = FALSE;
- else
- name_known = TRUE;
-
- adapter_ops->confirm_name(adapter->dev_id, bdaddr,
- name_known);
- }
+ if (confirm_name)
+ adapter_ops->confirm_name(adapter->dev_id, bdaddr, name_known);
alias = read_stored_data(&adapter->bdaddr, bdaddr, "aliases");
dev = found_device_new(bdaddr, type, name, alias, class, legacy,
- name_status, eir_data.flags);
+ eir_data.flags);
free(name);
free(alias);
eir_data_free(&eir_data);
}
-int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
- struct remote_dev_info *dev, match;
-
- memset(&match, 0, sizeof(struct remote_dev_info));
- bacpy(&match.bdaddr, bdaddr);
-
- dev = adapter_search_found_devices(adapter, &match);
- if (!dev)
- return -1;
-
- dev->name_status = NAME_NOT_REQUIRED;
-
- return 0;
-}
-
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
{
const gchar *path = adapter_get_path(adapter);
return TRUE;
}
-void adapter_suspend_discovery(struct btd_adapter *adapter)
-{
- if (adapter->disc_sessions == NULL ||
- adapter->state == STATE_SUSPENDED)
- return;
-
- DBG("Suspending discovery");
-
- adapter_set_state(adapter, STATE_SUSPENDED);
-}
-
-void adapter_resume_discovery(struct btd_adapter *adapter)
-{
- DBG("Resuming discovery");
-
- adapter_set_state(adapter, STATE_IDLE);
-}
-
int btd_register_adapter_driver(struct btd_adapter_driver *driver)
{
adapter_drivers = g_slist_append(adapter_drivers, driver);
int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
uint8_t io_cap)
{
+ suspend_discovery(adapter);
return adapter_ops->create_bonding(adapter->dev_id, bdaddr, io_cap);
}
return adapter_ops->cancel_bonding(adapter->dev_id, bdaddr);
}
+void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+ uint8_t status)
+{
+ struct btd_device *device;
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+ if (status == 0)
+ device = adapter_get_device(connection, adapter, addr);
+ else
+ device = adapter_find_device(adapter, addr);
+
+ if (device != NULL)
+ device_bonding_complete(device, status);
+
+ if (adapter->discov_suspended) {
+ adapter->discov_suspended = FALSE;
+ adapter_ops->start_discovery(adapter->dev_id);
+ }
+}
+
int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
{
return adapter_ops->read_local_oob_data(adapter->dev_id);
diff --git a/src/adapter.h b/src/adapter.h
index 3e93441..808c557 100644
--- a/src/adapter.h
+++ b/src/adapter.h
#define MODE_DISCOVERABLE 0x02
#define MODE_UNKNOWN 0xff
-/* Discover states */
-#define STATE_IDLE 0
-#define STATE_DISCOV 1
-#define STATE_RESOLVNAME 2
-#define STATE_SUSPENDED 3
-
#define MAX_NAME_LENGTH 248
/* Invalid SSP passkey value used to indicate negative replies */
#define INVALID_PASSKEY 0xffffffff
typedef enum {
- NAME_ANY,
- NAME_NOT_REQUIRED, /* used by get remote name without name resolving */
- NAME_REQUIRED, /* remote name needs be resolved */
- NAME_REQUESTED, /* HCI remote name request was sent */
-} name_status_t;
-
-typedef enum {
ADDR_TYPE_BREDR,
ADDR_TYPE_LE_PUBLIC,
ADDR_TYPE_LE_RANDOM,
char *name;
char *alias;
dbus_bool_t legacy;
- name_status_t name_status;
char **uuids;
size_t uuid_count;
GSList *services;
void adapter_remove(struct btd_adapter *adapter);
void adapter_set_allow_name_changes(struct btd_adapter *adapter,
gboolean allow_name_changes);
+void adapter_set_discovering(struct btd_adapter *adapter,
+ gboolean discovering);
uint16_t adapter_get_dev_id(struct btd_adapter *adapter);
const gchar *adapter_get_path(struct btd_adapter *adapter);
void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
void adapter_set_state(struct btd_adapter *adapter, int state);
int adapter_get_state(struct btd_adapter *adapter);
struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
- struct remote_dev_info *match);
+ bdaddr_t *bdaddr);
void adapter_update_found_devices(struct btd_adapter *adapter,
bdaddr_t *bdaddr, addr_type_t type,
uint32_t class, int8_t rssi,
uint8_t confirm_name,
uint8_t *data, uint8_t data_len);
-int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr);
void adapter_emit_device_found(struct btd_adapter *adapter,
struct remote_dev_info *dev);
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
void adapter_remove_connection(struct btd_adapter *adapter,
struct btd_device *device);
gboolean adapter_has_discov_sessions(struct btd_adapter *adapter);
-void adapter_suspend_discovery(struct btd_adapter *adapter);
-void adapter_resume_discovery(struct btd_adapter *adapter);
struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter);
void btd_adapter_unref(struct btd_adapter *adapter);
int (*start_discovery) (int index);
int (*stop_discovery) (int index);
- int (*resolve_name) (int index, bdaddr_t *bdaddr);
- int (*cancel_resolve_name) (int index, bdaddr_t *bdaddr);
int (*set_name) (int index, const char *name);
int (*set_dev_class) (int index, uint8_t major, uint8_t minor);
int (*set_fast_connectable) (int index, gboolean enable);
int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
+void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+ uint8_t status);
+
int btd_adapter_read_local_oob_data(struct btd_adapter *adapter);
int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
diff --git a/src/device.c b/src/device.c
index e49e9bc..570f678 100644
--- a/src/device.c
+++ b/src/device.c
device->bonding = NULL;
- adapter_resume_discovery(device->adapter);
-
if (!device->agent)
return;
bonding->conn = dbus_connection_ref(conn);
bonding->msg = dbus_message_ref(msg);
- adapter_suspend_discovery(device->adapter);
-
return bonding;
}
diff --git a/src/event.c b/src/event.c
index 4e61666..2be4bfe 100644
--- a/src/event.c
+++ b/src/event.c
if (!get_adapter_and_device(local, peer, &adapter, &device, create))
return;
- if (device)
- device_bonding_complete(device, status);
+ adapter_bonding_complete(adapter, peer, status);
}
void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
gboolean legacy)
{
struct btd_adapter *adapter;
- struct remote_dev_info *dev, match;
+ struct remote_dev_info *dev;
adapter = manager_find_adapter(local);
if (!adapter) {
return;
}
- memset(&match, 0, sizeof(struct remote_dev_info));
- bacpy(&match.bdaddr, peer);
- match.name_status = NAME_ANY;
-
- dev = adapter_search_found_devices(adapter, &match);
+ dev = adapter_search_found_devices(adapter, peer);
if (dev)
dev->legacy = legacy;
}
device_set_class(device, class);
}
-void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
- char *name)
+void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
{
struct btd_adapter *adapter;
- char srcaddr[18], dstaddr[18];
+ char srcaddr[18];
struct btd_device *device;
- struct remote_dev_info match, *dev_info;
-
- if (status == 0) {
- if (!g_utf8_validate(name, -1, NULL)) {
- int i;
-
- /* Assume ASCII, and replace all non-ASCII with
- * spaces */
- for (i = 0; name[i] != '\0'; i++) {
- if (!isascii(name[i]))
- name[i] = ' ';
- }
- /* Remove leading and trailing whitespace characters */
- g_strstrip(name);
- }
+ struct remote_dev_info *dev_info;
- write_device_name(local, peer, name);
+ if (!g_utf8_validate(name, -1, NULL)) {
+ int i;
+
+ /* Assume ASCII, and replace all non-ASCII with spaces */
+ for (i = 0; name[i] != '\0'; i++) {
+ if (!isascii(name[i]))
+ name[i] = ' ';
+ }
+ /* Remove leading and trailing whitespace characters */
+ g_strstrip(name);
}
+ write_device_name(local, peer, name);
+
if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
return;
ba2str(local, srcaddr);
- ba2str(peer, dstaddr);
-
- if (status != 0)
- goto proceed;
-
- bacpy(&match.bdaddr, peer);
- match.name_status = NAME_ANY;
- dev_info = adapter_search_found_devices(adapter, &match);
+ dev_info = adapter_search_found_devices(adapter, peer);
if (dev_info) {
g_free(dev_info->name);
dev_info->name = g_strdup(name);
if (device)
device_set_name(device, name);
-
-proceed:
- /* remove from remote name request list */
- adapter_remove_found_device(adapter, peer);
-
- adapter_set_state(adapter, STATE_IDLE);
}
int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
diff --git a/src/event.h b/src/event.h
index f91b42f..1f352f8 100644
--- a/src/event.h
+++ b/src/event.h
uint8_t *data, uint8_t data_len);
void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy);
void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
-void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name);
+void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name);
void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer);
void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer);