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