From 9575f385006817d43cdd5bacadd0b37f2e02bc9a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 18 Apr 2006 21:01:11 +0000 Subject: Added HCI cmds queue to retrieve remote infos --- hcid/dbus-todo.txt | 25 ++------- hcid/dbus.c | 83 +++++++++++++++--------------- hcid/hcid.h | 20 ++++++++ hcid/security.c | 146 ++++++++++++++++++++++++++++++++++------------------- 4 files changed, 159 insertions(+), 115 deletions(-) (limited to 'hcid') diff --git a/hcid/dbus-todo.txt b/hcid/dbus-todo.txt index b906a55d..3fecc3eb 100644 --- a/hcid/dbus-todo.txt +++ b/hcid/dbus-todo.txt @@ -7,25 +7,6 @@ Date: 2006/04/11 Description: Review these errors. The usage of "Does not exists" and "Not available" are confusing. -* pending HCI requests -Date: 2006/04/11 -Description: The D-Bus authentication method creates automatically -an ACL connection when required and disconnects when the procedure -finishes. When the HCI connection complete arrives, remote name/ -version/features are queued. Considering that the authentication -is not queued, when this procedure finishes and the disconnect is -requested, the remaining elements in the queue can't be executed. - -* active connections verification -Date: 2006/04/11 -Description: get_bdaddr function is called frequently in the -security.c file. In a real usage scenario, the disconnect -command can be sent by another process or BlueZ D-Bus method. -On this case if there is pending request confirmation(eg: remote -version complete or remote features complete), when the -confirmation arrives the bdaddr can't be retrieved because -there isn't active connection anymore. Suggestion: keep a active -connection list instead of call the get_bdaddr frequently. Keep -in mind that D-Bus data already has a list to store active -connections. - +* code standard for sending msg function +Date: 2006/04/13 +Description: use send_reply_and_unref when possible. diff --git a/hcid/dbus.c b/hcid/dbus.c index 3354da5f..cd864215 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -578,8 +578,7 @@ void hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status) { struct hci_dbus_data *pdata; - DBusMessage *msg_reply = NULL; - DBusMessage *msg_signal = NULL; + DBusMessage *message = NULL; char *local_addr, *peer_addr; const char *name; bdaddr_t tmp; @@ -615,49 +614,38 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u */ name = status ? "BondingFailed" : "BondingCreated"; /* authentication signal */ - msg_signal = dbus_message_new_signal(path, ADAPTER_INTERFACE, name); - - if (msg_signal == NULL) { - error("Can't allocate D-Bus message"); - goto failed; - } - - dbus_message_append_args(msg_signal, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID); - - if (dbus_connection_send(connection, msg_signal, NULL) == FALSE) { - error("Can't send D-Bus bonding created signal"); - goto failed; - } + message = dev_signal_factory(pdata->dev_id, name, + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); - dbus_connection_flush(connection); + send_reply_and_unref(connection, message); if (!pdata->bonding) goto failed; /* skip: no bonding req pending */ - msg_reply = dbus_msg_new_authentication_return(pdata->bonding->rq, status); - if (dbus_connection_send(connection, msg_reply, NULL) == FALSE) { - error("Can't send D-Bus reply for create bonding request"); - goto failed; - } - - /* FIXME: disconnect if required */ if (pdata->bonding->disconnect) { struct slist *l; l = slist_find(pdata->active_conn, peer, active_conn_find_by_bdaddr); if (l) { struct active_conn_info *con = l->data; - int dd = hci_open_dev(pdata->dev_id); - /* Send the HCI disconnect command */ - if (hci_disconnect(dd, con->handle, HCI_OE_USER_ENDED_CONNECTION, 100) < 0) { - error("Disconnect failed"); - } - hci_close_dev(dd); + struct hci_req_data *data; + disconnect_cp cp; + memset(&cp, 0, sizeof(cp)); + + cp.handle = con->handle; + cp.reason = HCI_OE_USER_ENDED_CONNECTION; + + data = hci_req_data_new(pdata->dev_id, peer, OGF_LINK_CTL, + OCF_DISCONNECT, EVT_DISCONN_COMPLETE, + &cp, DISCONNECT_CP_SIZE); + hci_req_queue_append(data); } } + message = dbus_msg_new_authentication_return(pdata->bonding->rq, status); + send_reply_and_unref(connection, message); + bonding_request_free(pdata->bonding); pdata->bonding = NULL; @@ -665,12 +653,6 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u pdata->requestor_name = NULL; failed: - if (msg_signal) - dbus_message_unref(msg_signal); - - if (msg_reply) - dbus_message_unref(msg_reply); - bt_free(local_addr); bt_free(peer_addr); } @@ -1234,13 +1216,32 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle goto failed; dev = l->data; - /* add in the active connetions list */ + baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp); - /* Sent the remote device disconnected signal */ - message = dbus_message_new_signal(path, ADAPTER_INTERFACE, "RemoteDeviceDisconnected"); + /* clean pending HCI cmds */ + hci_req_queue_remove(pdata->dev_id, &dev->bdaddr); - dbus_message_append_args(message, + /* Check if there is a pending Bonding */ + if (pdata->bonding) { + message = dev_signal_factory(pdata->dev_id, "BondingFailed", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); + + send_reply_and_unref(connection, message); + + message = dbus_msg_new_authentication_return(pdata->bonding->rq, status); + send_reply_and_unref(connection, message); + + bonding_request_free(pdata->bonding); + pdata->bonding = NULL; + + free(pdata->requestor_name); + pdata->requestor_name = NULL; + } + + /* Sent the remote device disconnected signal */ + message = dev_signal_factory(pdata->dev_id, "RemoteDeviceDisconnected", DBUS_TYPE_STRING, &peer_addr, DBUS_TYPE_INVALID); diff --git a/hcid/hcid.h b/hcid/hcid.h index 2f5d74c1..066f9358 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -84,6 +84,26 @@ struct hcid_opts { }; extern struct hcid_opts hcid; +typedef enum { + REQ_PENDING, + REQ_SENT +} req_status_t; + +struct hci_req_data { + int dev_id; + int event; + req_status_t status; + bdaddr_t dba; + uint16_t ogf; + uint16_t ocf; + void *cparam; + int clen; +}; + +struct hci_req_data *hci_req_data_new(int dev_id, const bdaddr_t *dba, uint16_t ogf, uint16_t ocf, int event, const void *cparam, int clen); +void hci_req_queue_append(struct hci_req_data *data); +void hci_req_queue_remove(int dev_id, bdaddr_t *dba); + #define HCID_SEC_NONE 0 #define HCID_SEC_AUTO 1 #define HCID_SEC_USER 2 diff --git a/hcid/security.c b/hcid/security.c index 72fcc9e6..6f0aa10f 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -62,17 +62,9 @@ static struct g_io_info io_data[HCI_MAX_DEV]; static int pairing = HCID_PAIRING_MULTI; -struct hci_req_data { - int dev; - uint16_t ogf; - uint16_t ocf; - void *cparam; - int clen; -}; - static struct slist *hci_req_queue = NULL; -static struct hci_req_data *hci_req_data_new(int dev, uint16_t ogf, uint16_t ocf, const void *cparam, int clen) +struct hci_req_data *hci_req_data_new(int dev_id, const bdaddr_t *dba, uint16_t ogf, uint16_t ocf, int event, const void *cparam, int clen) { struct hci_req_data *data; @@ -87,48 +79,103 @@ static struct hci_req_data *hci_req_data_new(int dev, uint16_t ogf, uint16_t ocf free(data); return NULL; } - + memcpy(data->cparam, cparam, clen); - data->dev = dev; + bacpy(&data->dba, dba); + + data->dev_id = dev_id; + data->status = REQ_PENDING; data->ogf = ogf; data->ocf = ocf; + data->event = event; data->clen = clen; return data; } -static int hci_req_find_by_dev(const void *data, const void *user_data) +void hci_req_queue_append(struct hci_req_data *data) +{ + hci_req_queue = slist_append(hci_req_queue, data); +} + +void hci_req_queue_remove(int dev_id, bdaddr_t *dba) +{ + struct slist *cur, *next; + struct hci_req_data *req; + + for (cur = hci_req_queue; cur != NULL; cur = next) { + req = cur->data; + next = cur->next; + if ((req->dev_id != dev_id) || (bacmp(&req->dba, dba))) + continue; + + hci_req_queue = slist_remove(hci_req_queue, req); + free(req->cparam); + free(req); + } +} + +static int hci_req_find_by_devid(const void *data, const void *user_data) { const struct hci_req_data *req = data; - const int *dev = user_data; + const int *dev_id = user_data; - return (*dev - req->dev); + return (*dev_id - req->dev_id); } -static int check_pending_hci_req(int dev) +static void check_pending_hci_req(int dev_id, int event) { struct hci_req_data *data; struct slist *l; + int dd, ret_val; if (!hci_req_queue) - return -1; + return; - l = slist_find(hci_req_queue, &dev, hci_req_find_by_dev); + /* find the first element(pending)*/ + l = slist_find(hci_req_queue, &dev_id, hci_req_find_by_devid); if (!l) - return -1; + return; data = l->data; - hci_send_cmd(dev, data->ogf, data->ocf, data->clen, data->cparam); + /* skip if there is pending confirmation */ + if (data->status == REQ_SENT) { + if (data->event != event) + return; + + /* remove the confirmed cmd */ + hci_req_queue = slist_remove(hci_req_queue, data); + free(data->cparam); + free(data); + } + + /* send the next pending cmd */ + dd = hci_open_dev(dev_id); + do { + l = slist_find(hci_req_queue, &dev_id, hci_req_find_by_devid); + + if (!l) + goto failed; + + data = l->data; + data->status = REQ_SENT; + + ret_val = hci_send_cmd(dd, data->ogf, data->ocf, data->clen, data->cparam); + if (ret_val < 0) { + hci_req_queue = slist_remove(hci_req_queue, data); + free(data->cparam); + free(data); + } - hci_req_queue = slist_remove(hci_req_queue, data); + } while(ret_val < 0); - free(data->cparam); - free(data); +failed: + hci_close_dev(dd); - return 0; + return; } static inline int get_bdaddr(int dev, bdaddr_t *sba, uint16_t handle, bdaddr_t *dba) @@ -412,9 +459,6 @@ static inline void remote_name_information(int dev, bdaddr_t *sba, void *ptr) } hcid_dbus_remote_name(sba, &dba, evt->status, name); - - /* pending remote version or remote features */ - check_pending_hci_req(dev); } static inline void remote_version_information(int dev, bdaddr_t *sba, void *ptr) @@ -430,9 +474,6 @@ static inline void remote_version_information(int dev, bdaddr_t *sba, void *ptr) write_version_info(sba, &dba, btohs(evt->manufacturer), evt->lmp_ver, btohs(evt->lmp_subver)); - - /* pending remote features */ - check_pending_hci_req(dev); } static inline void inquiry_complete(int dev, bdaddr_t *sba, void *ptr) @@ -531,23 +572,13 @@ static inline void remote_features_information(int dev, bdaddr_t *sba, void *ptr write_features_info(sba, &dba, evt->features); } -static inline void name_resolve(int dev, bdaddr_t *bdaddr) -{ - remote_name_req_cp cp; - - memset(&cp, 0, sizeof(cp)); - bacpy(&cp.bdaddr, bdaddr); - cp.pscan_rep_mode = 0x02; - - hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ, - REMOTE_NAME_REQ_CP_SIZE, &cp); -} - -static inline void conn_complete(int dev, bdaddr_t *sba, void *ptr) +static inline void conn_complete(int dev, int dev_id, bdaddr_t *sba, void *ptr) { evt_conn_complete *evt = ptr; char filename[PATH_MAX]; + remote_name_req_cp cp_name; bdaddr_t tmp; + struct hci_req_data *data; char *str, *local_addr, *peer_addr; hcid_dbus_conn_complete(sba, evt->status, evt->handle, &evt->bdaddr); @@ -557,7 +588,16 @@ static inline void conn_complete(int dev, bdaddr_t *sba, void *ptr) update_lastused(sba, &evt->bdaddr); - name_resolve(dev, &evt->bdaddr); + /* Request remote name */ + memset(&cp_name, 0, sizeof(cp_name)); + bacpy(&cp_name.bdaddr, &evt->bdaddr); + cp_name.pscan_rep_mode = 0x02; + + data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL, + OCF_REMOTE_NAME_REQ, EVT_REMOTE_NAME_REQ_COMPLETE, + &cp_name, REMOTE_NAME_REQ_CP_SIZE); + + hci_req_queue_append(data); /* check if the remote version needs be requested */ baswap(&tmp, sba); local_addr = batostr(&tmp); @@ -568,15 +608,15 @@ static inline void conn_complete(int dev, bdaddr_t *sba, void *ptr) str = textfile_get(filename, peer_addr); if (!str) { - struct hci_req_data *data; read_remote_version_cp cp; cp.handle = evt->handle; - data = hci_req_data_new(dev, OGF_LINK_CTL, OCF_READ_REMOTE_VERSION, - &cp, READ_REMOTE_VERSION_CP_SIZE); + data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL, + OCF_READ_REMOTE_VERSION, EVT_READ_REMOTE_VERSION_COMPLETE, + &cp, READ_REMOTE_VERSION_CP_SIZE); - hci_req_queue = slist_append(hci_req_queue, data); + hci_req_queue_append(data); } else { /* skip: remote version found */ free(str); @@ -588,15 +628,15 @@ static inline void conn_complete(int dev, bdaddr_t *sba, void *ptr) str = textfile_get(filename, peer_addr); if (!str) { - struct hci_req_data *data; read_remote_features_cp cp; cp.handle = evt->handle; - data = hci_req_data_new(dev, OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES, - &cp, READ_REMOTE_FEATURES_CP_SIZE); + data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL, + OCF_READ_REMOTE_FEATURES, EVT_READ_REMOTE_FEATURES_COMPLETE, + &cp, READ_REMOTE_FEATURES_CP_SIZE); - hci_req_queue = slist_append(hci_req_queue, data); + hci_req_queue_append(data); } else { /* skip: remote features found */ free(str); @@ -702,7 +742,7 @@ static gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer break; case EVT_CONN_COMPLETE: - conn_complete(dev, &di->bdaddr, ptr); + conn_complete(dev, di->dev_id, &di->bdaddr, ptr); break; case EVT_DISCONN_COMPLETE: @@ -713,6 +753,8 @@ static gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer auth_complete(dev, &di->bdaddr, ptr); break; } + /* check for pending cmd request */ + check_pending_hci_req(di->dev_id, eh->evt); if (hci_test_bit(HCI_SECMGR, &di->flags)) return TRUE; -- cgit