linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ] agent: Detect when ongoing request is already in progress
@ 2019-12-27 18:42 Luiz Augusto von Dentz
  0 siblings, 0 replies; only message in thread
From: Luiz Augusto von Dentz @ 2019-12-27 18:42 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This detects when a agent request is already pending for the same device
which could happen when there are 2 or more adapters in the system and
they are trying to pair with each other.
---
 src/adapter.c |   5 +-
 src/agent.c   | 128 ++++++++++++++++++++++++++++++++------------------
 src/agent.h   |   2 +-
 src/device.c  |  12 +++++
 4 files changed, 97 insertions(+), 50 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index cef25616f..63cc5c576 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -6454,7 +6454,6 @@ static gboolean process_auth_queue(gpointer user_data)
 	while (!g_queue_is_empty(adapter->auths)) {
 		struct service_auth *auth = adapter->auths->head->data;
 		struct btd_device *device = auth->device;
-		const char *dev_path;
 
 		/* Wait services to be resolved before asking authorization */
 		if (auth->svc_id > 0)
@@ -6477,9 +6476,7 @@ static gboolean process_auth_queue(gpointer user_data)
 			goto next;
 		}
 
-		dev_path = device_get_path(device);
-
-		if (agent_authorize_service(auth->agent, dev_path, auth->uuid,
+		if (agent_authorize_service(auth->agent, device, auth->uuid,
 					agent_auth_cb, adapter, NULL) < 0) {
 			auth->cb(&err, auth->user_data);
 			goto next;
diff --git a/src/agent.c b/src/agent.c
index 183e2f190..e0ffcd22f 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -76,6 +76,7 @@ struct agent {
 
 struct agent_request {
 	agent_request_type_t type;
+	struct btd_device *device; /* Weak reference */
 	struct agent *agent;
 	DBusMessage *msg;
 	DBusPendingCall *call;
@@ -296,6 +297,7 @@ static struct agent *agent_create( const char *name, const char *path,
 }
 
 static struct agent_request *agent_request_new(struct agent *agent,
+						struct btd_device *device,
 						agent_request_type_t type,
 						void *cb,
 						void *user_data,
@@ -306,6 +308,7 @@ static struct agent_request *agent_request_new(struct agent *agent,
 	req = g_new0(struct agent_request, 1);
 
 	req->agent = agent;
+	req->device = device;
 	req->type = type;
 	req->cb = cb;
 	req->user_data = user_data;
@@ -381,10 +384,10 @@ done:
 }
 
 static int agent_call_authorize_service(struct agent_request *req,
-						const char *device_path,
 						const char *uuid)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
 					AGENT_INTERFACE, "AuthorizeService");
@@ -393,8 +396,10 @@ static int agent_call_authorize_service(struct agent_request *req,
 		return -ENOMEM;
 	}
 
+	path = device_get_path(req->device);
+
 	dbus_message_append_args(req->msg,
-				DBUS_TYPE_OBJECT_PATH, &device_path,
+				DBUS_TYPE_OBJECT_PATH, &path,
 				DBUS_TYPE_STRING, &uuid,
 				DBUS_TYPE_INVALID);
 
@@ -406,23 +411,50 @@ static int agent_call_authorize_service(struct agent_request *req,
 	}
 
 	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+	DBG("authorize service request was sent for %s", path);
+
 	return 0;
 }
 
-int agent_authorize_service(struct agent *agent, const char *path,
+static int agent_has_request(struct agent *agent, struct btd_device *device,
+						agent_request_type_t type)
+{
+	if (!agent->request)
+		return 0;
+
+	if (agent->request->type != type)
+		return -EBUSY;
+
+	/* Check if request pending is for the same address */
+	if (bacmp(device_get_address(agent->request->device),
+			btd_adapter_get_address(device_get_adapter(device))))
+		return -EBUSY;
+
+	/* It must match in either direction */
+	if (bacmp(device_get_address(device),
+			btd_adapter_get_address(
+			device_get_adapter(agent->request->device))))
+		return -EBUSY;
+
+	return -EINPROGRESS;
+}
+
+int agent_authorize_service(struct agent *agent, struct btd_device *device,
 				const char *uuid, agent_cb cb,
 				void *user_data, GDestroyNotify destroy)
 {
 	struct agent_request *req;
 	int err;
 
-	if (agent->request)
-		return -EBUSY;
+	err = agent_has_request(agent, device, AGENT_REQUEST_AUTHORIZE_SERVICE);
+	if (err)
+		return err;
 
-	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE_SERVICE, cb,
-							user_data, destroy);
+	req = agent_request_new(agent, device, AGENT_REQUEST_AUTHORIZE_SERVICE,
+						cb, user_data, destroy);
 
-	err = agent_call_authorize_service(req, path, uuid);
+	err = agent_call_authorize_service(req, uuid);
 	if (err < 0) {
 		agent_request_free(req, FALSE);
 		return -ENOMEM;
@@ -430,8 +462,6 @@ int agent_authorize_service(struct agent *agent, const char *path,
 
 	agent->request = req;
 
-	DBG("authorize service request was sent for %s", path);
-
 	return 0;
 }
 
@@ -494,10 +524,10 @@ done:
 	agent_unref(agent);
 }
 
-static int pincode_request_new(struct agent_request *req, const char *device_path,
-				dbus_bool_t secure)
+static int pincode_request_new(struct agent_request *req, dbus_bool_t secure)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	/* TODO: Add a new method or a new param to Agent interface to request
 		secure pin. */
@@ -509,7 +539,9 @@ static int pincode_request_new(struct agent_request *req, const char *device_pat
 		return -ENOMEM;
 	}
 
-	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
+	path = device_get_path(req->device);
+
+	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &path,
 					DBUS_TYPE_INVALID);
 
 	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
@@ -527,16 +559,15 @@ int agent_request_pincode(struct agent *agent, struct btd_device *device,
 				void *user_data, GDestroyNotify destroy)
 {
 	struct agent_request *req;
-	const char *dev_path = device_get_path(device);
 	int err;
 
 	if (agent->request)
 		return -EBUSY;
 
-	req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
+	req = agent_request_new(agent, device, AGENT_REQUEST_PINCODE, cb,
 							user_data, destroy);
 
-	err = pincode_request_new(req, dev_path, secure);
+	err = pincode_request_new(req, secure);
 	if (err < 0)
 		goto failed;
 
@@ -591,10 +622,10 @@ done:
 	agent_request_free(req, TRUE);
 }
 
-static int passkey_request_new(struct agent_request *req,
-				const char *device_path)
+static int passkey_request_new(struct agent_request *req)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
 					AGENT_INTERFACE, "RequestPasskey");
@@ -603,7 +634,9 @@ static int passkey_request_new(struct agent_request *req,
 		return -ENOMEM;
 	}
 
-	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
+	path = device_get_path(req->device);
+
+	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &path,
 					DBUS_TYPE_INVALID);
 
 	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
@@ -621,7 +654,6 @@ int agent_request_passkey(struct agent *agent, struct btd_device *device,
 				GDestroyNotify destroy)
 {
 	struct agent_request *req;
-	const char *dev_path = device_get_path(device);
 	int err;
 
 	if (agent->request)
@@ -630,10 +662,10 @@ int agent_request_passkey(struct agent *agent, struct btd_device *device,
 	DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
 			agent->owner, agent->path);
 
-	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
+	req = agent_request_new(agent, device, AGENT_REQUEST_PASSKEY, cb,
 							user_data, destroy);
 
-	err = passkey_request_new(req, dev_path);
+	err = passkey_request_new(req);
 	if (err < 0)
 		goto failed;
 
@@ -647,10 +679,10 @@ failed:
 }
 
 static int confirmation_request_new(struct agent_request *req,
-					const char *device_path,
 					uint32_t passkey)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
 				AGENT_INTERFACE, "RequestConfirmation");
@@ -659,8 +691,10 @@ static int confirmation_request_new(struct agent_request *req,
 		return -ENOMEM;
 	}
 
+	path = device_get_path(req->device);
+
 	dbus_message_append_args(req->msg,
-				DBUS_TYPE_OBJECT_PATH, &device_path,
+				DBUS_TYPE_OBJECT_PATH, &path,
 				DBUS_TYPE_UINT32, &passkey,
 				DBUS_TYPE_INVALID);
 
@@ -680,19 +714,19 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,
 				void *user_data, GDestroyNotify destroy)
 {
 	struct agent_request *req;
-	const char *dev_path = device_get_path(device);
 	int err;
 
-	if (agent->request)
-		return -EBUSY;
+	err = agent_has_request(agent, device, AGENT_REQUEST_CONFIRMATION);
+	if (err)
+		return err;
 
 	DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
 			agent->owner, agent->path, passkey);
 
