diff options
-rw-r--r-- | hcid/dbus-adapter.c | 87 | ||||
-rw-r--r-- | hcid/dbus.c | 100 | ||||
-rw-r--r-- | hcid/dbus.h | 3 |
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); |