diff options
Diffstat (limited to 'hcid')
-rw-r--r-- | hcid/dbus-adapter.c | 55 | ||||
-rw-r--r-- | hcid/dbus-error.c | 7 | ||||
-rw-r--r-- | hcid/dbus.c | 202 | ||||
-rw-r--r-- | hcid/dbus.h | 7 |
4 files changed, 158 insertions, 113 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index ebc532dc..36c47e0b 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -105,7 +105,7 @@ static int bonding_requests_append(struct slist **list, bdaddr_t *bdaddr, DBusMe return -1; dev->bdaddr = malloc(sizeof(*dev->bdaddr)); - memcpy(dev->bdaddr, bdaddr, sizeof(*dev->bdaddr)); + bacpy(dev->bdaddr, bdaddr); dev->msg = msg; dev->bonding_state = bonding_state; @@ -811,13 +811,14 @@ static DBusHandlerResult handle_dev_get_remote_name_req(DBusConnection *conn, DB struct hci_dbus_data *dbus_data = data; DBusMessage *reply = NULL; DBusError err; - const char *str_bdaddr; - char *name; + const char *peer_addr; + bdaddr_t peer_bdaddr; + char *str; int ecode; dbus_error_init(&err); dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &str_bdaddr, + DBUS_TYPE_STRING, &peer_addr, DBUS_TYPE_INVALID); if (dbus_error_is_set(&err)) { @@ -827,28 +828,48 @@ static DBusHandlerResult handle_dev_get_remote_name_req(DBusConnection *conn, DB } ecode = get_device_address(dbus_data->dev_id, addr, sizeof(addr)); - if (ecode< 0) + if (ecode < 0) return error_failed(conn, msg, -ecode); + /* check if it is a unknown address */ + snprintf(filename, PATH_MAX, "%s/%s/lastseen", STORAGEDIR, addr); + + str = textfile_get(filename, peer_addr); + + if (!str) + return error_unknown_address(conn, msg); + + free(str); + + /* check if it is in the cache */ snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, addr); - name = textfile_get(filename, str_bdaddr); + str = textfile_get(filename, peer_addr); - if (!name) - return error_record_does_not_exist(conn, msg); + if (str) { + reply = dbus_message_new_method_return(msg); + if (!reply) { + free(str); + return error_out_of_memory(conn, msg); + } - reply = dbus_message_new_method_return(msg); - if (!reply) { - free(name); - return error_out_of_memory(conn, msg); + /* send the cached name */ + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + + free(str); + return send_reply_and_unref(conn, reply); } - dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID); + /* put the request name in the queue to resolve name */ + str2ba(peer_addr, &peer_bdaddr); + remote_name_append(&dbus_data->discovered_devices, &peer_bdaddr, NAME_PENDING); - free(name); + /* check if there is a discover process running */ + if (dbus_data->discover_state == DISCOVER_OFF) + remote_name_resolve(dbus_data); - return send_reply_and_unref(conn, reply); + return error_request_deferred(conn, msg); } static DBusHandlerResult handle_dev_get_remote_alias_req(DBusConnection *conn, DBusMessage *msg, void *data) @@ -1492,7 +1513,7 @@ static DBusHandlerResult handle_dev_cancel_discovery_req(DBusConnection *conn, D /* get the first element */ addr = (bdaddr_t *) (dbus_data->discovered_devices)->data; - memcpy(&cp.bdaddr, addr, sizeof(bdaddr_t)); + bacpy(&cp.bdaddr, addr); rq.ocf = OCF_REMOTE_NAME_REQ_CANCEL; rq.cparam = &cp; diff --git a/hcid/dbus-error.c b/hcid/dbus-error.c index 100de9b0..375456bd 100644 --- a/hcid/dbus-error.c +++ b/hcid/dbus-error.c @@ -90,6 +90,13 @@ DBusHandlerResult error_not_available(DBusConnection *conn, DBusMessage *msg) "Not available")); } +DBusHandlerResult error_request_deferred(DBusConnection *conn, DBusMessage *msg) +{ + return send_reply_and_unref(conn, + dbus_message_new_error(msg, ERROR_INTERFACE ".RequestDeferred", + "Request Deferred")); +} + DBusHandlerResult error_not_connected(DBusConnection *conn, DBusMessage *msg) { return send_reply_and_unref(conn, diff --git a/hcid/dbus.c b/hcid/dbus.c index 919f7456..ac00e8d1 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -122,15 +122,15 @@ int bonding_requests_find(const void *data, const void *user_data) int remote_name_find_by_bdaddr(const void *data, const void *user_data) { const struct discovered_dev_info *dev = data; - const bdaddr_t *baddr = user_data; + const bdaddr_t *bdaddr = user_data; - if (memcmp(dev->bdaddr, baddr, sizeof(*baddr)) == 0) + if (memcmp(dev->bdaddr, bdaddr, sizeof(*bdaddr)) == 0) return 0; return -1; } -int remote_name_find_by_name_status(const void *data, const void *user_data) +static int remote_name_find_by_name_status(const void *data, const void *user_data) { const struct discovered_dev_info *dev = data; const name_status_t *name_status = user_data; @@ -141,7 +141,7 @@ int remote_name_find_by_name_status(const void *data, const void *user_data) return -1; } -static int remote_name_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status) +int remote_name_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status) { struct discovered_dev_info *dev = NULL; struct slist *l; @@ -161,11 +161,10 @@ static int remote_name_append(struct slist **list, bdaddr_t *bdaddr, name_status return -1; dev->bdaddr = malloc(sizeof(*dev->bdaddr)); - memcpy(dev->bdaddr, bdaddr, sizeof(*dev->bdaddr)); + bacpy(dev->bdaddr, bdaddr); dev->name_status = name_status; *list = slist_append(*list, dev); - return 0; } @@ -246,7 +245,7 @@ int get_default_dev_id(void) return default_dev; } -static int dev_append_signal_args(DBusMessage *signal, int first, va_list var_args) +static inline int dev_append_signal_args(DBusMessage *signal, int first, va_list var_args) { void *value; DBusMessageIter iter; @@ -629,12 +628,17 @@ failed: bt_free(local_addr); } -static inline int remote_name_resolve(struct hci_dbus_data *dbus_data) +int remote_name_resolve(struct hci_dbus_data *dbus_data) { + struct hci_request rq; + evt_cmd_status rp; + remote_name_req_cp cp; + bdaddr_t tmp; struct discovered_dev_info *dev; + DBusMessage *message = NULL; struct slist *l = NULL; - remote_name_req_cp cp; - int dd; + char *peer_addr = NULL; + int dd, req_sent, ret_val = 0; name_status_t name_status = NAME_PENDING; /*get the next remote address */ @@ -654,16 +658,70 @@ static inline int remote_name_resolve(struct hci_dbus_data *dbus_data) if (dd < 0) return -1; - memset(&cp, 0, sizeof(cp)); - bacpy(&cp.bdaddr, dev->bdaddr); - cp.pscan_rep_mode = 0x02; + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_REMOTE_NAME_REQ; + rq.cparam = &cp; + rq.clen = REMOTE_NAME_REQ_CP_SIZE; + rq.rparam = &rp; + rq.rlen = EVT_CMD_STATUS_SIZE; + rq.event = EVT_CMD_STATUS; + + /* send at least one request or return failed if the list is empty */ + do { + req_sent = 1; + + memset(&cp, 0, sizeof(cp)); + bacpy(&cp.bdaddr, dev->bdaddr); + cp.pscan_rep_mode = 0x02; + + baswap(&tmp, dev->bdaddr); peer_addr = batostr(&tmp); + + if (hci_send_req(dd, &rq, 100) < 0) { + error("Unable to send the HCI remote name request: %s (%d)", + strerror(errno), errno); + message = dev_signal_factory(dbus_data->dev_id, "RemoteNameFailed", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); + req_sent = 0; + } + + if (rp.status) { + error("Remote name request failed with status 0x%02x", rp.status); + message = dev_signal_factory(dbus_data->dev_id, "RemoteNameFailed", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); + req_sent = 0; + } + + send_reply_and_unref(connection, message); + + free(peer_addr); + + /* if failed, request the next element */ + if (!req_sent) { + /* remove the element from the list */ + dbus_data->discovered_devices = slist_remove(dbus_data->discovered_devices, dev); + free(dev->bdaddr); + free(dev); + + /* get the next element */ + l = slist_find(dbus_data->discovered_devices, &name_status, remote_name_find_by_name_status); + + if (!l) { + /* no more devices: exit */ + ret_val = -1; + goto failed; + } - hci_send_cmd(dd, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ, - REMOTE_NAME_REQ_CP_SIZE, &cp); + dev = l->data; + } + } while (!req_sent); +failed: hci_close_dev(dd); - return 0; + return ret_val; } void hcid_dbus_inquiry_complete(bdaddr_t *local) @@ -686,17 +744,13 @@ void hcid_dbus_inquiry_complete(bdaddr_t *local) snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, id); if (dbus_connection_get_object_path_data(connection, path, (void *) &pdata)) { - if (pdata->discover_state == DISCOVER_RUNNING_WITH_NAMES) { - /* start name resolving */ + if (!remote_name_resolve(pdata)) { pdata->discover_state = RESOLVING_NAMES; - - if (!remote_name_resolve(pdata)) - goto failed; /* skip, sending the first name to resolve */ - - pdata->discover_state = DISCOVER_OFF; /* no names to resolve */ - + goto failed; /* skip - there is name to resolve */ } + pdata->discover_state = DISCOVER_OFF; + /* free discovered devices list */ slist_foreach(pdata->discovered_devices, discovered_device_free, NULL); slist_free(pdata->discovered_devices); @@ -822,26 +876,17 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i goto failed; /* don't sent the name again */ } - signal_name = dbus_message_new_signal(path, ADAPTER_INTERFACE, - "RemoteNameUpdated"); - if (signal_name == NULL) { - error("Can't allocate D-Bus message"); - goto failed; - } - snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, local_addr); - name = textfile_get(filename, peer_addr); if (name) { - dbus_message_append_args(signal_name, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID); - - if (dbus_connection_send(connection, signal_name, NULL) == FALSE) - error("Can't send D-Bus remote name updated signal"); + signal_name = dev_signal_factory(pdata->dev_id, "RemoteNameUpdate", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + send_reply_and_unref(connection, signal_name); + free(name); name_status = NAME_SENT; } @@ -854,15 +899,8 @@ failed: if (signal_device) dbus_message_unref(signal_device); - if (signal_name) - dbus_message_unref(signal_name); - bt_free(local_addr); bt_free(peer_addr); - - if (name) - bt_free(name); - } void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name) @@ -891,67 +929,41 @@ void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char /* if the requested name failed, don't send signal and request the next name */ if (status) - goto request_next; - - - /* send the remote name update signal */ - message = dbus_message_new_signal(path, ADAPTER_INTERFACE, - "RemoteNameUpdated"); - if (message == NULL) { - error("Can't allocate D-Bus message"); - goto failed; - } - - dbus_message_append_args(message, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID); - - if (dbus_connection_send(connection, message, NULL) == FALSE) { - error("Can't send D-Bus remote name updated signal"); - goto failed; - } - - dbus_connection_flush(connection); - -request_next: - if (!pdata->requestor_name) - goto failed; /* requested by an external app */ - + message = dev_signal_factory(pdata->dev_id, "RemoteNameFailed", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); + else + message = dev_signal_factory(pdata->dev_id, "RemoteNameUpdated", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + send_reply_and_unref(connection, message); + + /* check if there is more devices to request names */ if (!remote_name_resolve(pdata)) - goto failed; /* skip: there is more remote name to resolve */ + goto failed; /* skip if a new request has been sent */ /* free discovered devices list */ slist_foreach(pdata->discovered_devices, discovered_device_free, NULL); slist_free(pdata->discovered_devices); pdata->discovered_devices = NULL; - if (message) - dbus_message_unref(message); - - message = dbus_message_new_signal(path, ADAPTER_INTERFACE, - "DiscoveryCompleted"); - if (message == NULL) { - error("Can't allocate D-Bus message"); - goto failed; - } - - if (dbus_connection_send(connection, message, NULL) == FALSE) { - error("Can't send D-Bus discovery completed signal"); - goto failed; - } + if (pdata->discover_state != DISCOVER_OFF) { + message = dbus_message_new_signal(path, ADAPTER_INTERFACE, + "DiscoveryCompleted"); - dbus_connection_flush(connection); + send_reply_and_unref(connection, message); - free(pdata->requestor_name); - pdata->requestor_name = NULL; + if (pdata->requestor_name) { + free(pdata->requestor_name); + pdata->requestor_name = NULL; + } - pdata->discover_state = DISCOVER_OFF; + pdata->discover_state = DISCOVER_OFF; + } failed: - if (message) - dbus_message_unref(message); - bt_free(local_addr); bt_free(peer_addr); } diff --git a/hcid/dbus.h b/hcid/dbus.h index 98d89658..8eba6a95 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -82,7 +82,7 @@ typedef enum { typedef enum { NAME_PENDING, NAME_SENT -}name_status_t; +} name_status_t; struct discovered_dev_info { bdaddr_t *bdaddr; @@ -142,6 +142,7 @@ DBusHandlerResult error_out_of_memory(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_no_such_adapter(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_unknown_address(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_not_available(DBusConnection *conn, DBusMessage *msg); +DBusHandlerResult error_request_deferred(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_not_connected(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_unsupported_major_class(DBusConnection *conn, DBusMessage *msg); DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn, DBusMessage *msg, int err); @@ -185,6 +186,10 @@ static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusM void discovered_device_free(void *data, void *user_data); int bonding_requests_find(const void *data, const void *user_data); +int remote_name_find_by_bdaddr(const void *data, const void *user_data); +int remote_name_append(struct slist **list, bdaddr_t *bdaddr, name_status_t name_status); +int remote_name_resolve(struct hci_dbus_data *dbus_data); + /* * Scanning modes, used by DEV_SET_MODE * off: remote devices are not allowed to find or connect to this device |