diff options
| -rw-r--r-- | hcid/dbus-security.c | 113 | ||||
| -rw-r--r-- | hcid/dbus.c | 23 | ||||
| -rw-r--r-- | hcid/dbus.h | 24 | ||||
| -rw-r--r-- | hcid/hcid.h | 2 | 
4 files changed, 127 insertions, 35 deletions
| diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index 3ad09f2e..c6609d81 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -41,12 +41,6 @@  #define TIMEOUT (30 * 1000)		/* 30 seconds */ -struct pin_request { -	int dev; -	bdaddr_t sba; -	bdaddr_t bda; -}; -  static struct passkey_agent *default_agent = NULL;  static void default_agent_exited(const char *name, void *data) @@ -342,7 +336,7 @@ static struct service_data sec_services[] = {  static void passkey_agent_reply(DBusPendingCall *call, void *user_data)  { -	struct pin_request *req = (struct pin_request *) user_data; +	struct pending_agent_request *req = user_data;  	pin_code_reply_cp pr;  	DBusMessage *message;  	DBusError err; @@ -394,15 +388,22 @@ done:  	if (message)  		dbus_message_unref(message); -	dbus_pending_call_unref(call); +	req->agent->pending_requests = slist_remove(req->agent->pending_requests, req); + +	dbus_pending_call_cancel(req->call); +	dbus_pending_call_unref(req->call); +	dbus_connection_unref(req->conn); +	free(req->path); +	free(req);  } -static int call_passkey_agent(DBusConnection *conn, struct passkey_agent *agent, -		int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba) +static int call_passkey_agent(DBusConnection *conn, +				struct passkey_agent *agent, int dev, +				const char *path, bdaddr_t *sba, +				bdaddr_t *dba)  {  	DBusMessage *message = NULL; -	DBusPendingCall *pending = NULL; -	struct pin_request *req; +	struct pending_agent_request *req = NULL;  	char bda[18];  	char *ptr = bda; @@ -423,12 +424,18 @@ static int call_passkey_agent(DBusConnection *conn, struct passkey_agent *agent,  		goto failed;  	} -	req = malloc(sizeof(*req)); +	req = malloc(sizeof(struct pending_agent_request));  	if (!req)  		goto failed; +	memset(req, 0, sizeof(struct pending_agent_request));  	req->dev = dev;  	bacpy(&req->sba, sba);  	bacpy(&req->bda, dba); +	req->agent = agent; +	req->conn = dbus_connection_ref(conn); +	req->path = strdup(path); +	if (!req->path) +		goto failed;  	dbus_message_append_args(message,  					DBUS_TYPE_STRING, &path, @@ -436,12 +443,14 @@ static int call_passkey_agent(DBusConnection *conn, struct passkey_agent *agent,  					DBUS_TYPE_INVALID);  	if (dbus_connection_send_with_reply(conn, message, -				&pending, TIMEOUT) == FALSE) { +				&req->call, TIMEOUT) == FALSE) {  		error("D-Bus send failed");  		goto failed;  	} -	dbus_pending_call_set_notify(pending, passkey_agent_reply, req, free); +	dbus_pending_call_set_notify(req->call, passkey_agent_reply, req, NULL); + +	agent->pending_requests = slist_append(agent->pending_requests, req);  	dbus_message_unref(message); @@ -451,6 +460,12 @@ failed:  	if (message)  		dbus_message_unref(message); +	if (req) { +		dbus_connection_unref(req->conn); +		free(req->path); +		free(req); +	} +  	hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);  	return -1; @@ -468,7 +483,8 @@ DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg,  	return error_unknown_method(conn, msg);  } -int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba) +int handle_passkey_request(DBusConnection *conn, int dev, const char *path, +					bdaddr_t *sba, bdaddr_t *dba)  {  	struct passkey_agent *agent = default_agent;  	struct hci_dbus_data *adapter = NULL; @@ -496,3 +512,68 @@ int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdad  done:  	return call_passkey_agent(conn, agent, dev, path, sba, dba);  } + +static void send_cancel_request(struct passkey_agent *agent, struct pending_agent_request *req) +{ +	DBusMessage *message; +	char address[18], *ptr = address; + +	message = dbus_message_new_method_call(agent->name, agent->path, +			"org.bluez.PasskeyAgent", "Cancel"); +	if (message == NULL) { +		error("Couldn't allocate D-Bus message"); +		return; +	} + +	ba2str(&req->bda, address); + +	dbus_message_append_args(message, +			DBUS_TYPE_STRING, &req->path, +			DBUS_TYPE_STRING, &ptr, +			DBUS_TYPE_INVALID); + +	dbus_message_set_no_reply(message, TRUE); + +	send_reply_and_unref(req->conn, message); + +	dbus_pending_call_cancel(req->call); +	dbus_pending_call_unref(req->call); +	dbus_connection_unref(req->conn); +	free(req->path); +	free(req); + +	debug("PasskeyAgent.Request(%s, %s) was canceled", req->path, address); +} + +void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdaddr_t *addr) +{ +	struct slist *l, *next; + +	if (!default_agent) +		return; + +	/* First check the default agent */ +	for (l = default_agent->pending_requests; l != NULL; l = next) { +		struct pending_agent_request *req = l->data; +		next = l->next; +		if (!strcmp(path, req->path) && !bacmp(addr, &req->bda)) { +			send_cancel_request(default_agent, req); +			default_agent->pending_requests = slist_remove(default_agent->pending_requests, +									req); +		} +	} + +	/* and then the adapter specific agents */ +	for (;agents != NULL; agents = agents->next) { +		struct passkey_agent *agent = agents->data; +		for (l = agent->pending_requests; l != NULL; l = next) { +			struct pending_agent_request *req = l->data; +			next = l->next; +			if (!strcmp(path, req->path) && !bacmp(addr, &req->bda)) { +				send_cancel_request(default_agent, req); +				agent->pending_requests = slist_remove(agent->pending_requests, req); +			} +		} +	} + +} diff --git a/hcid/dbus.c b/hcid/dbus.c index 5288290a..365af30e 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -672,12 +672,7 @@ int hcid_dbus_stop_device(uint16_t id)  static int pending_bonding_cmp(const void *p1, const void *p2)  { -	const bdaddr_t *peer1 = p1; -	const bdaddr_t *peer2 = p2; - -	if (peer2) -		return bacmp(peer1, peer2); -	return -1; +	return p2 ? bacmp(p1, p2) : -1;  }  void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba) @@ -700,7 +695,7 @@ void hcid_dbus_pending_bonding_add(bdaddr_t *sba, bdaddr_t *dba)  	pdata->pending_bondings = slist_append(pdata->pending_bondings, peer);  } -void hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) +int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)  {  	char path[MAX_PATH_LENGTH], addr[18]; @@ -708,7 +703,7 @@ void hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)  	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, hci_devid(addr)); -	handle_passkey_request(connection, dev, path, sba, &ci->bdaddr); +	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) @@ -752,11 +747,13 @@ void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, const u  	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);  	if (l) { -		bdaddr_t *p = l->data; -		pdata->pending_bondings = slist_remove(pdata->pending_bondings, p); -		free(p); +		pdata->pending_bondings = slist_remove(pdata->pending_bondings, l->data); +		free(l->data);  		if (!status) {  			const char *name = "BondingCreated"; @@ -1380,7 +1377,7 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle  	/* clean pending HCI cmds */  	hci_req_queue_remove(pdata->dev_id, &dev->bdaddr); -	/* Check if there is a pending Bonding */ +	/* 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", @@ -1400,6 +1397,8 @@ void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle  		pdata->requestor_name = NULL;  	} +	cancel_passkey_agent_requests(pdata->passkey_agents, path, &dev->bdaddr); +  	/* Sent the remote device disconnected signal */  	message = dev_signal_factory(pdata->dev_id, "RemoteDeviceDisconnected",  					DBUS_TYPE_STRING, &peer_addr, diff --git a/hcid/dbus.h b/hcid/dbus.h index c8ac1d3f..4671c482 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -95,6 +95,23 @@ struct active_conn_info {  	uint16_t handle;  }; +struct passkey_agent { +	char *addr; +	char *name; +	char *path; +	struct slist *pending_requests; +}; + +struct pending_agent_request { +	struct passkey_agent *agent; +	int dev; +	bdaddr_t sba; +	bdaddr_t bda; +	char *path; +	DBusConnection *conn; +	DBusPendingCall *call; +}; +  struct hci_dbus_data {  	uint16_t dev_id;  	int up; @@ -112,12 +129,6 @@ struct hci_dbus_data {  	struct slist *pending_bondings;  }; -struct passkey_agent { -	char *addr; -	char *name; -	char *path; -}; -  typedef int register_function_t(DBusConnection *conn, uint16_t id);  typedef int unregister_function_t(DBusConnection *conn, uint16_t id); @@ -181,6 +192,7 @@ DBusHandlerResult simple_introspect(DBusConnection *conn, DBusMessage *msg, void  service_handler_func_t find_service_handler(struct service_data *services, DBusMessage *msg);  int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba); +void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdaddr_t *dba);  static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusMessage *reply)  { diff --git a/hcid/hcid.h b/hcid/hcid.h index 76c80906..c7208222 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -149,7 +149,7 @@ 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_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci); +int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci);  void hcid_dbus_inquiry_start(bdaddr_t *local);  void hcid_dbus_inquiry_complete(bdaddr_t *local); | 