-	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
+	req = agent_request_new(agent, device, AGENT_REQUEST_CONFIRMATION, cb,
 				user_data, destroy);
 
-	err = confirmation_request_new(req, dev_path, passkey);
+	err = confirmation_request_new(req, passkey);
 	if (err < 0)
 		goto failed;
 
@@ -705,10 +739,10 @@ failed:
 	return err;
 }
 
-static int authorization_request_new(struct agent_request *req,
-						const char *device_path)
+static int authorization_request_new(struct agent_request *req)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
 				AGENT_INTERFACE, "RequestAuthorization");
@@ -717,8 +751,10 @@ static int authorization_request_new(struct agent_request *req,
 		return -ENOMEM;
 	}
 
+	path = device_get_path(req->device);
+
 	dbus_message_append_args(req->msg,
-				DBUS_TYPE_OBJECT_PATH, &device_path,
+				DBUS_TYPE_OBJECT_PATH, &path,
 				DBUS_TYPE_INVALID);
 
 	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
@@ -737,19 +773,19 @@ int agent_request_authorization(struct agent *agent, struct btd_device *device,
 						GDestroyNotify destroy)
 {
 	struct agent_request *req;
-	const char *dev_path = device_get_path(device);
 	int err;
 
-	if (agent->request)
-		return -EBUSY;
+	err = agent_has_request(agent, device, AGENT_REQUEST_AUTHORIZATION);
+	if (err)
+		return err;
 
 	DBG("Calling Agent.RequestAuthorization: name=%s, path=%s",
 						agent->owner, agent->path);
 
-	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZATION, cb,
+	req = agent_request_new(agent, device, AGENT_REQUEST_AUTHORIZATION, cb,
 				user_data, destroy);
 
-	err = authorization_request_new(req, dev_path);
+	err = authorization_request_new(req);
 	if (err < 0)
 		goto failed;
 
@@ -838,10 +874,10 @@ done:
 }
 
 static int display_pincode_request_new(struct agent_request *req,
-					const char *device_path,
 					const char *pincode)
 {
 	struct agent *agent = req->agent;
+	const char *path;
 
 	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
 					AGENT_INTERFACE, "DisplayPinCode");
