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