diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2006-09-15 14:44:22 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2006-09-15 14:44:22 +0000 |
commit | 0ab6b68b07ee96bf4bd4cf0fe7d4b68582b5caf5 (patch) | |
tree | 77d374eb81c90b66d9994c9cd058812d49209a16 /hcid | |
parent | 87123c20dcf8baf2b952709ff2aacb07a21ca1b3 (diff) |
Use L2CAP raw sockets for HCI connection creation
Diffstat (limited to 'hcid')
-rw-r--r-- | hcid/dbus-adapter.c | 355 | ||||
-rw-r--r-- | hcid/dbus.c | 229 | ||||
-rw-r--r-- | hcid/dbus.h | 15 | ||||
-rw-r--r-- | hcid/hcid.h | 4 | ||||
-rw-r--r-- | hcid/security.c | 2 |
5 files changed, 280 insertions, 325 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index bfe7ae9a..907b81db 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -27,14 +27,16 @@ #include <stdio.h> #include <errno.h> -#include <unistd.h> #include <ctype.h> +#include <fcntl.h> +#include <unistd.h> #include <sys/param.h> #include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> #include <bluetooth/hci_lib.h> +#include <bluetooth/l2cap.h> #include <dbus/dbus.h> @@ -201,7 +203,8 @@ static int check_address(const char *addr) return 0; } -static struct bonding_request_info *bonding_request_new(bdaddr_t *peer) +static struct bonding_request_info *bonding_request_new(bdaddr_t *peer, DBusConnection *conn, + DBusMessage *msg) { struct bonding_request_info *bonding; @@ -214,6 +217,9 @@ static struct bonding_request_info *bonding_request_new(bdaddr_t *peer) bacpy(&bonding->bdaddr, peer); + bonding->conn = dbus_connection_ref(conn); + bonding->rq = dbus_message_ref(msg); + return bonding; } @@ -1690,19 +1696,164 @@ static DBusHandlerResult handle_dev_disconnect_remote_device_req(DBusConnection } -static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBusMessage *msg, void *data) +static int l2raw_connect(const char *local, const bdaddr_t *remote) +{ + struct sockaddr_l2 addr; + long arg; + int sk; + + sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP); + if (sk < 0) { + error("Can't create socket: %s (%d)", strerror(errno), errno); + return sk; + } + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + str2ba(local, &addr.l2_bdaddr); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + error("Can't bind socket: %s (%d)", strerror(errno), errno); + goto failed; + } + + arg = fcntl(sk, F_GETFL); + if (arg < 0) { + error("Can't get file flags: %s (%d)", strerror(errno), errno); + goto failed; + } + + arg |= O_NONBLOCK; + if (fcntl(sk, F_SETFL, arg) < 0) { + error("Can't set file flags: %s (%d)", strerror(errno), errno); + goto failed; + } + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, remote); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (errno == EAGAIN || errno == EINPROGRESS) + return sk; + error("Can't connect socket: %s (%d)", strerror(errno), errno); + goto failed; + } + + return sk; + +failed: + close(sk); + return -1; +} + +static gboolean create_bonding_conn_complete(GIOChannel *io, GIOCondition cond, + struct hci_dbus_data *pdata) { - char filename[PATH_MAX + 1]; struct hci_request rq; - create_conn_cp cc_cp; - auth_requested_cp ar_cp; + auth_requested_cp cp; evt_cmd_status rp; + struct l2cap_conninfo cinfo; + socklen_t len; + int sk, dd, ret; + + if (!pdata->bonding) { + /* If we come here it implies a bug somewhere */ + debug("create_bonding_conn_complete: no pending bonding!"); + g_io_channel_close(io); + g_io_channel_unref(io); + return FALSE; + } + + if (cond & G_IO_NVAL) { + error_authentication_canceled(pdata->bonding->conn, pdata->bonding->rq); + goto cleanup; + } + + sk = g_io_channel_unix_get_fd(io); + + len = sizeof(ret); + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + error("Can't get socket error: %s (%d)", strerror(errno), errno); + error_failed(pdata->bonding->conn, pdata->bonding->rq, errno); + goto failed; + } + + if (ret != 0) { + error_connection_attempt_failed(pdata->bonding->conn, pdata->bonding->rq, ret); + goto failed; + } + + len = sizeof(cinfo); + if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &cinfo, &len) < 0) { + error("Can't get connection info: %s (%d)", strerror(errno), errno); + error_failed(pdata->bonding->conn, pdata->bonding->rq, errno); + goto failed; + } + + dd = hci_open_dev(pdata->dev_id); + if (dd < 0) { + error_no_such_adapter(pdata->bonding->conn, pdata->bonding->rq); + goto failed; + } + + memset(&rp, 0, sizeof(rp)); + + memset(&cp, 0, sizeof(cp)); + cp.handle = cinfo.hci_handle; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_AUTH_REQUESTED; + rq.event = EVT_CMD_STATUS; + rq.cparam = &cp; + rq.clen = AUTH_REQUESTED_CP_SIZE; + rq.rparam = &rp; + rq.rlen = EVT_CMD_STATUS_SIZE; + + if (hci_send_req(dd, &rq, 100) < 0) { + error("Unable to send HCI request: %s (%d)", + strerror(errno), errno); + error_failed(pdata->bonding->conn, pdata->bonding->rq, errno); + hci_close_dev(dd); + goto failed; + } + + if (rp.status) { + error("HCI_Authentication_Requested failed with status 0x%02x", + rp.status); + error_failed(pdata->bonding->conn, pdata->bonding->rq, bt_error(rp.status)); + hci_close_dev(dd); + goto failed; + } + + hci_close_dev(dd); + + pdata->bonding->io_id = 0; + + return FALSE; + +failed: + g_io_channel_close(io); + +cleanup: + name_listener_remove(pdata->bonding->conn, dbus_message_get_sender(pdata->bonding->rq), + (name_cb_t) create_bond_req_exit, pdata); + + bonding_request_free(pdata->bonding); + pdata->bonding = NULL; + + return FALSE; +} + +static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBusMessage *msg, void *data) +{ + char filename[PATH_MAX + 1]; DBusError err; char *str, *peer_addr = NULL; struct hci_dbus_data *dbus_data = data; - struct slist *l; bdaddr_t peer_bdaddr; - int dd, disconnect; + int sk; if (!dbus_data->up) return error_not_ready(conn, msg); @@ -1723,14 +1874,16 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu str2ba(peer_addr, &peer_bdaddr); - /* check if there is a pending bonding request */ - if (dbus_data->bonding) - return error_bonding_in_progress(conn, msg); - /* check if there is a pending discover: requested by D-Bus/non clients */ if (dbus_data->discover_state != STATE_IDLE || dbus_data->discovery_requestor) return error_discover_in_progress(conn, msg); + if (dbus_data->bonding) + return error_bonding_in_progress(conn, msg); + + if (slist_find(dbus_data->pin_reqs, &peer_bdaddr, pin_req_cmp)) + return error_bonding_in_progress(conn, msg); + /* check if a link key already exists */ create_name(filename, PATH_MAX, STORAGEDIR, dbus_data->address, "linkkeys"); @@ -1740,83 +1893,36 @@ static DBusHandlerResult handle_dev_create_bonding_req(DBusConnection *conn, DBu return error_bonding_already_exists(conn, msg); } - dd = hci_open_dev(dbus_data->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, msg); + sk = l2raw_connect(dbus_data->address, &peer_bdaddr); + if (sk < 0) + return error_connection_attempt_failed(conn, msg, 0); - memset(&rq, 0, sizeof(rq)); - memset(&rp, 0, sizeof(rp)); - - rq.ogf = OGF_LINK_CTL; - rq.event = EVT_CMD_STATUS; - rq.rparam = &rp; - rq.rlen = EVT_CMD_STATUS_SIZE; - - /* check if there is an active connection */ - l = slist_find(dbus_data->active_conn, &peer_bdaddr, active_conn_find_by_bdaddr); - - if (!l) { - memset(&cc_cp, 0, sizeof(cc_cp)); - /* create a new connection */ - bacpy(&cc_cp.bdaddr, &peer_bdaddr); - cc_cp.pkt_type = htobs(HCI_DM1); - cc_cp.pscan_rep_mode = 0x02; - cc_cp.clock_offset = htobs(0x0000); - cc_cp.role_switch = 0x01; - - rq.ocf = OCF_CREATE_CONN; - rq.cparam = &cc_cp; - rq.clen = CREATE_CONN_CP_SIZE; - disconnect = 1; - } else { - struct active_conn_info *dev = l->data; - - memset(&ar_cp, 0, sizeof(ar_cp)); - - ar_cp.handle = dev->handle; - rq.ocf = OCF_AUTH_REQUESTED; - rq.cparam = &ar_cp; - rq.clen = AUTH_REQUESTED_CP_SIZE; - disconnect = 0; - } - - if (hci_send_req(dd, &rq, 100) < 0) { - int err = errno; - error("Unable to send the HCI request: %s (%d)", - strerror(errno), errno); - hci_close_dev(dd); - return error_failed(conn, msg, err); - } - - if (rp.status) { - error("%s failed with status 0x%02x", rq.ocf == OCF_CREATE_CONN ? - "HCI_Create_Connection" : "HCI_Authentication_Requested", - rp.status); - hci_close_dev(dd); - return error_failed(conn, msg, bt_error(rp.status)); + dbus_data->bonding = bonding_request_new(&peer_bdaddr, conn, msg); + if (!dbus_data->bonding) { + close(sk); + return DBUS_HANDLER_RESULT_NEED_MEMORY; } - dbus_data->bonding = bonding_request_new(&peer_bdaddr); - dbus_data->bonding->disconnect = disconnect; - dbus_data->bonding->rq = dbus_message_ref(msg); + dbus_data->bonding->io = g_io_channel_unix_new(sk); + dbus_data->bonding->io_id = g_io_add_watch(dbus_data->bonding->io, + G_IO_OUT | G_IO_NVAL, + (GIOFunc) create_bonding_conn_complete, + dbus_data); name_listener_add(conn, dbus_message_get_sender(msg), (name_cb_t) create_bond_req_exit, dbus_data); - hci_close_dev(dd); - return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult handle_dev_cancel_bonding_req(DBusConnection *conn, DBusMessage *msg, void *data) { struct hci_dbus_data *dbus_data = data; - struct slist *la; DBusMessage *reply; DBusError err; bdaddr_t peer_bdaddr; const char *peer_addr; - int dd = -1; + struct slist *l; if (!dbus_data->up) return error_not_ready(conn, msg); @@ -1837,103 +1943,46 @@ static DBusHandlerResult handle_dev_cancel_bonding_req(DBusConnection *conn, DBu str2ba(peer_addr, &peer_bdaddr); - /* check if there is a pending bonding request */ - if (!dbus_data->bonding || bacmp(&dbus_data->bonding->bdaddr, &peer_bdaddr)) { - error("No bonding request pending."); + if (!dbus_data->bonding || bacmp(&dbus_data->bonding->bdaddr, &peer_bdaddr)) return error_bonding_not_in_progress(conn, msg); - } if (strcmp(dbus_message_get_sender(dbus_data->bonding->rq), dbus_message_get_sender(msg))) return error_not_authorized(conn, msg); - dd = hci_open_dev(dbus_data->dev_id); - if (dd < 0) - return error_no_such_adapter(conn, msg); - dbus_data->bonding->cancel = 1; - la = slist_find(dbus_data->active_conn, &peer_bdaddr, active_conn_find_by_bdaddr); - - if (!la) { - /* connection request is pending */ - struct hci_request rq; - create_conn_cancel_cp cp; - evt_cmd_status rp; - - memset(&rq, 0, sizeof(rq)); - memset(&cp, 0, sizeof(cp)); - memset(&rp, 0, sizeof(rp)); + g_io_channel_close(dbus_data->bonding->io); - bacpy(&cp.bdaddr, &dbus_data->bonding->bdaddr); + l = slist_find(dbus_data->pin_reqs, &peer_bdaddr, pin_req_cmp); + if (l) { + struct pending_pin_info *pin_req = l->data; + + if (pin_req->replied) { + /* + * If disconnect can't be applied and the PIN Code Request + * was already replied it doesn't make sense cancel the + * remote passkey: return not authorized. + */ + return error_not_authorized(conn, msg); + } else { + int dd = hci_open_dev(dbus_data->dev_id); + if (dd < 0) { + error("Can't open hci%d: %s (%d)", + dbus_data->dev_id, strerror(errno), errno); + return DBUS_HANDLER_RESULT_HANDLED; + } - rq.ogf = OGF_LINK_CTL; - rq.ocf = OCF_CREATE_CONN_CANCEL; - rq.rparam = &rp; - rq.rlen = EVT_CMD_STATUS_SIZE; - rq.event = EVT_CMD_STATUS; - rq.cparam = &cp; - rq.clen = CREATE_CONN_CANCEL_CP_SIZE; + hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &peer_bdaddr); - if (hci_send_req(dd, &rq, 100) < 0) { - int err = errno; - error("Cancel bonding - unable to send the HCI request: %s (%d)", - strerror(errno), errno); hci_close_dev(dd); - return error_failed(conn, msg, err); - } - - if (rp.status) { - error("Cancel bonding - Failed with status 0x%02x", rp.status); - hci_close_dev(dd); - return error_failed(conn, msg, bt_error(rp.status)); - } + } - /* - * if the HCI doesn't support cancel create connection cmd let - * the create connection complete event arrives with page timeout. - * Bonding in progress will be returned to requestors. - */ - - } else { - struct slist *lb; - struct active_conn_info *cinfo = la->data; - - /* - * It is already connected, search in the pending passkey requests to - * figure out the current stage(waiting host passkey/remote passkey) - */ - lb = slist_find(dbus_data->pending_bondings, &peer_bdaddr, pending_bonding_cmp); - if (lb) { - struct pending_bonding_info *pb = lb->data; - /* 0: waiting host passkey 1: waiting remote passkey */ - if (pb->step) { - if (dbus_data->bonding->disconnect) { - - /* disconnect and let disconnect handler reply create bonding */ - if (hci_disconnect(dd, htobs(cinfo->handle), HCI_AUTHENTICATION_FAILURE, 1000) < 0) - error("Disconnect failed"); - } else { - /* - * If disconnect can't be applied and the PIN Code Request - * was already replied it doesn't make sense cancel the - * remote passkey: return not authorized. - */ - - error_not_authorized(conn, msg); - goto failed; - } - } else { - - /* for unlock PIN Code Request */ - hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &peer_bdaddr); - } - } + dbus_data->pin_reqs = slist_remove(dbus_data->pin_reqs, pin_req); + free(pin_req); } reply = dbus_message_new_method_return(msg); send_reply_and_unref(conn, reply); -failed: - hci_close_dev(dd); return DBUS_HANDLER_RESULT_HANDLED; } diff --git a/hcid/dbus.c b/hcid/dbus.c index 0cdb5ccf..6712b3a5 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -76,13 +76,21 @@ int hcid_dbus_use_experimental(void) return experimental; } -void bonding_request_free(struct bonding_request_info *dev ) +void bonding_request_free(struct bonding_request_info *bonding) { - if (dev) { - if (dev->rq) - dbus_message_unref(dev->rq); - free(dev); - } + if (!bonding) + return; + + if (bonding->rq) + dbus_message_unref(bonding->rq); + + if (bonding->conn) + dbus_connection_unref(bonding->conn); + + if (bonding->io) + g_io_channel_unref(bonding->io); + + free(bonding); } static int disc_device_find(const struct discovered_dev_info *d1, const struct discovered_dev_info *d2) @@ -377,6 +385,9 @@ static void reply_pending_requests(const char *path, struct hci_dbus_data *pdata error_authentication_canceled(connection, pdata->bonding->rq); name_listener_remove(connection, dbus_message_get_sender(pdata->bonding->rq), (name_cb_t) create_bond_req_exit, pdata); + if (pdata->bonding->io_id) + g_io_remove_watch(pdata->bonding->io_id); + g_io_channel_close(pdata->bonding->io); bonding_request_free(pdata->bonding); pdata->bonding = NULL; } @@ -425,10 +436,10 @@ static int unregister_dbus_path(const char *path) pdata->disc_devices = NULL; } - if (pdata->pending_bondings) { - slist_foreach(pdata->pending_bondings, (slist_func_t) free, NULL); - slist_free(pdata->pending_bondings); - pdata->pending_bondings = NULL; + if (pdata->pin_reqs) { + slist_foreach(pdata->pin_reqs, (slist_func_t) free, NULL); + slist_free(pdata->pin_reqs); + pdata->pin_reqs = NULL; } if (pdata->active_conn) { @@ -669,10 +680,10 @@ int hcid_dbus_stop_device(uint16_t id) pdata->disc_devices = NULL; } - if (pdata->pending_bondings) { - slist_foreach(pdata->pending_bondings, (slist_func_t) free, NULL); - slist_free(pdata->pending_bondings); - pdata->pending_bondings = NULL; + if (pdata->pin_reqs) { + slist_foreach(pdata->pin_reqs, (slist_func_t) free, NULL); + slist_free(pdata->pin_reqs); + pdata->pin_reqs = NULL; } if (pdata->active_conn) { @@ -688,19 +699,19 @@ int hcid_dbus_stop_device(uint16_t id) return 0; } -int pending_bonding_cmp(const void *p1, const void *p2) +int pin_req_cmp(const void *p1, const void *p2) { - const struct pending_bonding_info *pb1 = p1; - const struct pending_bonding_info *pb2 = p2; + const struct pending_pin_info *pb1 = p1; + const struct pending_pin_info *pb2 = p2; return p2 ? bacmp(&pb1->bdaddr, &pb2->bdaddr) : -1; } -void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba) +void hcid_dbus_pending_pin_req_add(bdaddr_t *sba, bdaddr_t *dba) { char path[MAX_PATH_LENGTH], addr[18]; struct hci_dbus_data *pdata; - struct pending_bonding_info *peer; + struct pending_pin_info *info; ba2str(sba, addr); @@ -711,11 +722,15 @@ void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba) return; } - peer = malloc(sizeof(*peer)); - memset(peer, 0, sizeof(*peer)); + info = malloc(sizeof(struct pending_pin_info)); + if (!info) { + error("Out of memory when adding new pin request"); + return; + } - bacpy(&peer->bdaddr, dba); - pdata->pending_bondings = slist_append(pdata->pending_bondings, peer); + memset(info, 0, sizeof(struct pending_pin_info)); + bacpy(&info->bdaddr, dba); + pdata->pin_reqs = slist_append(pdata->pin_reqs, info); } int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) @@ -729,7 +744,7 @@ int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) return handle_passkey_request(connection, dev, path, sba, &ci->bdaddr); } -void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status) +void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status) { struct hci_dbus_data *pdata; DBusMessage *message; @@ -756,34 +771,19 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u goto failed; } - /* - * 0x00: authentication request successfully completed - * 0x01-0x0F: authentication request failed - */ -#if 0 - name = status ? "BondingFailed" : "BondingCreated"; - /* authentication signal */ - message = dev_signal_factory(pdata->dev_id, name, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID); - - send_reply_and_unref(connection, message); -#endif - if (status) cancel_passkey_agent_requests(pdata->passkey_agents, path, peer); - l = slist_find(pdata->pending_bondings, peer, pending_bonding_cmp); + l = slist_find(pdata->pin_reqs, peer, pin_req_cmp); if (l) { void *d = l->data; - pdata->pending_bondings = slist_remove(pdata->pending_bondings, l->data); + pdata->pin_reqs = slist_remove(pdata->pin_reqs, l->data); free(d); if (!status) { - const char *name = "BondingCreated"; - message = dev_signal_factory(pdata->dev_id, name, - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID); + message = dev_signal_factory(pdata->dev_id, "BondingCreated", + DBUS_TYPE_STRING, &peer_addr, + DBUS_TYPE_INVALID); send_reply_and_unref(connection, message); } } @@ -793,26 +793,6 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u if (!pdata->bonding || bacmp(&pdata->bonding->bdaddr, peer)) goto failed; /* skip: no bonding req pending */ - 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; - struct hci_req_data *data; - disconnect_cp cp; - memset(&cp, 0, sizeof(cp)); - - cp.handle = con->handle; - cp.reason = (status ? HCI_AUTHENTICATION_FAILURE : 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); - } - } - if (pdata->bonding->cancel) { /* reply authentication canceled */ error_authentication_canceled(connection, pdata->bonding->rq); @@ -825,6 +805,7 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u name_listener_remove(connection, dbus_message_get_sender(pdata->bonding->rq), (name_cb_t) create_bond_req_exit, pdata); + g_io_channel_close(pdata->bonding->io); bonding_request_free(pdata->bonding); pdata->bonding = NULL; @@ -1236,9 +1217,6 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, b { char path[MAX_PATH_LENGTH]; DBusMessage *message; - struct hci_request rq; - evt_cmd_status rp; - auth_requested_cp cp; struct hci_dbus_data *pdata; char *local_addr, *peer_addr; bdaddr_t tmp; @@ -1274,72 +1252,6 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, b active_conn_append(&pdata->active_conn, peer, handle); } - /* check if this connection request was requested by a bonding procedure */ - if (!pdata->bonding || bacmp(&pdata->bonding->bdaddr, peer)) - goto done; /* skip */ - - dd = hci_open_dev(pdata->dev_id); - if (dd < 0) { - error_no_such_adapter(connection, pdata->bonding->rq); - goto bonding_failed; - } - - if (pdata->bonding->cancel) { - error_authentication_canceled(connection, pdata->bonding->rq); - - /* - * When the controller doesn't support cancel create connection, - * disconnect the if the connection has been completed later. - */ - if (!status) - hci_disconnect(dd, htobs(handle), HCI_AUTHENTICATION_FAILURE, 1000); - - goto bonding_failed; - } - - if (status) { - error_connection_attempt_failed(connection, pdata->bonding->rq, bt_error(status)); - goto bonding_failed; - } - - /* request authentication */ - memset(&rq, 0, sizeof(rq)); - memset(&rp, 0, sizeof(rp)); - memset(&cp, 0, sizeof(cp)); - - cp.handle = handle; - - rq.ogf = OGF_LINK_CTL; - rq.event = EVT_CMD_STATUS; - rq.rparam = &rp; - rq.rlen = EVT_CMD_STATUS_SIZE; - rq.ocf = OCF_AUTH_REQUESTED; - rq.cparam = &cp; - rq.clen = AUTH_REQUESTED_CP_SIZE; - - if (hci_send_req(dd, &rq, 100) < 0) { - error("Unable to send the HCI request: %s (%d)", - strerror(errno), errno); - error_failed(connection, pdata->bonding->rq, errno); - goto bonding_failed; - } - - if (rp.status) { - error("HCI_Authentication_Requested failed with status 0x%02x", - rp.status); - error_failed(connection, pdata->bonding->rq, bt_error(rp.status)); - goto bonding_failed; - } - - goto done; /* skip: authentication requested */ - -bonding_failed: - /* free bonding request if the HCI pairing request was not sent */ - name_listener_remove(connection, dbus_message_get_sender(pdata->bonding->rq), - (name_cb_t) create_bond_req_exit, pdata); - bonding_request_free(pdata->bonding); - pdata->bonding = NULL; - done: if (dd >= 0) hci_close_dev(dd); @@ -1397,13 +1309,6 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle /* Check if there is a pending CreateBonding request */ if (pdata->bonding && (bacmp(&pdata->bonding->bdaddr, &dev->bdaddr) == 0)) { -#if 0 - message = dev_signal_factory(pdata->dev_id, "BondingFailed", - DBUS_TYPE_STRING, &peer_addr, - DBUS_TYPE_INVALID); - - send_reply_and_unref(connection, message); -#endif if (pdata->bonding->cancel) { /* reply authentication canceled */ error_authentication_canceled(connection, pdata->bonding->rq); @@ -1414,6 +1319,7 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle name_listener_remove(connection, dbus_message_get_sender(pdata->bonding->rq), (name_cb_t) create_bond_req_exit, pdata); + g_io_channel_close(pdata->bonding->io); bonding_request_free(pdata->bonding); pdata->bonding = NULL; } @@ -2011,13 +1917,10 @@ void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr) goto failed; } - if (!pdata->pending_bondings) - goto failed; - - l = slist_find(pdata->pending_bondings, &ret->bdaddr, pending_bonding_cmp); + l = slist_find(pdata->pin_reqs, &ret->bdaddr, pin_req_cmp); if (l) { - struct pending_bonding_info *p = l->data; - p->step = 1; + struct pending_pin_info *p = l->data; + p->replied = 1; } failed: @@ -2027,6 +1930,7 @@ failed: void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata) { char path[MAX_PATH_LENGTH]; + struct slist *l; snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, pdata->dev_id); @@ -2035,27 +1939,28 @@ void create_bond_req_exit(const char *name, struct hci_dbus_data *pdata) cancel_passkey_agent_requests(pdata->passkey_agents, path, &pdata->bonding->bdaddr); release_passkey_agents(pdata, &pdata->bonding->bdaddr); - if (pdata->bonding->disconnect) { - struct slist *l; - - l = slist_find(pdata->active_conn, &pdata->bonding->bdaddr, active_conn_find_by_bdaddr); - if (l) { - struct active_conn_info *con = l->data; - struct hci_req_data *data; - disconnect_cp cp; - memset(&cp, 0, sizeof(cp)); - - cp.handle = con->handle; - cp.reason = HCI_OE_USER_ENDED_CONNECTION; + l = slist_find(pdata->pin_reqs, &pdata->bonding->bdaddr, pin_req_cmp); + if (l) { + struct pending_pin_info *p = l->data; - data = hci_req_data_new(pdata->dev_id, &pdata->bonding->bdaddr, OGF_LINK_CTL, - OCF_DISCONNECT, EVT_DISCONN_COMPLETE, - &cp, DISCONNECT_CP_SIZE); + if (!p->replied) { + int dd; - hci_req_queue_append(data); + dd = hci_open_dev(pdata->dev_id); + if (dd >= 0) { + hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &pdata->bonding->bdaddr); + hci_close_dev(dd); + } } + + pdata->pin_reqs = slist_remove(pdata->pin_reqs, p); + free(p); } + g_io_channel_close(pdata->bonding->io); + if (pdata->bonding->io_id) + g_io_remove_watch(pdata->bonding->io_id); bonding_request_free(pdata->bonding); pdata->bonding = NULL; } diff --git a/hcid/dbus.h b/hcid/dbus.h index 34e6fe0c..ebd634a2 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -86,15 +86,16 @@ struct discovered_dev_info { struct bonding_request_info { bdaddr_t bdaddr; + DBusConnection *conn; DBusMessage *rq; + GIOChannel *io; + guint io_id; int cancel; - int disconnect; /* disconnect after finish */ }; -struct pending_bonding_info { +struct pending_pin_info { bdaddr_t bdaddr; - int step; /* 0: waiting host passkey 1:waiting remote passkey */ - + int replied; /* If we've already replied to the request */ }; struct active_conn_info { @@ -115,9 +116,9 @@ struct hci_dbus_data { char *discovery_requestor; /* discovery requestor unique name */ DBusMessage *discovery_cancel; /* discovery cancel message request */ struct slist *passkey_agents; - struct bonding_request_info *bonding; struct slist *active_conn; - struct slist *pending_bondings; /* track D-Bus and non D-Bus requests */ + struct bonding_request_info *bonding; + struct slist *pin_reqs; }; struct passkey_agent { @@ -227,7 +228,7 @@ static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusM 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 pin_req_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_req_name(struct hci_dbus_data *dbus_data); diff --git a/hcid/hcid.h b/hcid/hcid.h index 7eb231f9..48041166 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -148,7 +148,7 @@ int hcid_dbus_register_device(uint16_t id); int hcid_dbus_unregister_device(uint16_t id); int hcid_dbus_start_device(uint16_t id); int hcid_dbus_stop_device(uint16_t id); -void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba); +void hcid_dbus_pending_pin_req_add(bdaddr_t *sba, bdaddr_t *dba); int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci); void hcid_dbus_inquiry_start(bdaddr_t *local); @@ -158,7 +158,7 @@ void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name); void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer); void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, uint8_t reason); -void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status); +void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status); void hcid_dbus_setname_complete(bdaddr_t *local); void hcid_dbus_setscan_enable_complete(bdaddr_t *local); void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr); diff --git a/hcid/security.c b/hcid/security.c index ebdc130c..cd78dd05 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -399,7 +399,7 @@ static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba) hcid_dbus_request_pin(dev, sba, ci); } - hcid_dbus_pending_bonding_add(sba, &ci->bdaddr); + hcid_dbus_pending_pin_req_add(sba, &ci->bdaddr); free(cr); |