agent: Detect when ongoing request is already in progress

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.
This commit is contained in:
Luiz Augusto von Dentz 2019-12-27 10:19:15 -08:00
parent 99fa144721
commit 9f9d1bc9ae
4 changed files with 97 additions and 50 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -6155,6 +6155,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);
}
@ -6202,6 +6208,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);
}