diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-20 19:05:10 +0000 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-20 19:05:10 +0000 | 
| commit | be52c05a25c0cbadcd605b24d66d0c0b682aee18 (patch) | |
| tree | 89abaf343d91156a88500480e75e9cdc3247198e /hcid/dbus-security.c | |
| parent | afa617e410dad21b496539c2c7e89124294f33ae (diff) | |
First round of Passkey Release method support
Diffstat (limited to 'hcid/dbus-security.c')
| -rw-r--r-- | hcid/dbus-security.c | 127 | 
1 files changed, 102 insertions, 25 deletions
| diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index 1495e44a..91a03e5d 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -43,6 +43,8 @@  static struct passkey_agent *default_agent = NULL; +static void release_agent(struct passkey_agent *agent); +  static void passkey_agent_free(struct passkey_agent *agent)  {  	struct slist *l; @@ -50,13 +52,6 @@ static void passkey_agent_free(struct passkey_agent *agent)  	if (!agent)  		return; -	if (agent->name) -		free(agent->name); -	if (agent->path) -		free(agent->path); -	if (agent->addr) -		free(agent->addr); -  	for (l = agent->pending_requests; l != NULL; l = l->next) {  		struct pending_agent_request *req = l->data; @@ -66,10 +61,21 @@ static void passkey_agent_free(struct passkey_agent *agent)  		free(req->path);  		dbus_pending_call_cancel(req->call);  		dbus_pending_call_unref(req->call); -		dbus_connection_unref(req->conn);  		free(req);  	} +	if (!agent->exited) +		release_agent(agent); + +	if (agent->name) +		free(agent->name); +	if (agent->path) +		free(agent->path); +	if (agent->addr) +		free(agent->addr); +	if (agent->conn) +		dbus_connection_unref(agent->conn); +  	slist_free(agent->pending_requests);  	free(agent); @@ -85,12 +91,15 @@ static void default_agent_exited(const char *name, void *data)  		return;  	} +	default_agent->exited = 1; +  	passkey_agent_free(default_agent);  	default_agent = NULL;  } -static struct passkey_agent *passkey_agent_new(const char *name, -					const char *path, const char *addr) +static struct passkey_agent *passkey_agent_new(struct hci_dbus_data *pdata, DBusConnection *conn, +						const char *name, const char *path, +						const char *addr)  {  	struct passkey_agent *agent; @@ -100,6 +109,8 @@ static struct passkey_agent *passkey_agent_new(const char *name,  	memset(agent, 0, sizeof(struct passkey_agent)); +	agent->pdata = pdata; +  	agent->name = strdup(name);  	if (!agent->name)  		goto mem_fail; @@ -114,9 +125,13 @@ static struct passkey_agent *passkey_agent_new(const char *name,  			goto mem_fail;  	} +	agent->conn = dbus_connection_ref(conn); +  	return agent;  mem_fail: +	/* So passkey_agent_free doesn't try to call Relese */ +	agent->exited = 1;  	passkey_agent_free(agent);  	return NULL;  } @@ -166,6 +181,8 @@ static void agent_exited(const char *name, struct hci_dbus_data *adapter)  		if (strcmp(agent->name, name))  			continue; +		agent->exited = 1; +  		adapter->passkey_agents = slist_remove(adapter->passkey_agents, agent);  		passkey_agent_free(agent);  	} @@ -199,12 +216,13 @@ static DBusHandlerResult register_agent(DBusConnection *conn,  	if (slist_find(adapter->passkey_agents, &ref, (cmp_func_t)agent_cmp))  		return error_passkey_agent_already_exists(conn, msg); -	agent = passkey_agent_new(ref.name, path, addr); +	agent = passkey_agent_new(adapter, conn, ref.name, path, addr);  	if (!agent)  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	reply = dbus_message_new_method_return(msg);  	if (!reply) { +		agent->exited = 1;  		passkey_agent_free(agent);  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	} @@ -252,6 +270,8 @@ static DBusHandlerResult unregister_agent(DBusConnection *conn,  	agent = match->data; +	agent->exited = 1; +  	adapter->passkey_agents = slist_remove(adapter->passkey_agents, agent);  	passkey_agent_free(agent); @@ -282,7 +302,7 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn,  				DBUS_TYPE_INVALID))  		return error_invalid_arguments(conn, msg); -	default_agent = passkey_agent_new(dbus_message_get_sender(msg), path, NULL); +	default_agent = passkey_agent_new(NULL, conn, dbus_message_get_sender(msg), path, NULL);  	if (!default_agent)  		goto need_memory; @@ -354,6 +374,7 @@ static struct service_data sec_services[] = {  static void passkey_agent_reply(DBusPendingCall *call, void *user_data)  {  	struct pending_agent_request *req = user_data; +	struct passkey_agent *agent = req->agent;  	pin_code_reply_cp pr;  	DBusMessage *message;  	DBusError err; @@ -407,13 +428,17 @@ done:  	if (message)  		dbus_message_unref(message); -	req->agent->pending_requests = slist_remove(req->agent->pending_requests, req); - +	agent->pending_requests = slist_remove(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); + +	if (agent != default_agent) { +		agent->pdata->passkey_agents = slist_remove(agent->pdata->passkey_agents, +								agent); +		passkey_agent_free(agent); +	}  }  static int call_passkey_agent(DBusConnection *conn, @@ -451,7 +476,6 @@ static int call_passkey_agent(DBusConnection *conn,  	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; @@ -480,7 +504,6 @@ failed:  		dbus_message_unref(message);  	if (req) { -		dbus_connection_unref(req->conn);  		free(req->path);  		free(req);  	} @@ -522,6 +545,8 @@ int handle_passkey_request(DBusConnection *conn, int dev, const char *path,  	for (l = adapter->passkey_agents; l != NULL; l = l->next) {  		struct passkey_agent *a = l->data; +		if (a != default_agent && slist_length(a->pending_requests) >= 1) +			continue;  		if (!strcmp(a->addr, addr)) {  			agent = a;  			break; @@ -532,12 +557,12 @@ 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) +static void send_cancel_request(struct pending_agent_request *req)  {  	DBusMessage *message;  	char address[18], *ptr = address; -	message = dbus_message_new_method_call(agent->name, agent->path, +	message = dbus_message_new_method_call(req->agent->name, req->agent->path,  			"org.bluez.PasskeyAgent", "Cancel");  	if (message == NULL) {  		error("Couldn't allocate D-Bus message"); @@ -553,18 +578,69 @@ static void send_cancel_request(struct passkey_agent *agent, struct pending_agen  	dbus_message_set_no_reply(message, TRUE); -	send_reply_and_unref(req->conn, message); +	send_reply_and_unref(req->agent->conn, message);  	debug("PasskeyAgent.Request(%s, %s) was canceled", req->path, address);  	dbus_pending_call_cancel(req->call);  	dbus_pending_call_unref(req->call); -	dbus_connection_unref(req->conn);  	free(req->path);  	free(req);  } -void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdaddr_t *addr) +static void release_agent(struct passkey_agent *agent) +{ +	DBusMessage *message; + +	debug("Releasing agent %s, %s", agent->name, agent->path); + +	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; +	} + +	dbus_message_set_no_reply(message, TRUE); + +	send_reply_and_unref(agent->conn, message); +} + +void release_default_agent(void) +{ +	if (!default_agent) +		return; + +	name_listener_remove(default_agent->conn, default_agent->name, +			(name_cb_t)default_agent_exited, NULL); + +	passkey_agent_free(default_agent); +	default_agent = NULL; +} + +void release_passkey_agents(struct hci_dbus_data *pdata, bdaddr_t *bda) +{ +	struct slist *l, *next; + +	for (l = pdata->passkey_agents; l != NULL; l = next) { +		struct passkey_agent *agent = l->data; +		next = l->next; +		 +		if (bda && agent->addr) { +			bdaddr_t tmp; +			str2ba(agent->addr, &tmp); +			if (bacmp(&tmp, bda)) +				continue; +		} + +		name_listener_remove(agent->conn, agent->name, (name_cb_t)agent_exited, pdata); +		passkey_agent_free(agent); +		pdata->passkey_agents = slist_remove(pdata->passkey_agents, agent); +	} +} + +void cancel_passkey_agent_requests(struct slist *agents, const char *path, +					bdaddr_t *addr)  {  	struct slist *l, *next; @@ -573,20 +649,21 @@ void cancel_passkey_agent_requests(struct slist *agents, const char *path, bdadd  		struct pending_agent_request *req = l->data;  		next = l->next;  		if (!strcmp(path, req->path) && (!addr || !bacmp(addr, &req->bda))) { -			send_cancel_request(default_agent, req); +			send_cancel_request(req);  			default_agent->pending_requests = slist_remove(default_agent->pending_requests,  									req);  		}  	}  	/* and then the adapter specific agents */ -	for (;agents != NULL; agents = agents->next) { +	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) && (!addr || !bacmp(addr, &req->bda))) { -				send_cancel_request(agent, req); +				send_cancel_request(req);  				agent->pending_requests = slist_remove(agent->pending_requests, req);  			}  		} | 
