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 | |
| parent | 87123c20dcf8baf2b952709ff2aacb07a21ca1b3 (diff) | |
Use L2CAP raw sockets for HCI connection creation
| -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); | 
