diff options
| author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2009-01-11 10:18:23 -0300 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2009-01-11 19:11:59 +0200 | 
| commit | 2aad1cf41acbc69481915d24cef33fa721d4e1fd (patch) | |
| tree | 3415f14eb928bc6da4c86bd8600697d31c062c97 | |
| parent | 60ec17b68922904833973af118ff91e0f1df1b04 (diff) | |
Move bonding creation to device.c.
| -rw-r--r-- | src/adapter.c | 694 | ||||
| -rw-r--r-- | src/adapter.h | 36 | ||||
| -rw-r--r-- | src/dbus-hci.c | 358 | ||||
| -rw-r--r-- | src/device.c | 692 | ||||
| -rw-r--r-- | src/device.h | 27 | 
5 files changed, 784 insertions, 1023 deletions
| diff --git a/src/adapter.c b/src/adapter.c index 21db540e..5df012e6 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -108,9 +108,6 @@ struct btd_adapter {  	GSList *passkey_agents;  	struct agent *agent;		/* For the new API */  	GSList *active_conn; -	struct bonding_request_info *bonding; -	GSList *auth_reqs;		/* Received and replied HCI -					   authentication requests */  	GSList *devices;		/* Devices structure pointers */  	GSList *mode_sessions;		/* Request Mode sessions */  	GSList *disc_sessions;		/* Discovery sessions */ @@ -179,59 +176,6 @@ static inline DBusMessage *unsupported_major_class(DBusMessage *msg)  			"Unsupported Major Class");  } -static DBusHandlerResult error_failed(DBusConnection *conn, -					DBusMessage *msg, const char * desc) -{ -	return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc); -} - -static DBusHandlerResult error_failed_errno(DBusConnection *conn, -						DBusMessage *msg, int err) -{ -	const char *desc = strerror(err); - -	return error_failed(conn, msg, desc); -} - -static DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn, -						DBusMessage *msg, int err) -{ -	return error_common_reply(conn, msg, -			ERROR_INTERFACE ".ConnectionAttemptFailed", -			err > 0 ? strerror(err) : "Connection attempt failed"); -} - -static void bonding_request_free(struct bonding_request_info *bonding) -{ -	struct btd_device *device; -	char address[18]; -	struct agent *agent; - -	if (!bonding) -		return; - -	if (bonding->msg) -		dbus_message_unref(bonding->msg); - -	if (bonding->conn) -		dbus_connection_unref(bonding->conn); - -	if (bonding->io) -		g_io_channel_unref(bonding->io); - -	ba2str(&bonding->bdaddr, address); - -	device = adapter_find_device(bonding->adapter, address); -	agent = device_get_agent(device); - -	if (device && agent) { -		agent_destroy(agent, FALSE); -		device_set_agent(device, NULL); -	} - -	g_free(bonding); -} -  static int active_conn_find_by_bdaddr(const void *data, const void *user_data)  {  	const struct active_conn_info *con = data; @@ -285,62 +229,6 @@ static int found_device_cmp(const struct remote_dev_info *d1,  	return 0;  } -static int auth_req_cmp(const void *p1, const void *p2) -{ -	const struct pending_auth_info *pb1 = p1; -	const bdaddr_t *bda = p2; - -	return bda ? bacmp(&pb1->bdaddr, bda) : -1; -} - -struct pending_auth_info *adapter_find_auth_request(struct btd_adapter *adapter, -							bdaddr_t *dba) -{ -	GSList *l; - -	l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp); -	if (l) -		return l->data; - -	return NULL; -} - -void adapter_remove_auth_request(struct btd_adapter *adapter, bdaddr_t *dba) -{ -	GSList *l; -	struct pending_auth_info *auth; - -	l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp); -	if (!l) -		return; - -	auth = l->data; - -	adapter->auth_reqs = g_slist_remove(adapter->auth_reqs, auth); - -	g_free(auth); -} - -struct pending_auth_info *adapter_new_auth_request(struct btd_adapter *adapter, -							bdaddr_t *dba, -							auth_type_t type) -{ -	struct pending_auth_info *info; - -	debug("hcid_dbus_new_auth_request"); - -	info = g_new0(struct pending_auth_info, 1); - -	bacpy(&info->bdaddr, dba); -	info->type = type; -	adapter->auth_reqs = g_slist_append(adapter->auth_reqs, info); - -	if (adapter->bonding && !bacmp(dba, &adapter->bonding->bdaddr)) -		adapter->bonding->auth_active = 1; - -	return info; -} -  static void dev_info_free(struct remote_dev_info *dev)  {  	g_free(dev->alias); @@ -384,91 +272,6 @@ int pending_remote_name_cancel(struct btd_adapter *adapter)  	return err;  } -static int auth_info_agent_cmp(const void *a, const void *b) -{ -	const struct pending_auth_info *auth = a; -	const struct agent *agent = b; - -	if (auth->agent == agent) -		return 0; - -	return -1; -} - -static void device_agent_removed(struct agent *agent, void *user_data) -{ -	struct btd_device *device = user_data; -	struct pending_auth_info *auth; -	GSList *l; -	struct btd_adapter *adapter; - -	adapter = device_get_adapter(device); -	device_set_agent(device, NULL); - -	l = g_slist_find_custom(adapter->auth_reqs, agent, -					auth_info_agent_cmp); -	if (!l) -		return; - -	auth = l->data; -	auth->agent = NULL; -} - -static struct bonding_request_info *bonding_request_new(DBusConnection *conn, -							DBusMessage *msg, -							struct btd_adapter *adapter, -							const char *address, -							const char *agent_path, -							uint8_t capability) -{ -	struct bonding_request_info *bonding; -	struct btd_device *device; -	const char *name = dbus_message_get_sender(msg); -	struct agent *agent; -	char addr[18]; -	bdaddr_t bdaddr; - -	debug("bonding_request_new(%s)", address); - -	device = adapter_get_device(conn, adapter, address); -	if (!device) -		return NULL; - -	device_get_address(device, &bdaddr); -	ba2str(&bdaddr, addr); - -	if (adapter->agent && -			agent_matches(adapter->agent, name, agent_path)) { -		error("Refusing adapter agent usage as device specific one"); -		return NULL; -	} - -	agent = agent_create(adapter, name, agent_path, -					capability, -					device_agent_removed, -					device); -	if (!agent) { -		error("Unable to create a new agent"); -		return NULL; -	} - -	device_set_agent(device, agent); - -	debug("Temporary agent registered for hci%d/%s at %s:%s", -			adapter->dev_id, addr, name, -			agent_path); - -	bonding = g_new0(struct bonding_request_info, 1); - -	bonding->conn = dbus_connection_ref(conn); -	bonding->msg = dbus_message_ref(msg); -	bonding->adapter = adapter; - -	str2ba(address, &bonding->bdaddr); - -	return bonding; -} -  static int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited)  {  	uint32_t dev_class; @@ -1079,19 +882,6 @@ static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,  	return dbus_message_new_method_return(msg);  } -static void reply_authentication_failure(struct bonding_request_info *bonding) -{ -	DBusMessage *reply; -	int status; - -	status = bonding->hci_status ? -			bonding->hci_status : HCI_AUTHENTICATION_FAILURE; - -	reply = new_authentication_return(bonding->msg, status); -	if (reply) -		g_dbus_send_message(bonding->conn, reply); -} -  struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest)  {  	struct btd_device *device; @@ -1156,93 +946,6 @@ struct btd_device *adapter_create_device(DBusConnection *conn,  	return device;  } -static DBusMessage *remove_bonding(DBusConnection *conn, DBusMessage *msg, -					const char *address, void *data) -{ -	struct btd_adapter *adapter = data; -	struct btd_device *device; -	char filename[PATH_MAX + 1]; -	char *str, srcaddr[18]; -	bdaddr_t dst; -	GSList *l; -	int dev; -	gboolean paired; - -	str2ba(address, &dst); -	ba2str(&adapter->bdaddr, srcaddr); - -	dev = hci_open_dev(adapter->dev_id); -	if (dev < 0 && msg) -		return no_such_adapter(msg); - -	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, -			"linkkeys"); - -	/* textfile_del doesn't return an error when the key is not found */ -	str = textfile_caseget(filename, address); -	paired = str ? TRUE : FALSE; -	g_free(str); - -	if (!paired && msg) { -		hci_close_dev(dev); -		return g_dbus_create_error(msg, -				ERROR_INTERFACE ".DoesNotExist", -				"Bonding does not exist"); -	} - -	/* Delete the link key from storage */ -	if (textfile_casedel(filename, address) < 0 && msg) { -		int err = errno; -		hci_close_dev(dev); -		return failed_strerror(msg, err); -	} - -	/* Delete the link key from the Bluetooth chip */ -	hci_delete_stored_link_key(dev, &dst, 0, HCI_REQ_TIMEOUT); - -	/* find the connection */ -	l = g_slist_find_custom(adapter->active_conn, &dst, -				active_conn_find_by_bdaddr); -	if (l) { -		struct active_conn_info *con = l->data; -		/* Send the HCI disconnect command */ -		if ((hci_disconnect(dev, htobs(con->handle), -					HCI_OE_USER_ENDED_CONNECTION, -					HCI_REQ_TIMEOUT) < 0) -					&& msg){ -			int err = errno; -			error("Disconnect failed"); -			hci_close_dev(dev); -			return failed_strerror(msg, err); -		} -	} - -	hci_close_dev(dev); - -	device = adapter_find_device(adapter, address); -	if (!device) -		goto proceed; - -	if (paired) { -		gboolean paired = FALSE; - -		const gchar *dev_path = device_get_path(device); - -		emit_property_changed(conn, dev_path, DEVICE_INTERFACE, -					"Paired", DBUS_TYPE_BOOLEAN, &paired); -	} - -proceed: -	if(!msg) -		goto done; - -	return dbus_message_new_method_return(msg); - -done: -	return NULL; -} - -  void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,  				struct btd_device *device)  { @@ -1257,9 +960,6 @@ void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,  	delete_entry(&adapter->bdaddr, "profiles", dstaddr);  	adapter->devices = g_slist_remove(adapter->devices, device); -	if (!device_is_temporary(device)) -		remove_bonding(conn, NULL, dstaddr, adapter); -  	adapter_update_devices(adapter);  	g_dbus_emit_signal(conn, adapter->path, @@ -1274,7 +974,7 @@ void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,  		device_set_agent(device, NULL);  	} -	device_remove(conn, device); +	device_remove(device, conn);  }  struct btd_device *adapter_get_device(DBusConnection *conn, @@ -1294,292 +994,6 @@ struct btd_device *adapter_get_device(DBusConnection *conn,  	return adapter_create_device(conn, adapter, address);  } -void remove_pending_device(struct btd_adapter *adapter) -{ -	struct btd_device *device; -	char address[18]; - -	ba2str(&adapter->bonding->bdaddr, address); -	device = adapter_find_device(adapter, address); -	if (!device) -		return; - -	if (device_is_temporary(device)) -		adapter_remove_device(adapter->bonding->conn, adapter, device); -} - -static gboolean create_bonding_io_cb(GIOChannel *io, GIOCondition cond, -					struct btd_adapter *adapter) -{ -	struct hci_request rq; -	auth_requested_cp cp; -	evt_cmd_status rp; -	struct l2cap_conninfo cinfo; -	socklen_t len; -	int sk, dd, ret; - -	if (!adapter->bonding) { -		/* If we come here it implies a bug somewhere */ -		debug("create_bonding_io_cb: no pending bonding!"); -		g_io_channel_close(io); -		return FALSE; -	} - -	if (cond & G_IO_NVAL) { -		DBusMessage *reply; -		reply = new_authentication_return(adapter->bonding->msg, 0x09); -		g_dbus_send_message(adapter->bonding->conn, reply); -		goto cleanup; -	} - -	if (cond & (G_IO_HUP | G_IO_ERR)) { -		debug("Hangup or error on bonding IO channel"); - -		if (!adapter->bonding->auth_active) -			error_connection_attempt_failed(adapter->bonding->conn, -							adapter->bonding->msg, -							ENETDOWN); -		else -			reply_authentication_failure(adapter->bonding); - -		goto failed; -	} - -	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_errno(adapter->bonding->conn, adapter->bonding->msg, -				errno); -		goto failed; -	} - -	if (ret != 0) { -		if (adapter->bonding->auth_active) -			reply_authentication_failure(adapter->bonding); -		else -			error_connection_attempt_failed(adapter->bonding->conn, -							adapter->bonding->msg, -							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_errno(adapter->bonding->conn, adapter->bonding->msg, -				errno); -		goto failed; -	} - -	dd = hci_open_dev(adapter->dev_id); -	if (dd < 0) { -		DBusMessage *reply = no_such_adapter(adapter->bonding->msg); -		g_dbus_send_message(adapter->bonding->conn, reply); -		goto failed; -	} - -	memset(&rp, 0, sizeof(rp)); - -	memset(&cp, 0, sizeof(cp)); -	cp.handle = htobs(cinfo.hci_handle); - -	memset(&rq, 0, sizeof(rq)); -	rq.ogf    = OGF_LINK_CTL; -	rq.ocf    = OCF_AUTH_REQUESTED; -	rq.cparam = &cp; -	rq.clen   = AUTH_REQUESTED_CP_SIZE; -	rq.rparam = &rp; -	rq.rlen   = EVT_CMD_STATUS_SIZE; -	rq.event  = EVT_CMD_STATUS; - -	if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { -		error("Unable to send HCI request: %s (%d)", -					strerror(errno), errno); -		error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, -				errno); -		hci_close_dev(dd); -		goto failed; -	} - -	if (rp.status) { -		error("HCI_Authentication_Requested failed with status 0x%02x", -				rp.status); -		error_failed_errno(adapter->bonding->conn, adapter->bonding->msg, -				bt_error(rp.status)); -		hci_close_dev(dd); -		goto failed; -	} - -	hci_close_dev(dd); - -	adapter->bonding->auth_active = 1; - -	adapter->bonding->io_id = g_io_add_watch(io, -						G_IO_NVAL | G_IO_HUP | G_IO_ERR, -						(GIOFunc) create_bonding_io_cb, -						adapter); - -	return FALSE; - -failed: -	g_io_channel_close(io); -	remove_pending_device(adapter); - -cleanup: -	g_dbus_remove_watch(adapter->bonding->conn, -				adapter->bonding->listener_id); -	bonding_request_free(adapter->bonding); -	adapter->bonding = NULL; - -	return FALSE; -} - -static void cancel_auth_request(struct pending_auth_info *auth, int dev_id) -{ -	int dd; - -	if (auth->replied) -		return; - -	dd = hci_open_dev(dev_id); -	if (dd < 0) { -		error("hci_open_dev: %s (%d)", strerror(errno), errno); -		return; -	} - -	switch (auth->type) { -	case AUTH_TYPE_PINCODE: -		hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, -				6, &auth->bdaddr); -		break; -	case AUTH_TYPE_CONFIRM: -		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY, -				6, &auth->bdaddr); -		break; -	case AUTH_TYPE_PASSKEY: -		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY, -				6, &auth->bdaddr); -		break; -	case AUTH_TYPE_NOTIFY: -		/* User Notify doesn't require any reply */ -		break; -	} - -	auth->replied = TRUE; - -	hci_close_dev(dd); -} - -static void cancel_bonding(struct btd_adapter *adapter, gboolean exited) -{ -	struct pending_auth_info *auth; -	struct bonding_request_info *bonding = adapter->bonding; - -	auth = adapter_find_auth_request(adapter, &adapter->bdaddr); -	if (auth) { -		cancel_auth_request(auth, adapter->dev_id); -		if (auth->agent) -			agent_cancel(auth->agent); -		adapter_remove_auth_request(adapter, &bonding->bdaddr); -	} - -	remove_pending_device(adapter); - -	if (bonding->io) -		g_io_channel_close(bonding->io); - -	if (exited) { -		if (bonding->io_id) { -			g_source_remove(bonding->io_id); -			bonding->io_id = 0; -		} -		bonding_request_free(bonding); -		adapter->bonding = NULL; - -	} else -		bonding->cancel = TRUE; -} - -static void create_bond_req_exit(DBusConnection *conn, void *user_data) -{ -	struct btd_adapter *adapter = user_data; - -	debug("CreateConnection requestor exited before bonding was completed"); - -	cancel_bonding(adapter, TRUE); -} - -static DBusMessage *create_bonding(DBusConnection *conn, DBusMessage *msg, -				const char *address, const char *agent_path, -				uint8_t capability, void *data) -{ -	char filename[PATH_MAX + 1]; -	char *str, srcaddr[18]; -	struct btd_adapter *adapter = data; -	struct bonding_request_info *bonding; -	bdaddr_t dst; -	int sk; - -	str2ba(address, &dst); -	ba2str(&adapter->bdaddr, srcaddr); - -	/* check if there is a pending discover: requested by D-Bus/non clients */ -	if (adapter->state & STD_INQUIRY) -		return in_progress(msg, "Discover in progress"); - -	pending_remote_name_cancel(adapter); - -	if (adapter->bonding) -		return in_progress(msg, "Bonding in progress"); - -	if (adapter_find_auth_request(adapter, &dst)) -		return in_progress(msg, "Bonding in progress"); - -	/* check if a link key already exists */ -	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, -			"linkkeys"); - -	str = textfile_caseget(filename, address); -	if (str) { -		free(str); -		return g_dbus_create_error(msg, -				ERROR_INTERFACE ".AlreadyExists", -				"Bonding already exists"); -	} - -	sk = l2raw_connect(&adapter->bdaddr, &dst); -	if (sk < 0) -		return g_dbus_create_error(msg, -				ERROR_INTERFACE ".ConnectionAttemptFailed", -				"Connection attempt failed"); - -	bonding = bonding_request_new(conn, msg, adapter, address, agent_path, -					capability); -	if (!bonding) { -		close(sk); -		return NULL; -	} - -	bonding->io = g_io_channel_unix_new(sk); -	bonding->io_id = g_io_add_watch(bonding->io, -					G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, -					(GIOFunc) create_bonding_io_cb, -					adapter); - -	bonding->listener_id = g_dbus_add_disconnect_watch(conn, -						dbus_message_get_sender(msg), -						create_bond_req_exit, adapter, -						NULL); - -	adapter->bonding = bonding; - -	return NULL; -} -  static int start_inquiry(struct btd_adapter *adapter)  {  	inquiry_cp cp; @@ -2010,9 +1424,8 @@ static DBusMessage *cancel_device_creation(DBusConnection *conn,  						DBusMessage *msg, void *data)  {  	struct btd_adapter *adapter = data; -	struct bonding_request_info *bonding = adapter->bonding;  	const gchar *address; -	bdaddr_t bda; +	struct btd_device *device;  	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,  						DBUS_TYPE_INVALID) == FALSE) @@ -2021,16 +1434,17 @@ static DBusMessage *cancel_device_creation(DBusConnection *conn,  	if (check_address(address) < 0)  		return invalid_args(msg); -	str2ba(address, &bda); +	device = adapter_find_device(adapter, address); +	if (!device) +		return g_dbus_create_error(msg, +				ERROR_INTERFACE ".DoesNotExist", +				"Device does not exist"); -	if (bonding && !bacmp(&bonding->bdaddr, &bda)) { -		if (!g_str_equal(dbus_message_get_sender(msg), -					dbus_message_get_sender(bonding->msg))) -			return not_authorized(msg); +	if (!device_is_temporary(device) || +			!device_is_bonding(device, dbus_message_get_sender(msg))) +		return not_authorized(msg); -		debug("Canceling device creation for %s", address); -		cancel_bonding(adapter, FALSE); -	} +	adapter_remove_device(conn, adapter, device);  	return dbus_message_new_method_return(msg);  } @@ -2085,7 +1499,9 @@ static uint8_t parse_io_capability(const char *capability)  static DBusMessage *create_paired_device(DBusConnection *conn,  					DBusMessage *msg, void *data)  { -	const gchar *address, *agent_path, *capability; +	struct btd_adapter *adapter = data; +	struct btd_device *device; +	const gchar *address, *agent_path, *capability, *sender;  	uint8_t cap;  	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, @@ -2097,11 +1513,20 @@ static DBusMessage *create_paired_device(DBusConnection *conn,  	if (check_address(address) < 0)  		return invalid_args(msg); +	sender = dbus_message_get_sender(msg); +	if (adapter->agent && +			agent_matches(adapter->agent, sender, agent_path)) { +		error("Refusing adapter agent usage as device specific one"); +		return invalid_args(msg); +	} +  	cap = parse_io_capability(capability);  	if (cap == IO_CAPABILITY_INVALID)  		return invalid_args(msg); -	return create_bonding(conn, msg, address, agent_path, cap, data); +	device = adapter_get_device(conn, adapter, address); + +	return device_create_bonding(device, conn, msg, agent_path, cap);  }  static gint device_path_cmp(struct btd_device *device, const gchar *path) @@ -2179,18 +1604,7 @@ static DBusMessage *find_device(DBusConnection *conn,  static void agent_removed(struct agent *agent, struct btd_adapter *adapter)  { -	struct pending_auth_info *auth; -	GSList *l; -  	adapter->agent = NULL; - -	l = g_slist_find_custom(adapter->auth_reqs, agent, -					auth_info_agent_cmp); -	if (!l) -		return; - -	auth = l->data; -	auth->agent = NULL;  }  static DBusMessage *register_agent(DBusConnection *conn, @@ -2725,27 +2139,18 @@ setup:  static void reply_pending_requests(struct btd_adapter *adapter)  { -	DBusMessage *reply; +	GSList *l;  	if (!adapter)  		return;  	/* pending bonding */ -	if (adapter->bonding) { -		reply = new_authentication_return(adapter->bonding->msg, -					HCI_OE_USER_ENDED_CONNECTION); -		g_dbus_send_message(connection, reply); -		remove_pending_device(adapter); - -		g_dbus_remove_watch(adapter->bonding->conn, -					adapter->bonding->listener_id); +	for (l = adapter->devices; l; l = l->next) { +		struct btd_device *device = l->data; -		if (adapter->bonding->io_id) -			g_source_remove(adapter->bonding->io_id); -		if (adapter->bonding->io) -			g_io_channel_close(adapter->bonding->io); -		bonding_request_free(adapter->bonding); -		adapter->bonding = NULL; +		if (device_is_bonding(device, NULL)) +			device_cancel_bonding(device, +						HCI_OE_USER_ENDED_CONNECTION);  	}  	if (adapter->state & STD_INQUIRY) { @@ -2806,12 +2211,6 @@ int adapter_stop(struct btd_adapter *adapter)  		adapter->oor_devices = NULL;  	} -	if (adapter->auth_reqs) { -		g_slist_foreach(adapter->auth_reqs, (GFunc) g_free, NULL); -		g_slist_free(adapter->auth_reqs); -		adapter->auth_reqs = NULL; -	} -  	if (adapter->active_conn) {  		g_slist_foreach(adapter->active_conn, (GFunc) g_free, NULL);  		g_slist_free(adapter->active_conn); @@ -2958,7 +2357,7 @@ void adapter_remove(struct btd_adapter *adapter)  	unload_drivers(adapter);  	for (l = adapter->devices; l; l = l->next) -		device_remove(connection, l->data); +		device_remove(l->data, connection);  	g_slist_free(adapter->devices);  	/* Return adapter to down state if it was not up on init */ @@ -3304,29 +2703,6 @@ struct active_conn_info *adapter_search_active_conn_by_handle(struct btd_adapter  	return NULL;  } -void adapter_free_bonding_request(struct btd_adapter *adapter) -{ -	g_dbus_remove_watch(connection, adapter->bonding->listener_id); - -	if (adapter->bonding->io_id) -		g_source_remove(adapter->bonding->io_id); - -	if (adapter->bonding->io) -		g_io_channel_close(adapter->bonding->io); - -	bonding_request_free(adapter->bonding); - -	adapter->bonding = NULL; -} - -struct bonding_request_info *adapter_get_bonding_info(struct btd_adapter *adapter) -{ -	if (!adapter) -		return NULL; - -	return adapter->bonding; -} -  gboolean adapter_has_discov_sessions(struct btd_adapter *adapter)  {  	if (!adapter || !adapter->disc_sessions) @@ -3521,11 +2897,3 @@ gboolean adapter_is_pairable(struct btd_adapter *adapter)  {  	return adapter->pairable;  } - -gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda) -{ -	if (!adapter->bonding) -		return FALSE; - -	return (bacmp(&adapter->bonding->bdaddr, bda) == 0); -} diff --git a/src/adapter.h b/src/adapter.h index 0ca6842c..2f9068f2 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -43,12 +43,7 @@ typedef enum {  	NAME_SENT          /* D-Bus signal RemoteNameUpdated sent */  } name_status_t; -typedef enum { -	AUTH_TYPE_PINCODE, -	AUTH_TYPE_PASSKEY, -	AUTH_TYPE_CONFIRM, -	AUTH_TYPE_NOTIFY, -} auth_type_t; +struct btd_adapter;  struct remote_dev_info {  	bdaddr_t bdaddr; @@ -58,26 +53,6 @@ struct remote_dev_info {  	name_status_t name_status;  }; -struct bonding_request_info { -	DBusConnection *conn; -	DBusMessage *msg; -	struct btd_adapter *adapter; -	bdaddr_t bdaddr; -	GIOChannel *io; -	guint io_id; -	guint listener_id; -	int hci_status; -	int cancel; -	int auth_active; -}; - -struct pending_auth_info { -	auth_type_t type; -	bdaddr_t bdaddr; -	gboolean replied;	/* If we've already replied to the request */ -	struct agent *agent;    /* Agent associated with the request */ -}; -  struct active_conn_info {  	bdaddr_t bdaddr;  	uint16_t handle; @@ -123,12 +98,6 @@ int pending_remote_name_cancel(struct btd_adapter *adapter);  void remove_pending_device(struct btd_adapter *adapter); -struct pending_auth_info *adapter_find_auth_request(struct btd_adapter *adapter, -							bdaddr_t *dba); -void adapter_remove_auth_request(struct btd_adapter *adapter, bdaddr_t *dba); -struct pending_auth_info *adapter_new_auth_request(struct btd_adapter *adapter, -							bdaddr_t *dba, -							auth_type_t type);  struct btd_adapter *adapter_create(DBusConnection *conn, int id,  				gboolean devup);  void adapter_remove(struct btd_adapter *adapter); @@ -155,8 +124,6 @@ struct active_conn_info *adapter_search_active_conn_by_bdaddr(struct btd_adapter  								bdaddr_t *bda);  struct active_conn_info *adapter_search_active_conn_by_handle(struct btd_adapter *adapter,  							uint16_t handle); -void adapter_free_bonding_request(struct btd_adapter *adapter); -struct bonding_request_info *adapter_get_bonding_info(struct btd_adapter *adapter);  gboolean adapter_has_discov_sessions(struct btd_adapter *adapter);  struct btd_adapter_driver { @@ -178,4 +145,3 @@ const char *adapter_any_get_path(void);  const char *btd_adapter_any_request_path(void);  void btd_adapter_any_release_path(void);  gboolean adapter_is_pairable(struct btd_adapter *adapter); -gboolean adapter_pairing_initiator(struct btd_adapter *adapter, bdaddr_t *bda); diff --git a/src/dbus-hci.c b/src/dbus-hci.c index 7432f018..0e574aff 100644 --- a/src/dbus-hci.c +++ b/src/dbus-hci.c @@ -119,54 +119,6 @@ const char *class_to_icon(uint32_t class)  	return NULL;  } -DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status) -{ -	switch (status) { -	case 0x00: /* success */ -		return dbus_message_new_method_return(msg); - -	case 0x04: /* page timeout */ -	case 0x08: /* connection timeout */ -	case 0x10: /* connection accept timeout */ -	case 0x22: /* LMP response timeout */ -	case 0x28: /* instant passed - is this a timeout? */ -		return dbus_message_new_error(msg, -					ERROR_INTERFACE ".AuthenticationTimeout", -					"Authentication Timeout"); -	case 0x17: /* too frequent pairing attempts */ -		return dbus_message_new_error(msg, -					ERROR_INTERFACE ".RepeatedAttempts", -					"Repeated Attempts"); - -	case 0x06: -	case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */ -		return dbus_message_new_error(msg, -					ERROR_INTERFACE ".AuthenticationRejected", -					"Authentication Rejected"); - -	case 0x07: /* memory capacity */ -	case 0x09: /* connection limit */ -	case 0x0a: /* synchronous connection limit */ -	case 0x0d: /* limited resources */ -	case 0x13: /* user ended the connection */ -	case 0x14: /* terminated due to low resources */ -		return dbus_message_new_error(msg, -					ERROR_INTERFACE ".AuthenticationCanceled", -					"Authentication Canceled"); - -	case 0x05: /* authentication failure */ -	case 0x0E: /* rejected due to security reasons - is this auth failure? */ -	case 0x25: /* encryption mode not acceptable - is this auth failure? */ -	case 0x26: /* link key cannot be changed - is this auth failure? */ -	case 0x29: /* pairing with unit key unsupported - is this auth failure? */ -	case 0x2f: /* insufficient security - is this auth failure? */ -	default: -		return dbus_message_new_error(msg, -					ERROR_INTERFACE ".AuthenticationFailed", -					"Authentication Failed"); -	} -} -  /*****************************************************************   *   *  Section reserved to HCI commands confirmation handling and low @@ -182,13 +134,7 @@ static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,  	bdaddr_t sba, dba;  	size_t len;  	int dev; -	struct pending_auth_info *auth;  	uint16_t dev_id = adapter_get_dev_id(adapter); -	struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); - -	/* No need to reply anything if the authentication already failed */ -	if (bonding && bonding->hci_status) -		return;  	dev = hci_open_dev(dev_id);  	if (dev < 0) { @@ -200,8 +146,6 @@ static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,  	adapter_get_address(adapter, &sba);  	device_get_address(device, &dba); -	auth = adapter_find_auth_request(adapter, &dba); -  	if (err) {  		hci_send_cmd(dev, OGF_LINK_CTL,  				OCF_PIN_CODE_NEG_REPLY, 6, &dba); @@ -219,10 +163,6 @@ static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,  	hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr);  done: -	if (auth) { -		auth->replied = TRUE; -		auth->agent = NULL; -	}  	hci_close_dev(dev);  } @@ -231,8 +171,6 @@ int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)  	char addr[18];  	struct btd_adapter *adapter;  	struct btd_device *device; -	struct agent *agent = NULL; -	int ret;  	adapter = manager_find_adapter(sba);  	if (!adapter) { @@ -240,42 +178,21 @@ int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)  		return -1;  	} -	if (!adapter_pairing_initiator(adapter, &ci->bdaddr) && -			!adapter_is_pairable(adapter)) -		return -EPERM; -  	ba2str(&ci->bdaddr, addr);  	device = adapter_find_device(adapter, addr); - -	if (device) -		agent = device_get_agent(device); - -	if (!agent) -		agent = adapter_get_agent(adapter); - -	if (!agent) { -		error("No agent available for PIN request"); +	/* Check if the adapter is not pairable and if there isn't a bonding in +	 * progress */ +	if (!adapter_is_pairable(adapter) && +			!(device && device_is_bonding(device, NULL)))  		return -EPERM; -	} -	if (!device) { -		device = adapter_create_device(connection, adapter, addr); -		if (!device) -			return -ENODEV; -	} - -	ret = agent_request_pincode(agent, device, -					(agent_pincode_cb) pincode_cb, -					device); -	if (ret == 0) { -		struct pending_auth_info *auth; -		auth = adapter_new_auth_request(adapter, &ci->bdaddr, -						AUTH_TYPE_PINCODE); -		auth->agent = agent; -	} +	device = adapter_get_device(connection, adapter, addr); +	if (!device) +		return -ENODEV; -	return ret; +	return device_request_authentication(device, AUTH_TYPE_PINCODE, +					0, pincode_cb);  }  static void confirm_cb(struct agent *agent, DBusError *err, void *user_data) @@ -284,13 +201,7 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)  	struct btd_adapter *adapter = device_get_adapter(device);  	user_confirm_reply_cp cp;  	int dd; -	struct pending_auth_info *auth;  	uint16_t dev_id = adapter_get_dev_id(adapter); -	struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); - -	/* No need to reply anything if the authentication already failed */ -	if (bonding && bonding->hci_status) -		return;  	dd = hci_open_dev(dev_id);  	if (dd < 0) { @@ -301,8 +212,6 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)  	memset(&cp, 0, sizeof(cp));  	device_get_address(device, &cp.bdaddr); -	auth = adapter_find_auth_request(adapter, &cp.bdaddr); -  	if (err)  		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,  					USER_CONFIRM_REPLY_CP_SIZE, &cp); @@ -310,11 +219,6 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)  		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,  					USER_CONFIRM_REPLY_CP_SIZE, &cp); -	if (auth) { -		auth->replied = TRUE; -		auth->agent = FALSE; -	} -  	hci_close_dev(dd);  } @@ -326,13 +230,7 @@ static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,  	user_passkey_reply_cp cp;  	bdaddr_t dba;  	int dd; -	struct pending_auth_info *auth;  	uint16_t dev_id = adapter_get_dev_id(adapter); -	struct bonding_request_info *bonding = adapter_get_bonding_info(adapter); - -	/* No need to reply anything if the authentication already failed */ -	if (bonding && bonding->hci_status) -		return;  	dd = hci_open_dev(dev_id);  	if (dd < 0) { @@ -346,8 +244,6 @@ static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,  	bacpy(&cp.bdaddr, &dba);  	cp.passkey = passkey; -	auth = adapter_find_auth_request(adapter, &dba); -  	if (err)  		hci_send_cmd(dd, OGF_LINK_CTL,  				OCF_USER_PASSKEY_NEG_REPLY, 6, &dba); @@ -355,11 +251,6 @@ static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,  		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_REPLY,  					USER_PASSKEY_REPLY_CP_SIZE, &cp); -	if (auth) { -		auth->replied = TRUE; -		auth->agent = NULL; -	} -  	hci_close_dev(dd);  } @@ -403,10 +294,8 @@ int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)  {  	struct btd_adapter *adapter;  	struct btd_device *device; -	struct agent *agent;  	char addr[18];  	uint8_t type; -	struct pending_auth_info *auth;  	uint16_t dev_id;  	adapter = manager_find_adapter(sba); @@ -457,41 +346,19 @@ int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)  		hci_close_dev(dd); -		auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_CONFIRM); -		auth->replied = TRUE; - -		return 0; -	} - -	agent = device_get_agent(device); - -	if (!agent) -		agent = adapter_get_agent(adapter); - -	if (!agent) { -		error("No agent available for user confirm request"); -		return -1; -	} - -	if (agent_request_confirmation(agent, device, passkey, -						confirm_cb, device) < 0) { -		error("Requesting passkey failed"); -		return -1; +		return device_request_authentication(device, AUTH_TYPE_AUTO, +					0, NULL);  	} -	auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_CONFIRM); -	auth->agent = agent; - -	return 0; +	return device_request_authentication(device, AUTH_TYPE_CONFIRM, +					passkey, confirm_cb);  }  int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)  {  	struct btd_adapter *adapter;  	struct btd_device *device; -	struct agent *agent = NULL;  	char addr[18]; -	struct pending_auth_info *auth;  	adapter = manager_find_adapter(sba);  	if (!adapter) { @@ -503,35 +370,18 @@ int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)  	device = adapter_get_device(connection, adapter, addr); -	if (device) -		agent = device_get_agent(device); - -	if (!agent) -		agent = adapter_get_agent(adapter); - -	if (!agent) { -		error("No agent available for user passkey request"); -		return -1; -	} - -	if (agent_request_passkey(agent, device, passkey_cb, device) < 0) { -		error("Requesting passkey failed"); -		return -1; -	} - -	auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_PASSKEY); -	auth->agent = agent; +	if (!device) +		return -ENODEV; -	return 0; +	return device_request_authentication(device, AUTH_TYPE_PASSKEY, +					0, passkey_cb);  }  int hcid_dbus_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)  {  	struct btd_adapter *adapter;  	struct btd_device *device; -	struct agent *agent = NULL;  	char addr[18]; -	struct pending_auth_info *auth;  	adapter = manager_find_adapter(sba);  	if (!adapter) { @@ -542,26 +392,11 @@ int hcid_dbus_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)  	ba2str(dba, addr);  	device = adapter_get_device(connection, adapter, addr); -	if (device) -		agent = device_get_agent(device); - -	if (!agent) -		agent = adapter_get_agent(adapter); - -	if (!agent) { -		error("No agent available for user confirm request"); -		return -1; -	} - -	if (agent_display_passkey(agent, device, passkey) < 0) { -		error("Displaying passkey failed"); -		return -1; -	} - -	auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_NOTIFY); -	auth->agent = agent; +	if (!device) +		return -ENODEV; -	return 0; +	return device_request_authentication(device, AUTH_TYPE_NOTIFY, +					passkey, NULL);  }  void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, @@ -569,74 +404,35 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer,  {  	struct btd_adapter *adapter;  	char peer_addr[18]; -	DBusMessage *reply;  	struct btd_device *device; -	struct bonding_request_info *bonding; -	struct pending_auth_info *auth;  	debug("hcid_dbus_bonding_process_complete: status=%02x", status); -	ba2str(peer, peer_addr); -  	adapter = manager_find_adapter(local);  	if (!adapter) {  		error("Unable to find matching adapter");  		return;  	} -	bonding = adapter_get_bonding_info(adapter); - -	if (bonding && bacmp(&bonding->bdaddr, peer)) -		bonding = NULL; +	ba2str(peer, peer_addr); -	if (status == 0) { -		device = adapter_get_device(connection, adapter, peer_addr); -		if (!device) { -			/* This should really only happen if we run out of -			 * memory */ -			error("Unable to get device object!"); -			status = HCI_REJECTED_LIMITED_RESOURCES; -		} +	device = adapter_find_device(adapter, peer_addr); +	if (!device) { +		error("Unable to get device object!"); +		return;  	} -	if (status && bonding) -		bonding->hci_status = status; - -	auth = adapter_find_auth_request(adapter, peer); -	if (!auth) { -		/* This means that there was no pending PIN or SSP token request -		 * from the controller, i.e. this is not a new pairing */ +	if (!device_is_authenticating(device)) { +		/* This means that there was no pending PIN or SSP token +		 * request from the controller, i.e. this is not a new +		 * pairing */  		debug("hcid_dbus_bonding_process_complete: no pending auth request"); -		goto proceed; -	} - -	if (auth->agent) -		agent_cancel(auth->agent); - -	adapter_remove_auth_request(adapter, peer); - -	/* If this is a new pairing send the appropriate signal for it -	 * and proceed with service discovery */ -	if (status == 0) { -		device_set_paired(connection, device, bonding); -		if (bonding) -			adapter_free_bonding_request(adapter);  		return;  	} -proceed: -	if (!bonding) -		return; /* skip: no bonding req pending */ - -	if (bonding->cancel) -		reply = new_authentication_return(bonding->msg, -					HCI_OE_USER_ENDED_CONNECTION); -	else -		reply = new_authentication_return(bonding->msg, status); - -	g_dbus_send_message(connection, reply); - -	adapter_free_bonding_request(adapter); +	/* If this is a new pairing send the appropriate reply and signal for +	 * it and proceed with service discovery */ +	device_bonding_complete(device, status);  }  void hcid_dbus_inquiry_start(bdaddr_t *local) @@ -1125,7 +921,6 @@ void hcid_dbus_link_key_notify(bdaddr_t *local, bdaddr_t *peer)  	char peer_addr[18];  	struct btd_device *device;  	struct btd_adapter *adapter; -	struct bonding_request_info *bonding;  	adapter = manager_find_adapter(local);  	if (!adapter) { @@ -1141,11 +936,9 @@ void hcid_dbus_link_key_notify(bdaddr_t *local, bdaddr_t *peer)  		return;  	} -	bonding = adapter_get_bonding_info(adapter); -  	if (!device_get_connected(device))  		device_set_secmode3_conn(device, TRUE); -	else if (!bonding) +	else if (!device_is_bonding(device, NULL))  		hcid_dbus_bonding_process_complete(local, peer, 0);  } @@ -1154,7 +947,6 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,  {  	char peer_addr[18];  	struct btd_adapter *adapter; -	struct bonding_request_info *bonding;  	struct btd_device *device;  	adapter = manager_find_adapter(local); @@ -1166,42 +958,32 @@ void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,  	ba2str(peer, peer_addr);  	device = adapter_get_device(connection, adapter, peer_addr); +	if (!device) { +		error("No matching device found"); +		return; +	}  	if (status) { -		struct pending_auth_info *auth; - -		auth = adapter_find_auth_request(adapter, peer); -		if (auth && auth->agent) -			agent_cancel(auth->agent); - -		adapter_remove_auth_request(adapter, peer); - -		if (device) -			device_set_secmode3_conn(device, FALSE); +		device_set_secmode3_conn(device, FALSE); +		if (device_is_bonding(device, NULL)) +			device_bonding_complete(device, status); +		return; +	} -		bonding = adapter_get_bonding_info(adapter); -		if (bonding) -			bonding->hci_status = status; -	} else { -		if (device) -			device_set_connected(connection, device, TRUE); +	device_set_connected(device, connection, TRUE); -		/* add in the active connetions list */ -		adapter_add_active_conn(adapter, peer, handle); -	} +	/* add in the active connetions list */ +	adapter_add_active_conn(adapter, peer, handle);  }  void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,  				uint16_t handle, uint8_t reason)  { -	DBusMessage *reply;  	char peer_addr[18];  	struct btd_adapter *adapter;  	struct btd_device *device;  	struct active_conn_info *dev; -	struct pending_auth_info *auth;  	uint16_t dev_id; -	struct bonding_request_info *bonding;  	if (status) {  		error("Disconnection failed: 0x%02x", status); @@ -1227,39 +1009,17 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,  	/* clean pending HCI cmds */  	hci_req_queue_remove(dev_id, &dev->bdaddr); -	/* Cancel D-Bus/non D-Bus requests */ -	auth = adapter_find_auth_request(adapter, &dev->bdaddr); -	if (auth && auth->agent) -		agent_cancel(auth->agent); - -	adapter_remove_auth_request(adapter, &dev->bdaddr); - -	bonding = adapter_get_bonding_info(adapter); -	/* Check if there is a pending Bonding request */ -	if (bonding && (bacmp(&bonding->bdaddr, &dev->bdaddr) == 0)) { -		if (bonding->cancel) { -			/* reply authentication canceled */ -			reply = new_authentication_return(bonding->msg, -							HCI_OE_USER_ENDED_CONNECTION); -			g_dbus_send_message(connection, reply); -		} else { -			reply = new_authentication_return(bonding->msg, -							HCI_AUTHENTICATION_FAILURE); -			g_dbus_send_message(connection, reply); -		} -		adapter_free_bonding_request(adapter); -	} -  	adapter_remove_active_conn(adapter, dev);  	device = adapter_find_device(adapter, peer_addr); -	if (device) { -		device_set_connected(connection, device, FALSE); +	if (!device) +		return; -		if (device_is_temporary(device)) { -			debug("Removing temporary device %s", peer_addr); -			adapter_remove_device(connection, adapter, device); -		} +	device_set_connected(device, connection, FALSE); + +	if (device_is_temporary(device)) { +		debug("Removing temporary device %s", peer_addr); +		adapter_remove_device(connection, adapter, device);  	}  } @@ -1482,14 +1242,16 @@ int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,  	if (get_auth_requirements(local, remote, auth) < 0)  		return -1; -	if (!adapter_pairing_initiator(adapter, remote) && -			!adapter_is_pairable(adapter)) -		return -EPERM; -  	ba2str(remote, addr); -	/* For CreatePairedDevice use dedicated bonding */  	device = adapter_find_device(adapter, addr); +	/* Check if the adapter is not pairable and if there isn't a bonding in +	 * progress */ +	if (!adapter_is_pairable(adapter) && +			!(device && device_is_bonding(device, NULL))) +		return -EPERM; + +	/* For CreatePairedDevice use dedicated bonding */  	if (device) {  		agent = device_get_agent(device);  		if (agent) diff --git a/src/device.c b/src/device.c index f51184ca..7891d1e5 100644 --- a/src/device.c +++ b/src/device.c @@ -35,6 +35,7 @@  #include <bluetooth/bluetooth.h>  #include <bluetooth/hci.h>  #include <bluetooth/hci_lib.h> +#include <bluetooth/l2cap.h>  #include <bluetooth/sdp.h>  #include <bluetooth/sdp_lib.h> @@ -65,6 +66,22 @@ struct btd_driver_data {  	void *priv;  }; +struct bonding_req { +	DBusConnection *conn; +	DBusMessage *msg; +	GIOChannel *io; +	guint io_id; +	guint listener_id; +	struct btd_device *device; +}; + +struct authentication_req { +	auth_type_t type; +	void *cb; +	struct agent *agent; +	struct btd_device *device; +}; +  struct btd_device {  	bdaddr_t	bdaddr;  	gchar		*path; @@ -78,6 +95,8 @@ struct btd_device {  	char		*discov_requestor;	/* discovery requestor unique name */  	guint		discov_listener;  	guint		discov_timer; +	struct bonding_req *bonding; +	struct authentication_req *authr;	/* authentication request */  	/* For Secure Simple Pairing */  	uint8_t		cap; @@ -111,6 +130,39 @@ static uint16_t uuid_list[] = {  static GSList *device_drivers = NULL; +static DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn, +						DBusMessage *msg, int err) +{ +	return error_common_reply(conn, msg, +			ERROR_INTERFACE ".ConnectionAttemptFailed", +			err > 0 ? strerror(err) : "Connection attempt failed"); +} + +static DBusHandlerResult error_failed(DBusConnection *conn, +					DBusMessage *msg, const char * desc) +{ +	return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc); +} + +static DBusHandlerResult error_failed_errno(DBusConnection *conn, +						DBusMessage *msg, int err) +{ +	const char *desc = strerror(err); + +	return error_failed(conn, msg, desc); +} + +static inline DBusMessage *no_such_adapter(DBusMessage *msg) +{ +	return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchAdapter", +							"No such adapter"); +} + +static inline DBusMessage *in_progress(DBusMessage *msg, const char *str) +{ +	return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", str); +} +  static void device_free(gpointer user_data)  {  	struct btd_device *device = user_data; @@ -254,13 +306,6 @@ static DBusMessage *get_properties(DBusConnection *conn,  	ptr = adapter_get_path(adapter);  	dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr); -	if (read_remote_eir(&src, &device->bdaddr, NULL) < 0) -		boolean = TRUE; -	else -		boolean = FALSE; - -	dict_append_entry(&dict, "LegacyPairing", DBUS_TYPE_BOOLEAN, &boolean); -  	dbus_message_iter_close_container(&iter, &dict);  	return reply; @@ -523,7 +568,7 @@ gboolean device_get_connected(struct btd_device *device)  	return device->connected;  } -void device_set_connected(DBusConnection *conn, struct btd_device *device, +void device_set_connected(struct btd_device *device, DBusConnection *conn,  			gboolean connected)  {  	device->connected = connected; @@ -579,7 +624,61 @@ struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapt  	return device;  } -void device_remove(DBusConnection *conn, struct btd_device *device) +static void device_remove_bonding(struct btd_device *device, DBusConnection *conn) +{ +	struct active_conn_info *ci; +	char filename[PATH_MAX + 1]; +	char *str, srcaddr[18], dstaddr[18]; +	int dd, dev_id; +	bdaddr_t bdaddr; +	gboolean paired; + +	adapter_get_address(device->adapter, &bdaddr); +	ba2str(&bdaddr, srcaddr); +	ba2str(&device->bdaddr, dstaddr); + +	dev_id = adapter_get_dev_id(device->adapter); + +	dd = hci_open_dev(dev_id); +	if (dd < 0) +		return; + +	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, +			"linkkeys"); + +	/* textfile_del doesn't return an error when the key is not found */ +	str = textfile_caseget(filename, dstaddr); +	paired = str ? TRUE : FALSE; +	g_free(str); + +	if (!paired) +		return; + +	/* Delete the link key from storage */ +	textfile_casedel(filename, dstaddr); + +	/* Delete the link key from the Bluetooth chip */ +	hci_delete_stored_link_key(dd, &device->bdaddr, 0, HCI_REQ_TIMEOUT); + +	/* Send the HCI disconnect command */ +	ci = adapter_search_active_conn_by_bdaddr(device->adapter, +						&device->bdaddr); +	if (ci) { +		int err = hci_disconnect(dd, htobs(ci->handle), +					HCI_OE_USER_ENDED_CONNECTION, +					HCI_REQ_TIMEOUT); +		if (err < 0) +			error("Disconnect: %s (%d)", strerror(-err), -err); +	} + +	hci_close_dev(dd); + +	paired = FALSE; +	emit_property_changed(conn, device->path, DEVICE_INTERFACE, +				"Paired", DBUS_TYPE_BOOLEAN, &paired); +} + +void device_remove(struct btd_device *device, DBusConnection *conn)  {  	GSList *list;  	struct btd_device_driver *driver; @@ -587,6 +686,12 @@ void device_remove(DBusConnection *conn, struct btd_device *device)  	debug("Removing device %s", path); +	if (device->bonding) +		device_cancel_bonding(device, HCI_OE_USER_ENDED_CONNECTION); + +	if (!device->temporary) +		device_remove_bonding(device, conn); +  	for (list = device->drivers; list; list = list->next) {  		struct btd_driver_data *driver_data = list->data;  		driver = driver_data->driver; @@ -1280,15 +1385,356 @@ static gboolean start_discovery(gpointer user_data)  	return FALSE;  } -int device_set_paired(DBusConnection *conn, struct btd_device *device, -			struct bonding_request_info *bonding) +DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)  { -	dbus_bool_t paired = TRUE; +	switch (status) { +	case 0x00: /* success */ +		return dbus_message_new_method_return(msg); + +	case 0x04: /* page timeout */ +	case 0x08: /* connection timeout */ +	case 0x10: /* connection accept timeout */ +	case 0x22: /* LMP response timeout */ +	case 0x28: /* instant passed - is this a timeout? */ +		return dbus_message_new_error(msg, +					ERROR_INTERFACE ".AuthenticationTimeout", +					"Authentication Timeout"); +	case 0x17: /* too frequent pairing attempts */ +		return dbus_message_new_error(msg, +					ERROR_INTERFACE ".RepeatedAttempts", +					"Repeated Attempts"); + +	case 0x06: +	case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */ +		return dbus_message_new_error(msg, +					ERROR_INTERFACE ".AuthenticationRejected", +					"Authentication Rejected"); + +	case 0x07: /* memory capacity */ +	case 0x09: /* connection limit */ +	case 0x0a: /* synchronous connection limit */ +	case 0x0d: /* limited resources */ +	case 0x13: /* user ended the connection */ +	case 0x14: /* terminated due to low resources */ +		return dbus_message_new_error(msg, +					ERROR_INTERFACE ".AuthenticationCanceled", +					"Authentication Canceled"); + +	case 0x05: /* authentication failure */ +	case 0x0E: /* rejected due to security reasons - is this auth failure? */ +	case 0x25: /* encryption mode not acceptable - is this auth failure? */ +	case 0x26: /* link key cannot be changed - is this auth failure? */ +	case 0x29: /* pairing with unit key unsupported - is this auth failure? */ +	case 0x2f: /* insufficient security - is this auth failure? */ +	default: +		return dbus_message_new_error(msg, +					ERROR_INTERFACE ".AuthenticationFailed", +					"Authentication Failed"); +	} +} + +static void bonding_request_free(struct bonding_req *bonding) +{ +	struct btd_device *device; + +	if (!bonding) +		return; + +	if (bonding->listener_id) +		g_dbus_remove_watch(bonding->conn, bonding->listener_id); -	device_set_temporary(device, FALSE); +	if (bonding->msg) +		dbus_message_unref(bonding->msg); + +	if (bonding->conn) +		dbus_connection_unref(bonding->conn); + +	if (bonding->io_id) +		g_source_remove(bonding->io_id); + +	if (bonding->io) +		g_io_channel_unref(bonding->io); + +	device = bonding->device; + +	if (device && device->agent) { +		agent_destroy(device->agent, FALSE); +		device->agent = NULL; +	} + +	device->bonding = NULL; +	g_free(bonding); +} + +static void device_set_paired(struct btd_device *device, gboolean value) +{ +	DBusConnection *conn = get_dbus_connection();  	emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired", -				DBUS_TYPE_BOOLEAN, &paired); +				DBUS_TYPE_BOOLEAN, &value); +} + +static void device_agent_removed(struct agent *agent, void *user_data) +{ +	struct btd_device *device = user_data; + +	device_set_agent(device, NULL); + +	if (device->authr) +		device->authr->agent = NULL; +} + +static struct bonding_req *bonding_request_new(DBusConnection *conn, +						DBusMessage *msg, +						struct btd_device *device, +						const char *agent_path, +						uint8_t capability) +{ +	struct bonding_req *bonding; +	const char *name = dbus_message_get_sender(msg); +	struct agent *agent; + +	debug("%s: requesting bonding", device->path); + +	if (!agent_path) +		goto proceed; + +	agent = agent_create(device->adapter, name, agent_path, +					capability, +					device_agent_removed, +					device); +	if (!agent) { +		error("Unable to create a new agent"); +		return NULL; +	} + +	device->agent = agent; + +	debug("Temporary agent registered for %s at %s:%s", +			device->path, name, agent_path); + +proceed: + +	bonding = g_new0(struct bonding_req, 1); + +	bonding->conn = dbus_connection_ref(conn); +	bonding->msg = dbus_message_ref(msg); + +	return bonding; +} + +static gboolean create_bonding_io_cb(GIOChannel *io, GIOCondition cond, +					struct btd_device *device) +{ +	struct hci_request rq; +	auth_requested_cp cp; +	evt_cmd_status rp; +	struct l2cap_conninfo cinfo; +	socklen_t len; +	int sk, dd, ret; + +	if (!device->bonding) { +		/* If we come here it implies a bug somewhere */ +		debug("create_bonding_io_cb: no pending bonding!"); +		g_io_channel_close(io); +		return FALSE; +	} + +	if (cond & G_IO_NVAL) { +		if (device->bonding) { +			DBusMessage *reply; + +			reply = new_authentication_return(device->bonding->msg, +							0x09); +			g_dbus_send_message(device->bonding->conn, reply); +		} + +		goto cleanup; +	} + +	if (cond & (G_IO_HUP | G_IO_ERR)) { +		debug("Hangup or error on bonding IO channel"); + +		if (device->bonding) +			error_connection_attempt_failed(device->bonding->conn, +							device->bonding->msg, +							ENETDOWN); + +		goto failed; +	} + +	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_errno(device->bonding->conn, device->bonding->msg, +				errno); +		goto failed; +	} + +	if (ret != 0) { +		if (device->bonding) +			error_connection_attempt_failed(device->bonding->conn, +							device->bonding->msg, +							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_errno(device->bonding->conn, device->bonding->msg, +				errno); +		goto failed; +	} + +	dd = hci_open_dev(adapter_get_dev_id(device->adapter)); +	if (dd < 0) { +		DBusMessage *reply = no_such_adapter(device->bonding->msg); +		g_dbus_send_message(device->bonding->conn, reply); +		goto failed; +	} + +	memset(&rp, 0, sizeof(rp)); + +	memset(&cp, 0, sizeof(cp)); +	cp.handle = htobs(cinfo.hci_handle); + +	memset(&rq, 0, sizeof(rq)); +	rq.ogf    = OGF_LINK_CTL; +	rq.ocf    = OCF_AUTH_REQUESTED; +	rq.cparam = &cp; +	rq.clen   = AUTH_REQUESTED_CP_SIZE; +	rq.rparam = &rp; +	rq.rlen   = EVT_CMD_STATUS_SIZE; +	rq.event  = EVT_CMD_STATUS; + +	if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) { +		error("Unable to send HCI request: %s (%d)", +					strerror(errno), errno); +		error_failed_errno(device->bonding->conn, device->bonding->msg, +				errno); +		hci_close_dev(dd); +		goto failed; +	} + +	if (rp.status) { +		error("HCI_Authentication_Requested failed with status 0x%02x", +				rp.status); +		error_failed_errno(device->bonding->conn, device->bonding->msg, +				bt_error(rp.status)); +		hci_close_dev(dd); +		goto failed; +	} + +	hci_close_dev(dd); + +	device->bonding->io_id = g_io_add_watch(io, +						G_IO_NVAL | G_IO_HUP | G_IO_ERR, +						(GIOFunc) create_bonding_io_cb, +						device); + +	return FALSE; + +failed: +	g_io_channel_close(io); + +cleanup: +	device->bonding->io_id = 0; +	bonding_request_free(device->bonding); + +	return FALSE; +} + +static void create_bond_req_exit(DBusConnection *conn, void *user_data) +{ +	struct btd_device *device = user_data; + +	debug("%s: requestor exited before bonding was completed", device->path); + +	if (device->authr) +		device_cancel_authentication(device); + +	if (device->bonding) { +		device->bonding->listener_id = 0; +		g_io_channel_close(device->bonding->io); +		bonding_request_free(device->bonding); +	} +} + +DBusMessage *device_create_bonding(struct btd_device *device, +					DBusConnection *conn, +					DBusMessage *msg, +					const char *agent_path, +					uint8_t capability) +{ +	char filename[PATH_MAX + 1]; +	char *str, srcaddr[18], dstaddr[18]; +	struct btd_adapter *adapter = device->adapter; +	struct bonding_req *bonding; +	bdaddr_t src; +	int sk; + +	adapter_get_address(adapter, &src); +	ba2str(&src, srcaddr); +	ba2str(&device->bdaddr, dstaddr); + +	if (device->bonding) +		return in_progress(msg, "Bonding in progress"); + +	/* check if a link key already exists */ +	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, +			"linkkeys"); + +	str = textfile_caseget(filename, dstaddr); +	if (str) { +		free(str); +		return g_dbus_create_error(msg, +				ERROR_INTERFACE ".AlreadyExists", +				"Bonding already exists"); +	} + +	sk = l2raw_connect(&src, &device->bdaddr); +	if (sk < 0) +		return g_dbus_create_error(msg, +				ERROR_INTERFACE ".ConnectionAttemptFailed", +				"Connection attempt failed"); + +	bonding = bonding_request_new(conn, msg, device, agent_path, +					capability); +	if (!bonding) { +		close(sk); +		return NULL; +	} + +	bonding->io = g_io_channel_unix_new(sk); +	bonding->io_id = g_io_add_watch(bonding->io, +					G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR, +					(GIOFunc) create_bonding_io_cb, +					device); + +	bonding->listener_id = g_dbus_add_disconnect_watch(conn, +						dbus_message_get_sender(msg), +						create_bond_req_exit, device, +						NULL); + +	device->bonding = bonding; +	bonding->device = device; + +	return NULL; +} + +void device_bonding_complete(struct btd_device *device, uint8_t status) +{ +	struct bonding_req *bonding = device->bonding; + +	if (status) +		goto failed; + +	device->temporary = FALSE;  	/* If we were initiators start service discovery immediately.  	 * However if the other end was the initator wait a few seconds @@ -1302,18 +1748,218 @@ int device_set_paired(DBusConnection *conn, struct btd_device *device,  			device->discov_timer = 0;  		} -		return device_browse(device, bonding->conn, bonding->msg, -					NULL, FALSE); +		device_browse(device, bonding->conn, bonding->msg, +				NULL, FALSE); +	} else if (!device->discov_active && !device->discov_timer) { +		/* If we are not initiators and there is no currently active +		 * discovery or discovery timer, set the discovery timer */ +		device->discov_timer = g_timeout_add_seconds(DISCOVERY_TIMER, +						start_discovery, +						device);  	} -	/* If we are not initiators and there is no currently active discovery -	 * or discovery timer, set the discovery timer */ -	if (!device->discov_active && !device->discov_timer) -		device->discov_timer = g_timeout_add_seconds(DISCOVERY_TIMER, -							start_discovery, -							device); +	device_set_paired(device, TRUE); -	return 0; +	g_free(device->authr); +	device->authr = NULL; +	bonding_request_free(bonding); + +	return; + +failed: + +	device_cancel_bonding(device, status); +} + +gboolean device_is_bonding(struct btd_device *device, const char *sender) +{ +	struct bonding_req *bonding = device->bonding; + +	if (!device->bonding) +		return FALSE; + +	if (!sender) +		return TRUE; + +	return g_str_equal(sender, dbus_message_get_sender(bonding->msg)); +} + +void device_cancel_bonding(struct btd_device *device, uint8_t status) +{ +	struct bonding_req *bonding = device->bonding; +	DBusMessage *reply; + +	if (!bonding) +		return; + +	debug("%s: canceling bonding request", device->path); + +	if (device->authr) +		device_cancel_authentication(device); + +	reply = new_authentication_return(bonding->msg, status); +	g_dbus_send_message(bonding->conn, reply); + +	if (device->bonding->io_id) +		g_source_remove(device->bonding->io_id); + +	bonding_request_free(bonding); +} + +static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode, +			void *data) +{ +	struct authentication_req *auth = data; +	struct btd_device *device = auth->device; + +	/* No need to reply anything if the authentication already failed */ +	if (!auth->cb) +		return; + +	((agent_pincode_cb) auth->cb)(agent, err, pincode, device); + +	auth->cb = NULL; +} + +static void confirm_cb(struct agent *agent, DBusError *err, void *data) +{ +	struct authentication_req *auth = data; +	struct btd_device *device = auth->device; + +	/* No need to reply anything if the authentication already failed */ +	if (!auth->cb) +		return; + +	((agent_cb) auth->cb)(agent, err, device); + +	auth->cb = NULL; +} + +static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey, +			void *data) +{ +	struct authentication_req *auth = data; +	struct btd_device *device = auth->device; + +	/* No need to reply anything if the authentication already failed */ +	if (!auth->cb) +		return; + +	((agent_passkey_cb) auth->cb)(agent, err, passkey, device); + +	auth->cb = NULL; +} + +int device_request_authentication(struct btd_device *device, auth_type_t type, +				uint32_t passkey, void *cb) +{ +	struct authentication_req *auth; +	struct agent *agent; +	int ret; + +	debug("%s: requesting agent authentication", device->path); + +	agent = device->agent; + +	if (!agent) +		agent = adapter_get_agent(device->adapter); + +	if (!agent) { +		error("No agent available for %u request", type); +		return -EPERM; +	} + +	auth = g_new0(struct authentication_req, 1); +	auth->agent = agent; +	auth->device = device; +	auth->cb = cb; +	auth->type = type; +	device->authr = auth; + +	switch (type) { +	case AUTH_TYPE_PINCODE: +		ret = agent_request_pincode(agent, device, pincode_cb, +					auth); +		break; +	case AUTH_TYPE_PASSKEY: +		ret = agent_request_passkey(agent, device, passkey_cb, +					auth); +		break; +	case AUTH_TYPE_CONFIRM: +		ret = agent_request_confirmation(agent, device, passkey, +					confirm_cb, auth); +		break; +	case AUTH_TYPE_NOTIFY: +		ret = agent_display_passkey(agent, device, passkey); +		break; +	case AUTH_TYPE_AUTO: +		ret = 0; +		break; +	default: +		ret = -EINVAL; +	} + +	if (ret < 0) { +		error("Failed requesting authentication"); +		g_free(auth); +		device->authr = NULL; +	} + +	return ret; +} + +static void cancel_authentication(struct authentication_req *auth) +{ +	struct btd_device *device = auth->device; +	struct agent *agent = auth->agent; +	DBusError err; + +	if (!auth->cb) +		return; + +	dbus_error_init(&err); +	dbus_set_error_const(&err, "org.bluez.Error.Canceled", NULL); + +	switch (auth->type) { +	case AUTH_TYPE_PINCODE: +		((agent_pincode_cb) auth->cb)(agent, &err, NULL, device); +		break; +	case AUTH_TYPE_CONFIRM: +		((agent_cb) auth->cb)(agent, &err, device); +		break; +	case AUTH_TYPE_PASSKEY: +		((agent_passkey_cb) auth->cb)(agent, &err, 0, device); +		break; +	case AUTH_TYPE_NOTIFY: +	case AUTH_TYPE_AUTO: +		/* User Notify/Auto doesn't require any reply */ +		break; +	} + +	dbus_error_free(&err); +	auth->cb = NULL; +} + +void device_cancel_authentication(struct btd_device *device) +{ +	struct authentication_req *auth = device->authr; + +	if (!auth) +		return; + +	debug("%s: canceling authentication request", device->path); + +	if (auth->agent) +		agent_cancel(auth->agent); + +	cancel_authentication(auth); +	device->authr = NULL; +	g_free(auth); +} + +gboolean device_is_authenticating(struct btd_device *device) +{ +	return (device->authr != NULL);  }  void btd_device_add_uuid(struct btd_device *device, const char *uuid) diff --git a/src/device.h b/src/device.h index 4113ecdb..c9137f7c 100644 --- a/src/device.h +++ b/src/device.h @@ -24,9 +24,19 @@  #define DEVICE_INTERFACE	"org.bluez.Device" +struct btd_device; + +typedef enum { +	AUTH_TYPE_PINCODE, +	AUTH_TYPE_PASSKEY, +	AUTH_TYPE_CONFIRM, +	AUTH_TYPE_NOTIFY, +	AUTH_TYPE_AUTO, +} auth_type_t; +  struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter,  				const gchar *address); -void device_remove(DBusConnection *conn, struct btd_device *device); +void device_remove(struct btd_device *device, DBusConnection *conn);  gint device_address_cmp(struct btd_device *device, const gchar *address);  int device_browse(struct btd_device *device, DBusConnection *conn,  			DBusMessage *msg, uuid_t *search, gboolean reverse); @@ -45,12 +55,21 @@ void device_set_temporary(struct btd_device *device, gboolean temporary);  void device_set_cap(struct btd_device *device, uint8_t cap);  void device_set_auth(struct btd_device *device, uint8_t auth);  uint8_t device_get_auth(struct btd_device *device); -int device_set_paired(DBusConnection *conn, struct btd_device *device, -			struct bonding_request_info *bonding);  gboolean device_get_connected(struct btd_device *device); -void device_set_connected(DBusConnection *conn, struct btd_device *device, +void device_set_connected(struct btd_device *device, DBusConnection *conn,  				gboolean connected);  void device_set_secmode3_conn(struct btd_device *device, gboolean enable); +DBusMessage *device_create_bonding(struct btd_device *device, +				DBusConnection *conn, DBusMessage *msg, +				const char *agent_path, uint8_t capability); +void device_remove_bondind(struct btd_device *device, DBusConnection *connection); +void device_bonding_complete(struct btd_device *device, uint8_t status); +gboolean device_is_bonding(struct btd_device *device, const char *sender); +void device_cancel_bonding(struct btd_device *device, uint8_t status); +int device_request_authentication(struct btd_device *device, auth_type_t type, +				uint32_t passkey, void *cb); +void device_cancel_authentication(struct btd_device *device); +gboolean device_is_authenticating(struct btd_device *device);  #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } ) | 
