summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2006-09-15 14:44:22 +0000
committerMarcel Holtmann <marcel@holtmann.org>2006-09-15 14:44:22 +0000
commit0ab6b68b07ee96bf4bd4cf0fe7d4b68582b5caf5 (patch)
tree77d374eb81c90b66d9994c9cd058812d49209a16 /hcid
parent87123c20dcf8baf2b952709ff2aacb07a21ca1b3 (diff)
Use L2CAP raw sockets for HCI connection creation
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-adapter.c355
-rw-r--r--hcid/dbus.c229
-rw-r--r--hcid/dbus.h15
-rw-r--r--hcid/hcid.h4
-rw-r--r--hcid/security.c2
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);