summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hcid/dbus-adapter.c87
-rw-r--r--hcid/dbus.c100
-rw-r--r--hcid/dbus.h3
3 files changed, 117 insertions, 73 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c
index 6a1573f3..dab3255f 100644
--- a/hcid/dbus-adapter.c
+++ b/hcid/dbus-adapter.c
@@ -2237,6 +2237,10 @@ static DBusHandlerResult handle_dev_discover_devices_req(DBusConnection *conn, D
hci_close_dev(dd);
+ /* track the request owner to cancel it automatically if the owner exits */
+ name_listener_add(conn, dbus_message_get_sender(msg),
+ (name_cb_t) discover_devices_req_exit, dbus_data);
+
return send_reply_and_unref(conn, reply);
}
@@ -2244,14 +2248,8 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D
{
DBusMessage *reply = NULL;
const char *requestor_name;
- struct discovered_dev_info *dev, match;
- struct slist *l;
- struct hci_request rq;
- remote_name_req_cancel_cp cp;
struct hci_dbus_data *dbus_data = data;
- uint8_t status = 0x00;
- int dd = -1;
- DBusHandlerResult ret_val = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ int err;
if (!dbus_data->up)
return error_not_ready(conn, msg);
@@ -2270,74 +2268,21 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D
if (!dbus_data->discovery_requestor ||
strcmp(dbus_data->discovery_requestor, requestor_name))
return error_not_authorized(conn, msg);
+ /*
+ * Cleanup the discovered devices list and send the cmd
+ * to cancel inquiry or cancel remote name request
+ */
+ err = cancel_discovery(dbus_data);
+ if (err < 0) {
+ if (err == -ENODEV)
+ return error_no_such_adapter(conn, msg);
+ else
+ return error_failed(conn, msg, -err);
- dd = hci_open_dev(dbus_data->dev_id);
- if (dd < 0)
- return error_no_such_adapter(conn, msg);
-
- memset(&rq, 0, sizeof(rq));
- memset(&cp, 0, sizeof(cp));
-
- rq.ogf = OGF_LINK_CTL;
-
- rq.rparam = &status;
- rq.rlen = sizeof(status);
- rq.event = EVT_CMD_COMPLETE;
-
- switch (dbus_data->discover_state) {
- case STATE_RESOLVING_NAMES:
- /* find the pending remote name request */
- memset(&match, 0, sizeof(struct discovered_dev_info));
- bacpy(&match.bdaddr, BDADDR_ANY);
- match.name_status = NAME_REQUESTED;
- match.discover_type = RESOLVE_NAME;
-
- l = slist_find(dbus_data->disc_devices, &match, (cmp_func_t) disc_device_find);
- if (!l)
- goto done; /* no request pending */
-
- dev = l->data;
-
- bacpy(&cp.bdaddr, &dev->bdaddr);
-
- rq.ocf = OCF_REMOTE_NAME_REQ_CANCEL;
- rq.cparam = &cp;
- rq.clen = REMOTE_NAME_REQ_CANCEL_CP_SIZE;
- break;
- default: /* STATE_DISCOVER */
- rq.ocf = OCF_INQUIRY_CANCEL;
- break;
- }
-
- if (hci_send_req(dd, &rq, 100) < 0) {
- error("Sending command failed: %s (%d)", strerror(errno), errno);
- ret_val = error_failed(conn, msg, errno);
- goto cleanup;
- }
-
- if (status) {
- error("Cancel failed with status 0x%02x", status);
- ret_val = error_failed(conn, msg, bt_error(status));
- goto cleanup;
}
-done:
reply = dbus_message_new_method_return(msg);
- ret_val = send_reply_and_unref(conn, reply);
-
-cleanup:
- /*
- * Reset discovery_requestor and discover_state in the remote name
- * request event handler or in the inquiry complete handler.
- */
- slist_foreach(dbus_data->disc_devices, (slist_func_t) free, NULL);
- slist_free(dbus_data->disc_devices);
- dbus_data->disc_devices = NULL;
-
- if (dd >= 0)
- hci_close_dev(dd);
-
- return ret_val;
+ return send_reply_and_unref(conn, reply);
}
const char *major_class_str(uint32_t class)
diff --git a/hcid/dbus.c b/hcid/dbus.c
index f82845d3..f3333e6d 100644
--- a/hcid/dbus.c
+++ b/hcid/dbus.c
@@ -85,7 +85,7 @@ void bonding_request_free(struct bonding_request_info *dev )
}
}
-int disc_device_find(const struct discovered_dev_info *d1, const struct discovered_dev_info *d2)
+static int disc_device_find(const struct discovered_dev_info *d1, const struct discovered_dev_info *d2)
{
int ret;
@@ -406,6 +406,8 @@ static int unregister_dbus_path(const char *path)
release_passkey_agents(pdata, NULL);
if (pdata->discovery_requestor) {
+ name_listener_remove(connection, pdata->discovery_requestor,
+ (name_cb_t) discover_devices_req_exit, pdata);
free(pdata->discovery_requestor);
pdata->discovery_requestor = NULL;
}
@@ -648,6 +650,8 @@ int hcid_dbus_stop_device(uint16_t id)
release_passkey_agents(pdata, NULL);
if (pdata->discovery_requestor) {
+ name_listener_remove(connection, pdata->discovery_requestor,
+ (name_cb_t) discover_devices_req_exit, pdata);
free(pdata->discovery_requestor);
pdata->discovery_requestor = NULL;
}
@@ -999,6 +1003,8 @@ void hcid_dbus_inquiry_complete(bdaddr_t *local)
pdata->disc_devices = NULL;
if (pdata->discovery_requestor) {
+ name_listener_remove(connection, pdata->discovery_requestor,
+ (name_cb_t) discover_devices_req_exit, pdata);
free(pdata->discovery_requestor);
pdata->discovery_requestor = NULL;
}
@@ -1189,6 +1195,8 @@ void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char
send_reply_and_unref(connection, message);
if (pdata->discovery_requestor) {
+ name_listener_remove(connection, pdata->discovery_requestor,
+ (name_cb_t) discover_devices_req_exit, pdata);
free(pdata->discovery_requestor);
pdata->discovery_requestor = NULL;
}
@@ -2028,3 +2036,93 @@ void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata)
bonding_request_free(pdata->bonding);
pdata->bonding = NULL;
}
+
+void discover_devices_req_exit(const char *name, struct hci_dbus_data *pdata)
+{
+ debug("DiscoverDevices requestor at %s exited before the operation finishes", name);
+
+ /*
+ * Cleanup the discovered devices list and send the cmd to cancel inquiry
+ * or cancel remote name request. The return value can be ignored.
+ */
+ cancel_discovery(pdata);
+}
+
+int cancel_discovery(struct hci_dbus_data *pdata)
+{
+ struct discovered_dev_info *dev, match;
+ struct slist *l;
+ struct hci_request rq;
+ remote_name_req_cancel_cp cp;
+ int dd = -1, err = 0;
+ uint8_t status = 0x00;
+
+ dd = hci_open_dev(pdata->dev_id);
+ if (dd < 0) {
+ err = -ENODEV;
+ goto cleanup;
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ memset(&cp, 0, sizeof(cp));
+
+ rq.ogf = OGF_LINK_CTL;
+
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ switch (pdata->discover_state) {
+ case STATE_RESOLVING_NAMES:
+ /* find the pending remote name request */
+ memset(&match, 0, sizeof(struct discovered_dev_info));
+ bacpy(&match.bdaddr, BDADDR_ANY);
+ match.name_status = NAME_REQUESTED;
+ match.discover_type = RESOLVE_NAME;
+
+ l = slist_find(pdata->disc_devices, &match, (cmp_func_t) disc_device_find);
+ if (!l)
+ goto cleanup; /* no request pending */
+
+ dev = l->data;
+
+ bacpy(&cp.bdaddr, &dev->bdaddr);
+
+ rq.ocf = OCF_REMOTE_NAME_REQ_CANCEL;
+ rq.cparam = &cp;
+ rq.clen = REMOTE_NAME_REQ_CANCEL_CP_SIZE;
+ break;
+ case STATE_DISCOVER:
+ rq.ocf = OCF_INQUIRY_CANCEL;
+ break;
+ default:
+ /* discover is not pending */
+ goto cleanup;
+ }
+
+ if (hci_send_req(dd, &rq, 100) < 0) {
+ error("Sending command failed: %s (%d)", strerror(errno), errno);
+ err = -errno;
+ goto cleanup;
+ }
+
+ if (status) {
+ error("Cancel failed with status 0x%02x", status);
+ err = -bt_error(status);
+ goto cleanup;
+ }
+
+cleanup:
+ /*
+ * Reset discovery_requestor and discover_state in the remote name
+ * request event handler or in the inquiry complete handler.
+ */
+ slist_foreach(pdata->disc_devices, (slist_func_t) free, NULL);
+ slist_free(pdata->disc_devices);
+ pdata->disc_devices = NULL;
+
+ if (dd >= 0)
+ hci_close_dev(dd);
+
+ return err;
+}
diff --git a/hcid/dbus.h b/hcid/dbus.h
index ecaf008b..3a3bd62e 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -205,6 +205,8 @@ DBusHandlerResult simple_introspect(DBusConnection *conn, DBusMessage *msg, void
service_handler_func_t find_service_handler(struct service_data *services, DBusMessage *msg);
void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata);
+void discover_devices_req_exit(const char *name, struct hci_dbus_data *pdata);
+int cancel_discovery(struct hci_dbus_data *pdata);
int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba);
void release_default_agent(void);
@@ -226,7 +228,6 @@ int active_conn_find_by_bdaddr(const void *data, const void *user_data);
void bonding_request_free(struct bonding_request_info *dev);
int pending_bonding_cmp(const void *p1, const void *p2);
int disc_device_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status, int discover_type);
-int disc_device_find(const struct discovered_dev_info *d1, const struct discovered_dev_info *d2);
int disc_device_req_name(struct hci_dbus_data *dbus_data);
int discoverable_timeout_handler(void *data);