Home | History | Annotate | Download | only in src
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2006-2010  Nokia Corporation
      6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdio.h>
     30 #include <errno.h>
     31 #include <stdlib.h>
     32 #include <sys/socket.h>
     33 #include <sys/ioctl.h>
     34 
     35 #include <bluetooth/bluetooth.h>
     36 #include <bluetooth/sdp.h>
     37 
     38 #include <glib.h>
     39 #include <dbus/dbus.h>
     40 #include <gdbus.h>
     41 
     42 #include "log.h"
     43 
     44 #include "hcid.h"
     45 #include "adapter.h"
     46 #include "device.h"
     47 #include "agent.h"
     48 
     49 #define REQUEST_TIMEOUT (60 * 1000)		/* 60 seconds */
     50 
     51 typedef enum {
     52 	AGENT_REQUEST_PASSKEY,
     53 	AGENT_REQUEST_CONFIRMATION,
     54 	AGENT_REQUEST_PINCODE,
     55 	AGENT_REQUEST_AUTHORIZE,
     56 	AGENT_REQUEST_CONFIRM_MODE,
     57 	AGENT_REQUEST_PAIRING_CONSENT,
     58 } agent_request_type_t;
     59 
     60 struct agent {
     61 	struct btd_adapter *adapter;
     62 	char *name;
     63 	char *path;
     64 	uint8_t capability;
     65 	struct agent_request *request;
     66 	int exited;
     67 	agent_remove_cb remove_cb;
     68 	void *remove_cb_data;
     69 	guint listener_id;
     70 };
     71 
     72 struct agent_request {
     73 	agent_request_type_t type;
     74 	struct agent *agent;
     75 	DBusMessage *msg;
     76 	DBusPendingCall *call;
     77 	void *cb;
     78 	void *user_data;
     79 	GDestroyNotify destroy;
     80 };
     81 
     82 static DBusConnection *connection = NULL;
     83 
     84 static int request_fallback(struct agent_request *req,
     85 				DBusPendingCallNotifyFunction function);
     86 
     87 static void agent_release(struct agent *agent)
     88 {
     89 	DBusMessage *message;
     90 
     91 	DBG("Releasing agent %s, %s", agent->name, agent->path);
     92 
     93 	if (agent->request)
     94 		agent_cancel(agent);
     95 
     96 	message = dbus_message_new_method_call(agent->name, agent->path,
     97 			"org.bluez.Agent", "Release");
     98 	if (message == NULL) {
     99 		error("Couldn't allocate D-Bus message");
    100 		return;
    101 	}
    102 
    103 	g_dbus_send_message(connection, message);
    104 }
    105 
    106 static int send_cancel_request(struct agent_request *req)
    107 {
    108 	DBusMessage *message;
    109 
    110 	DBG("Sending Cancel request to %s, %s", req->agent->name,
    111 							req->agent->path);
    112 
    113 	message = dbus_message_new_method_call(req->agent->name, req->agent->path,
    114 						"org.bluez.Agent", "Cancel");
    115 	if (message == NULL) {
    116 		error("Couldn't allocate D-Bus message");
    117 		return -ENOMEM;
    118 	}
    119 
    120 	g_dbus_send_message(connection, message);
    121 
    122 	return 0;
    123 }
    124 
    125 static void agent_request_free(struct agent_request *req, gboolean destroy)
    126 {
    127 	if (req->msg)
    128 		dbus_message_unref(req->msg);
    129 	if (req->call)
    130 		dbus_pending_call_unref(req->call);
    131 	if (req->agent && req->agent->request)
    132 		req->agent->request = NULL;
    133 	if (destroy && req->destroy)
    134 		req->destroy(req->user_data);
    135 	g_free(req);
    136 }
    137 
    138 static void agent_exited(DBusConnection *conn, void *user_data)
    139 {
    140 	struct agent *agent = user_data;
    141 
    142 	DBG("Agent exited without calling Unregister");
    143 
    144 	agent->exited = TRUE;
    145 
    146 	agent_free(agent);
    147 }
    148 
    149 void agent_free(struct agent *agent)
    150 {
    151 	if (!agent)
    152 		return;
    153 
    154 	if (agent->remove_cb)
    155 		agent->remove_cb(agent, agent->remove_cb_data);
    156 
    157 	if (agent->request) {
    158 		DBusError err;
    159 		agent_pincode_cb pincode_cb;
    160 		agent_cb cb;
    161 
    162 		dbus_error_init(&err);
    163 		dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled");
    164 
    165 		switch (agent->request->type) {
    166 		case AGENT_REQUEST_PINCODE:
    167 			pincode_cb = agent->request->cb;
    168 			pincode_cb(agent, &err, NULL, agent->request->user_data);
    169 			break;
    170 		default:
    171 			cb = agent->request->cb;
    172 			cb(agent, &err, agent->request->user_data);
    173 		}
    174 
    175 		dbus_error_free(&err);
    176 
    177 		agent_cancel(agent);
    178 	}
    179 
    180 	if (!agent->exited) {
    181 		g_dbus_remove_watch(connection, agent->listener_id);
    182 		agent_release(agent);
    183 	}
    184 
    185 	g_free(agent->name);
    186 	g_free(agent->path);
    187 
    188 	g_free(agent);
    189 }
    190 
    191 struct agent *agent_create(struct btd_adapter *adapter, const char *name,
    192 				const char *path, uint8_t capability,
    193 				agent_remove_cb cb, void *remove_cb_data)
    194 {
    195 	struct agent *agent;
    196 
    197 	agent = g_new0(struct agent, 1);
    198 
    199 	agent->adapter = adapter;
    200 	agent->name = g_strdup(name);
    201 	agent->path = g_strdup(path);
    202 	agent->capability = capability;
    203 	agent->remove_cb = cb;
    204 	agent->remove_cb_data = remove_cb_data;
    205 
    206 	agent->listener_id = g_dbus_add_disconnect_watch(connection, name,
    207 							agent_exited, agent,
    208 							NULL);
    209 
    210 	return agent;
    211 }
    212 
    213 static struct agent_request *agent_request_new(struct agent *agent,
    214 						agent_request_type_t type,
    215 						void *cb,
    216 						void *user_data,
    217 						GDestroyNotify destroy)
    218 {
    219 	struct agent_request *req;
    220 
    221 	req = g_new0(struct agent_request, 1);
    222 
    223 	req->agent = agent;
    224 	req->type = type;
    225 	req->cb = cb;
    226 	req->user_data = user_data;
    227 	req->destroy = destroy;
    228 
    229 	return req;
    230 }
    231 
    232 int agent_cancel(struct agent *agent)
    233 {
    234 	if (!agent->request)
    235 		return -EINVAL;
    236 
    237 	if (agent->request->call)
    238 		dbus_pending_call_cancel(agent->request->call);
    239 
    240 	if (!agent->exited)
    241 		send_cancel_request(agent->request);
    242 
    243 	agent_request_free(agent->request, TRUE);
    244 	agent->request = NULL;
    245 
    246 	return 0;
    247 }
    248 
    249 static void simple_agent_reply(DBusPendingCall *call, void *user_data)
    250 {
    251 	struct agent_request *req = user_data;
    252 	struct agent *agent = req->agent;
    253 	DBusMessage *message;
    254 	DBusError err;
    255 	agent_cb cb = req->cb;
    256 
    257 	/* steal_reply will always return non-NULL since the callback
    258 	 * is only called after a reply has been received */
    259 	message = dbus_pending_call_steal_reply(call);
    260 
    261 	dbus_error_init(&err);
    262 	if (dbus_set_error_from_message(&err, message)) {
    263 		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
    264 				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
    265 				request_fallback(req, simple_agent_reply) == 0) {
    266 			dbus_error_free(&err);
    267 			return;
    268 		}
    269 
    270 		error("Agent replied with an error: %s, %s",
    271 				err.name, err.message);
    272 
    273 		cb(agent, &err, req->user_data);
    274 
    275 		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
    276 			agent_cancel(agent);
    277 			dbus_message_unref(message);
    278 			dbus_error_free(&err);
    279 			return;
    280 		}
    281 
    282 		dbus_error_free(&err);
    283 		goto done;
    284 	}
    285 
    286 	dbus_error_init(&err);
    287 	if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
    288 		error("Wrong reply signature: %s", err.message);
    289 		cb(agent, &err, req->user_data);
    290 		dbus_error_free(&err);
    291 		goto done;
    292 	}
    293 
    294 	cb(agent, NULL, req->user_data);
    295 done:
    296 	dbus_message_unref(message);
    297 
    298 	agent->request = NULL;
    299 	agent_request_free(req, TRUE);
    300 }
    301 
    302 static int agent_call_authorize(struct agent_request *req,
    303 				const char *device_path,
    304 				const char *uuid)
    305 {
    306 	struct agent *agent = req->agent;
    307 
    308 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    309 				"org.bluez.Agent", "Authorize");
    310 	if (!req->msg) {
    311 		error("Couldn't allocate D-Bus message");
    312 		return -ENOMEM;
    313 	}
    314 
    315 	dbus_message_append_args(req->msg,
    316 				DBUS_TYPE_OBJECT_PATH, &device_path,
    317 				DBUS_TYPE_STRING, &uuid,
    318 				DBUS_TYPE_INVALID);
    319 
    320 	if (dbus_connection_send_with_reply(connection, req->msg,
    321 					&req->call, REQUEST_TIMEOUT) == FALSE) {
    322 		error("D-Bus send failed");
    323 		return -EIO;
    324 	}
    325 
    326 	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
    327 	return 0;
    328 }
    329 
    330 int agent_authorize(struct agent *agent,
    331 			const char *path,
    332 			const char *uuid,
    333 			agent_cb cb,
    334 			void *user_data,
    335 			GDestroyNotify destroy)
    336 {
    337 	struct agent_request *req;
    338 	int err;
    339 
    340 	if (agent->request)
    341 		return -EBUSY;
    342 
    343 	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb,
    344 							user_data, destroy);
    345 
    346 	err = agent_call_authorize(req, path, uuid);
    347 	if (err < 0) {
    348 		agent_request_free(req, FALSE);
    349 		return -ENOMEM;
    350 	}
    351 
    352 	agent->request = req;
    353 
    354 	DBG("authorize request was sent for %s", path);
    355 
    356 	return 0;
    357 }
    358 
    359 static void pincode_reply(DBusPendingCall *call, void *user_data)
    360 {
    361 	struct agent_request *req = user_data;
    362 	struct agent *agent = req->agent;
    363 	struct btd_adapter *adapter = agent->adapter;
    364 	agent_pincode_cb cb = req->cb;
    365 	DBusMessage *message;
    366 	DBusError err;
    367 	bdaddr_t sba;
    368 	size_t len;
    369 	char *pin;
    370 
    371 	adapter_get_address(adapter, &sba);
    372 
    373 	/* steal_reply will always return non-NULL since the callback
    374 	 * is only called after a reply has been received */
    375 	message = dbus_pending_call_steal_reply(call);
    376 
    377 	dbus_error_init(&err);
    378 	if (dbus_set_error_from_message(&err, message)) {
    379 		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
    380 				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
    381 				request_fallback(req, pincode_reply) == 0) {
    382 			dbus_error_free(&err);
    383 			return;
    384 		}
    385 
    386 		error("Agent replied with an error: %s, %s",
    387 				err.name, err.message);
    388 
    389 		cb(agent, &err, NULL, req->user_data);
    390 		dbus_error_free(&err);
    391 		goto done;
    392 	}
    393 
    394 	dbus_error_init(&err);
    395 	if (!dbus_message_get_args(message, &err,
    396 				DBUS_TYPE_STRING, &pin,
    397 				DBUS_TYPE_INVALID)) {
    398 		error("Wrong passkey reply signature: %s", err.message);
    399 		cb(agent, &err, NULL, req->user_data);
    400 		dbus_error_free(&err);
    401 		goto done;
    402 	}
    403 
    404 	len = strlen(pin);
    405 
    406 	dbus_error_init(&err);
    407 	if (len < 1) {
    408 		error("Invalid PIN length (%zu) from agent", len);
    409 		dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs",
    410 					"Invalid passkey length");
    411 		cb(agent, &err, NULL, req->user_data);
    412 		dbus_error_free(&err);
    413 		goto done;
    414 	}
    415 
    416 	cb(agent, NULL, pin, req->user_data);
    417 
    418 done:
    419 	if (message)
    420 		dbus_message_unref(message);
    421 
    422 	dbus_pending_call_cancel(req->call);
    423 	agent->request = NULL;
    424 	agent_request_free(req, TRUE);
    425 }
    426 
    427 static int pincode_request_new(struct agent_request *req, const char *device_path,
    428 				dbus_bool_t numeric)
    429 {
    430 	struct agent *agent = req->agent;
    431 
    432 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    433 					"org.bluez.Agent", "RequestPinCode");
    434 	if (req->msg == NULL) {
    435 		error("Couldn't allocate D-Bus message");
    436 		return -ENOMEM;
    437 	}
    438 
    439 	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
    440 					DBUS_TYPE_INVALID);
    441 
    442 	if (dbus_connection_send_with_reply(connection, req->msg,
    443 					&req->call, REQUEST_TIMEOUT) == FALSE) {
    444 		error("D-Bus send failed");
    445 		return -EIO;
    446 	}
    447 
    448 	dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL);
    449 	return 0;
    450 }
    451 
    452 int agent_request_pincode(struct agent *agent, struct btd_device *device,
    453 				agent_pincode_cb cb, void *user_data,
    454 				GDestroyNotify destroy)
    455 {
    456 	struct agent_request *req;
    457 	const gchar *dev_path = device_get_path(device);
    458 	int err;
    459 
    460 	if (agent->request)
    461 		return -EBUSY;
    462 
    463 	req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
    464 							user_data, destroy);
    465 
    466 	err = pincode_request_new(req, dev_path, FALSE);
    467 	if (err < 0)
    468 		goto failed;
    469 
    470 	agent->request = req;
    471 
    472 	return 0;
    473 
    474 failed:
    475 	g_free(req);
    476 	return err;
    477 }
    478 
    479 static int confirm_mode_change_request_new(struct agent_request *req,
    480 						const char *mode)
    481 {
    482 	struct agent *agent = req->agent;
    483 
    484 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    485 				"org.bluez.Agent", "ConfirmModeChange");
    486 	if (req->msg == NULL) {
    487 		error("Couldn't allocate D-Bus message");
    488 		return -ENOMEM;
    489 	}
    490 
    491 	dbus_message_append_args(req->msg,
    492 				DBUS_TYPE_STRING, &mode,
    493 				DBUS_TYPE_INVALID);
    494 
    495 	if (dbus_connection_send_with_reply(connection, req->msg,
    496 					&req->call, REQUEST_TIMEOUT) == FALSE) {
    497 		error("D-Bus send failed");
    498 		return -EIO;
    499 	}
    500 
    501 	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
    502 	return 0;
    503 }
    504 
    505 int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
    506 				agent_cb cb, void *user_data,
    507 				GDestroyNotify destroy)
    508 {
    509 	struct agent_request *req;
    510 	int err;
    511 
    512 	if (agent->request)
    513 		return -EBUSY;
    514 
    515 	DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
    516 			agent->name, agent->path, new_mode);
    517 
    518 	req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,
    519 				cb, user_data, destroy);
    520 
    521 	err = confirm_mode_change_request_new(req, new_mode);
    522 	if (err < 0)
    523 		goto failed;
    524 
    525 	agent->request = req;
    526 
    527 	return 0;
    528 
    529 failed:
    530 	agent_request_free(req, FALSE);
    531 	return err;
    532 }
    533 
    534 static void passkey_reply(DBusPendingCall *call, void *user_data)
    535 {
    536 	struct agent_request *req = user_data;
    537 	struct agent *agent = req->agent;
    538 	agent_passkey_cb cb = req->cb;
    539 	DBusMessage *message;
    540 	DBusError err;
    541 	uint32_t passkey;
    542 
    543 	/* steal_reply will always return non-NULL since the callback
    544 	 * is only called after a reply has been received */
    545 	message = dbus_pending_call_steal_reply(call);
    546 
    547 	dbus_error_init(&err);
    548 	if (dbus_set_error_from_message(&err, message)) {
    549 		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
    550 				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
    551 				request_fallback(req, passkey_reply) == 0) {
    552 			dbus_error_free(&err);
    553 			return;
    554 		}
    555 
    556 		error("Agent replied with an error: %s, %s",
    557 				err.name, err.message);
    558 		cb(agent, &err, 0, req->user_data);
    559 		dbus_error_free(&err);
    560 		goto done;
    561 	}
    562 
    563 	dbus_error_init(&err);
    564 	if (!dbus_message_get_args(message, &err,
    565 				DBUS_TYPE_UINT32, &passkey,
    566 				DBUS_TYPE_INVALID)) {
    567 		error("Wrong passkey reply signature: %s", err.message);
    568 		cb(agent, &err, 0, req->user_data);
    569 		dbus_error_free(&err);
    570 		goto done;
    571 	}
    572 
    573 	cb(agent, NULL, passkey, req->user_data);
    574 
    575 done:
    576 	if (message)
    577 		dbus_message_unref(message);
    578 
    579 	dbus_pending_call_cancel(req->call);
    580 	agent->request = NULL;
    581 	agent_request_free(req, TRUE);
    582 }
    583 
    584 static int passkey_request_new(struct agent_request *req,
    585 				const char *device_path)
    586 {
    587 	struct agent *agent = req->agent;
    588 
    589 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    590 					"org.bluez.Agent", "RequestPasskey");
    591 	if (req->msg == NULL) {
    592 		error("Couldn't allocate D-Bus message");
    593 		return -ENOMEM;
    594 	}
    595 
    596 	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
    597 					DBUS_TYPE_INVALID);
    598 
    599 	if (dbus_connection_send_with_reply(connection, req->msg,
    600 					&req->call, REQUEST_TIMEOUT) == FALSE) {
    601 		error("D-Bus send failed");
    602 		return -EIO;
    603 	}
    604 
    605 	dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
    606 	return 0;
    607 }
    608 
    609 int agent_request_passkey(struct agent *agent, struct btd_device *device,
    610 				agent_passkey_cb cb, void *user_data,
    611 				GDestroyNotify destroy)
    612 {
    613 	struct agent_request *req;
    614 	const gchar *dev_path = device_get_path(device);
    615 	int err;
    616 
    617 	if (agent->request)
    618 		return -EBUSY;
    619 
    620 	DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
    621 			agent->name, agent->path);
    622 
    623 	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
    624 							user_data, destroy);
    625 
    626 	err = passkey_request_new(req, dev_path);
    627 	if (err < 0)
    628 		goto failed;
    629 
    630 	agent->request = req;
    631 
    632 	return 0;
    633 
    634 failed:
    635 	agent_request_free(req, FALSE);
    636 	return err;
    637 }
    638 
    639 static int confirmation_request_new(struct agent_request *req,
    640 					const char *device_path,
    641 					uint32_t passkey)
    642 {
    643 	struct agent *agent = req->agent;
    644 
    645 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    646 				"org.bluez.Agent", "RequestConfirmation");
    647 	if (req->msg == NULL) {
    648 		error("Couldn't allocate D-Bus message");
    649 		return -ENOMEM;
    650 	}
    651 
    652 	dbus_message_append_args(req->msg,
    653 				DBUS_TYPE_OBJECT_PATH, &device_path,
    654 				DBUS_TYPE_UINT32, &passkey,
    655 				DBUS_TYPE_INVALID);
    656 
    657 	if (dbus_connection_send_with_reply(connection, req->msg,
    658 				&req->call, REQUEST_TIMEOUT) == FALSE) {
    659 		error("D-Bus send failed");
    660 		return -EIO;
    661 	}
    662 
    663 	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
    664 
    665 	return 0;
    666 }
    667 
    668 int agent_request_confirmation(struct agent *agent, struct btd_device *device,
    669 				uint32_t passkey, agent_cb cb,
    670 				void *user_data, GDestroyNotify destroy)
    671 {
    672 	struct agent_request *req;
    673 	const gchar *dev_path = device_get_path(device);
    674 	int err;
    675 
    676 	if (agent->request)
    677 		return -EBUSY;
    678 
    679 	DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
    680 			agent->name, agent->path, passkey);
    681 
    682 	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
    683 				user_data, destroy);
    684 
    685 	err = confirmation_request_new(req, dev_path, passkey);
    686 	if (err < 0)
    687 		goto failed;
    688 
    689 	agent->request = req;
    690 
    691 	return 0;
    692 
    693 failed:
    694 	agent_request_free(req, FALSE);
    695 	return err;
    696 }
    697 
    698 static int pairing_consent_request_new(struct agent_request *req,
    699 						const char *device_path)
    700 {
    701 	struct agent *agent = req->agent;
    702 
    703 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
    704 				"org.bluez.Agent", "RequestPairingConsent");
    705 	if (req->msg == NULL) {
    706 		error("Couldn't allocate D-Bus message");
    707 		return -ENOMEM;
    708 	}
    709 
    710 	dbus_message_append_args(req->msg,
    711 				DBUS_TYPE_OBJECT_PATH, &device_path,
    712 				DBUS_TYPE_INVALID);
    713 
    714 	if (dbus_connection_send_with_reply(connection, req->msg,
    715 				&req->call, REQUEST_TIMEOUT) == FALSE) {
    716 		error("D-Bus send failed");
    717 		return -EIO;
    718 	}
    719 
    720 	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
    721 
    722 	return 0;
    723 }
    724 
    725 int agent_request_pairing_consent(struct agent *agent, struct btd_device *device,
    726 				agent_cb cb, void *user_data,
    727 				GDestroyNotify destroy)
    728 {
    729 	struct agent_request *req;
    730 	const gchar *dev_path = device_get_path(device);
    731 	int err;
    732 
    733 	if (agent->request)
    734 		return -EBUSY;
    735 
    736 	DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s",
    737 			agent->name, agent->path);
    738 
    739 	req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb,
    740 				user_data, destroy);
    741 
    742 	err = pairing_consent_request_new(req, dev_path);
    743 	if (err < 0)
    744 		goto failed;
    745 
    746 	agent->request = req;
    747 
    748 	return 0;
    749 
    750 failed:
    751 	agent_request_free(req, FALSE);
    752 	return err;
    753 }
    754 
    755 static int request_fallback(struct agent_request *req,
    756 				DBusPendingCallNotifyFunction function)
    757 {
    758 	struct btd_adapter *adapter = req->agent->adapter;
    759 	struct agent *adapter_agent = adapter_get_agent(adapter);
    760 	DBusMessage *msg;
    761 
    762 	if (req->agent == adapter_agent || adapter_agent == NULL)
    763 		return -EINVAL;
    764 
    765 	dbus_pending_call_cancel(req->call);
    766 	dbus_pending_call_unref(req->call);
    767 
    768 	msg = dbus_message_copy(req->msg);
    769 
    770 	dbus_message_set_destination(msg, adapter_agent->name);
    771 	dbus_message_set_path(msg, adapter_agent->path);
    772 
    773 	if (dbus_connection_send_with_reply(connection, msg,
    774 					&req->call, REQUEST_TIMEOUT) == FALSE) {
    775 		error("D-Bus send failed");
    776 		dbus_message_unref(msg);
    777 		return -EIO;
    778 	}
    779 
    780 	req->agent->request = NULL;
    781 	req->agent = adapter_agent;
    782 	req->agent->request = req;
    783 
    784 	dbus_message_unref(req->msg);
    785 	req->msg = msg;
    786 
    787 	dbus_pending_call_set_notify(req->call, function, req, NULL);
    788 
    789 	return 0;
    790 }
    791 
    792 int agent_display_passkey(struct agent *agent, struct btd_device *device,
    793 				uint32_t passkey)
    794 {
    795 	DBusMessage *message;
    796 	const gchar *dev_path = device_get_path(device);
    797 
    798 	message = dbus_message_new_method_call(agent->name, agent->path,
    799 				"org.bluez.Agent", "DisplayPasskey");
    800 	if (!message) {
    801 		error("Couldn't allocate D-Bus message");
    802 		return -1;
    803 	}
    804 
    805 	dbus_message_append_args(message,
    806 				DBUS_TYPE_OBJECT_PATH, &dev_path,
    807 				DBUS_TYPE_UINT32, &passkey,
    808 				DBUS_TYPE_INVALID);
    809 
    810 	if (!g_dbus_send_message(connection, message)) {
    811 		error("D-Bus send failed");
    812 		dbus_message_unref(message);
    813 		return -1;
    814 	}
    815 
    816 	return 0;
    817 }
    818 
    819 uint8_t agent_get_io_capability(struct agent *agent)
    820 {
    821 	return agent->capability;
    822 }
    823 
    824 gboolean agent_matches(struct agent *agent, const char *name, const char *path)
    825 {
    826 	if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path))
    827 		return TRUE;
    828 
    829 	return FALSE;
    830 }
    831 
    832 gboolean agent_is_busy(struct agent *agent, void *user_data)
    833 {
    834 	if (!agent->request)
    835 		return FALSE;
    836 
    837 	if (user_data && user_data != agent->request->user_data)
    838 		return FALSE;
    839 
    840 	return TRUE;
    841 }
    842 
    843 void agent_exit(void)
    844 {
    845 	dbus_connection_unref(connection);
    846 	connection = NULL;
    847 }
    848 
    849 void agent_init(void)
    850 {
    851 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
    852 }
    853