• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
agent_release(struct agent * agent)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 
send_cancel_request(struct agent_request * req)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 
agent_request_free(struct agent_request * req,gboolean destroy)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 
agent_exited(DBusConnection * conn,void * user_data)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 
agent_free(struct agent * agent)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 
agent_create(struct btd_adapter * adapter,const char * name,const char * path,uint8_t capability,agent_remove_cb cb,void * remove_cb_data)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 
agent_request_new(struct agent * agent,agent_request_type_t type,void * cb,void * user_data,GDestroyNotify destroy)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 
agent_cancel(struct agent * agent)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 
simple_agent_reply(DBusPendingCall * call,void * user_data)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 
agent_call_authorize(struct agent_request * req,const char * device_path,const char * uuid)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 
agent_authorize(struct agent * agent,const char * path,const char * uuid,agent_cb cb,void * user_data,GDestroyNotify destroy)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 
pincode_reply(DBusPendingCall * call,void * user_data)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 
pincode_request_new(struct agent_request * req,const char * device_path,dbus_bool_t numeric)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 
agent_request_pincode(struct agent * agent,struct btd_device * device,agent_pincode_cb cb,void * user_data,GDestroyNotify destroy)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 
confirm_mode_change_request_new(struct agent_request * req,const char * mode)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 
agent_confirm_mode_change(struct agent * agent,const char * new_mode,agent_cb cb,void * user_data,GDestroyNotify destroy)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 
passkey_reply(DBusPendingCall * call,void * user_data)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 
passkey_request_new(struct agent_request * req,const char * device_path)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 
agent_request_passkey(struct agent * agent,struct btd_device * device,agent_passkey_cb cb,void * user_data,GDestroyNotify destroy)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 
confirmation_request_new(struct agent_request * req,const char * device_path,uint32_t passkey)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 
agent_request_confirmation(struct agent * agent,struct btd_device * device,uint32_t passkey,agent_cb cb,void * user_data,GDestroyNotify destroy)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 
pairing_consent_request_new(struct agent_request * req,const char * device_path)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 
agent_request_pairing_consent(struct agent * agent,struct btd_device * device,agent_cb cb,void * user_data,GDestroyNotify destroy)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 
request_fallback(struct agent_request * req,DBusPendingCallNotifyFunction function)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 
agent_display_passkey(struct agent * agent,struct btd_device * device,uint32_t passkey)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 
agent_get_io_capability(struct agent * agent)819 uint8_t agent_get_io_capability(struct agent *agent)
820 {
821 	return agent->capability;
822 }
823 
agent_matches(struct agent * agent,const char * name,const char * path)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 
agent_is_busy(struct agent * agent,void * user_data)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 
agent_exit(void)843 void agent_exit(void)
844 {
845 	dbus_connection_unref(connection);
846 	connection = NULL;
847 }
848 
agent_init(void)849 void agent_init(void)
850 {
851 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
852 }
853