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