@@ -850,8 +886,10 @@ static int display_pincode_request_new(struct agent_request *req,
 		return -ENOMEM;
 	}
 
+	path = device_get_path(req->device);
+
 	dbus_message_append_args(req->msg,
-					DBUS_TYPE_OBJECT_PATH, &device_path,
+					DBUS_TYPE_OBJECT_PATH, &path,
 					DBUS_TYPE_STRING, &pincode,
 					DBUS_TYPE_INVALID);
 
@@ -872,19 +910,19 @@ int agent_display_pincode(struct agent *agent, struct btd_device *device,
 				void *user_data, GDestroyNotify destroy)
 {
 	struct agent_request *req;
-	const char *dev_path = device_get_path(device);
 	int err;
 
-	if (agent->request)
-		return -EBUSY;
+	err = agent_has_request(agent, device, AGENT_REQUEST_DISPLAY_PINCODE);
+	if (err)
+		return err;
 
 	DBG("Calling Agent.DisplayPinCode: name=%s, path=%s, pincode=%s",
 					agent->owner, agent->path, pincode);
 
-	req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb,
-							user_data, destroy);
+	req = agent_request_new(agent, device, AGENT_REQUEST_DISPLAY_PINCODE,
+				cb, user_data, destroy);
 
-	err = display_pincode_request_new(req, dev_path, pincode);
+	err = display_pincode_request_new(req, pincode);
 	if (err < 0)
 		goto failed;
 
diff --git a/src/agent.h b/src/agent.h
index f14d14325..1438b9e6d 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -45,7 +45,7 @@ void agent_unref(struct agent *agent);
 
 struct agent *agent_get(const char *owner);
 
-int agent_authorize_service(struct agent *agent, const char *path,
+int agent_authorize_service(struct agent *agent, struct btd_device *device,
 				const char *uuid, agent_cb cb,
 				void *user_data, GDestroyNotify destroy);
 
diff --git a/src/device.c b/src/device.c
index 0eec7c922..f7f0bc789 100644
--- a/src/device.c
+++ b/src/device.c
@@ -6166,6 +6166,12 @@ int device_confirm_passkey(struct btd_device *device, uint8_t type,
 						confirm_cb, auth, NULL);
 
 	if (err < 0) {
+		if (err == -EINPROGRESS) {
+			/* Already in progress */
+			confirm_cb(auth->agent, NULL, auth);
+			return 0;
+		}
+
 		error("Failed requesting authentication");
 		device_auth_req_free(device);
 	}
@@ -6213,6 +6219,12 @@ int device_notify_pincode(struct btd_device *device, gboolean secure,
 	err = agent_display_pincode(auth->agent, device, pincode,
 					display_pincode_cb, auth, NULL);
 	if (err < 0) {
+		if (err == -EINPROGRESS) {
+			/* Already in progress */
+			display_pincode_cb(auth->agent, NULL, auth);
+			return 0;
+		}
+
 		error("Failed requesting authentication");
 		device_auth_req_free(device);
 	}
-- 
2.21.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-12-27 18:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-27 18:42 [PATCH BlueZ] agent: Detect when ongoing request is already in progress Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).