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