tizen 2.3.1 release
[framework/connectivity/bluez.git] / src / agent.c
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 <stdbool.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35
36 #include <glib.h>
37 #include <dbus/dbus.h>
38
39 #include "lib/bluetooth.h"
40 #include "lib/sdp.h"
41
42 #include "gdbus/gdbus.h"
43
44 #include "log.h"
45 #include "error.h"
46 #include "hcid.h"
47 #include "dbus-common.h"
48 #include "adapter.h"
49 #include "device.h"
50 #include "agent.h"
51 #include "shared/queue.h"
52
53 #define IO_CAPABILITY_DISPLAYONLY       0x00
54 #define IO_CAPABILITY_DISPLAYYESNO      0x01
55 #define IO_CAPABILITY_KEYBOARDONLY      0x02
56 #define IO_CAPABILITY_NOINPUTNOOUTPUT   0x03
57 #define IO_CAPABILITY_KEYBOARDDISPLAY   0x04
58 #define IO_CAPABILITY_INVALID           0xFF
59
60 #define REQUEST_TIMEOUT (60 * 1000)             /* 60 seconds */
61 #define AGENT_INTERFACE "org.bluez.Agent1"
62
63 static GHashTable *agent_list;
64 struct queue *default_agents = NULL;
65
66 typedef enum {
67         AGENT_REQUEST_PASSKEY,
68         AGENT_REQUEST_CONFIRMATION,
69         AGENT_REQUEST_AUTHORIZATION,
70         AGENT_REQUEST_PINCODE,
71         AGENT_REQUEST_AUTHORIZE_SERVICE,
72         AGENT_REQUEST_DISPLAY_PINCODE,
73 } agent_request_type_t;
74
75 struct agent {
76         int ref;
77         char *owner;
78         char *path;
79         uint8_t capability;
80         struct agent_request *request;
81         guint watch;
82 };
83
84 struct agent_request {
85         agent_request_type_t type;
86         struct agent *agent;
87         DBusMessage *msg;
88         DBusPendingCall *call;
89         void *cb;
90         void *user_data;
91         GDestroyNotify destroy;
92 };
93
94 static void agent_release(struct agent *agent)
95 {
96         DBusMessage *message;
97
98         DBG("Releasing agent %s, %s", agent->owner, agent->path);
99
100         if (agent->request)
101                 agent_cancel(agent);
102
103         message = dbus_message_new_method_call(agent->owner, agent->path,
104                                                 AGENT_INTERFACE, "Release");
105         if (message == NULL) {
106                 error("Couldn't allocate D-Bus message");
107                 return;
108         }
109
110         g_dbus_send_message(btd_get_dbus_connection(), message);
111 }
112
113 static int send_cancel_request(struct agent_request *req)
114 {
115         DBusMessage *message;
116
117         DBG("Sending Cancel request to %s, %s", req->agent->owner,
118                                                         req->agent->path);
119
120         message = dbus_message_new_method_call(req->agent->owner, req->agent->path,
121                                                 AGENT_INTERFACE, "Cancel");
122         if (message == NULL) {
123                 error("Couldn't allocate D-Bus message");
124                 return -ENOMEM;
125         }
126
127         g_dbus_send_message(btd_get_dbus_connection(), message);
128
129         return 0;
130 }
131
132 static void agent_request_free(struct agent_request *req, gboolean destroy)
133 {
134         if (req->msg)
135                 dbus_message_unref(req->msg);
136         if (req->call)
137                 dbus_pending_call_unref(req->call);
138         if (req->agent && req->agent->request)
139                 req->agent->request = NULL;
140         if (destroy && req->destroy)
141                 req->destroy(req->user_data);
142         g_free(req);
143 }
144
145 static void set_io_cap(struct btd_adapter *adapter, gpointer user_data)
146 {
147         struct agent *agent = user_data;
148         uint8_t io_cap;
149
150         if (agent)
151                 io_cap = agent->capability;
152         else
153                 io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
154
155         adapter_set_io_capability(adapter, io_cap);
156 }
157
158 static bool add_default_agent(struct agent *agent)
159 {
160         if (queue_peek_head(default_agents) == agent)
161                 return true;
162
163         queue_remove(default_agents, agent);
164
165         if (!queue_push_head(default_agents, agent))
166                 return false;
167
168         DBG("Default agent set to %s %s", agent->owner, agent->path);
169
170         adapter_foreach(set_io_cap, agent);
171
172         return true;
173 }
174
175 static void remove_default_agent(struct agent *agent)
176 {
177         if (queue_peek_head(default_agents) != agent) {
178                 queue_remove(default_agents, agent);
179                 return;
180         }
181
182         queue_remove(default_agents, agent);
183
184         agent = queue_peek_head(default_agents);
185         if (agent)
186                 DBG("Default agent set to %s %s", agent->owner, agent->path);
187         else
188                 DBG("Default agent cleared");
189
190         adapter_foreach(set_io_cap, agent);
191 }
192
193 static void agent_disconnect(DBusConnection *conn, void *user_data)
194 {
195         struct agent *agent = user_data;
196
197         DBG("Agent %s disconnected", agent->owner);
198
199         if (agent->watch > 0) {
200                 g_dbus_remove_watch(conn, agent->watch);
201                 agent->watch = 0;
202         }
203
204         remove_default_agent(agent);
205
206         g_hash_table_remove(agent_list, agent->owner);
207 }
208
209 struct agent *agent_ref(struct agent *agent)
210 {
211         agent->ref++;
212
213         DBG("%p: ref=%d", agent, agent->ref);
214
215         return agent;
216 }
217
218 void agent_unref(struct agent *agent)
219 {
220         agent->ref--;
221
222         DBG("%p: ref=%d", agent, agent->ref);
223
224         if (agent->ref > 0)
225                 return;
226
227         if (agent->request) {
228                 DBusError err;
229                 agent_pincode_cb pincode_cb;
230                 agent_passkey_cb passkey_cb;
231                 agent_cb cb;
232
233                 dbus_error_init(&err);
234                 dbus_set_error_const(&err, ERROR_INTERFACE ".Failed",
235                                                                 "Canceled");
236
237                 switch (agent->request->type) {
238                 case AGENT_REQUEST_PINCODE:
239                         pincode_cb = agent->request->cb;
240                         pincode_cb(agent, &err, NULL, agent->request->user_data);
241                         break;
242                 case AGENT_REQUEST_PASSKEY:
243                         passkey_cb = agent->request->cb;
244                         passkey_cb(agent, &err, 0, agent->request->user_data);
245                         break;
246                 case AGENT_REQUEST_CONFIRMATION:
247                 case AGENT_REQUEST_AUTHORIZATION:
248                 case AGENT_REQUEST_AUTHORIZE_SERVICE:
249                 case AGENT_REQUEST_DISPLAY_PINCODE:
250                 default:
251                         cb = agent->request->cb;
252                         cb(agent, &err, agent->request->user_data);
253                 }
254
255                 dbus_error_free(&err);
256
257                 agent_cancel(agent);
258         }
259
260         g_free(agent->owner);
261         g_free(agent->path);
262
263         g_free(agent);
264 }
265
266 struct agent *agent_get(const char *owner)
267 {
268         struct agent *agent;
269
270         if (owner) {
271                 agent = g_hash_table_lookup(agent_list, owner);
272                 if (agent)
273                         return agent_ref(agent);
274         }
275
276         if (!queue_isempty(default_agents))
277                 return agent_ref(queue_peek_head(default_agents));
278
279         return NULL;
280 }
281
282 static struct agent *agent_create( const char *name, const char *path,
283                                                         uint8_t capability)
284 {
285         struct agent *agent;
286
287         agent = g_new0(struct agent, 1);
288
289         agent->owner = g_strdup(name);
290         agent->path = g_strdup(path);
291         agent->capability = capability;
292
293         agent->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
294                                                         name, agent_disconnect,
295                                                         agent, NULL);
296
297         return agent_ref(agent);
298 }
299
300 static struct agent_request *agent_request_new(struct agent *agent,
301                                                 agent_request_type_t type,
302                                                 void *cb,
303                                                 void *user_data,
304                                                 GDestroyNotify destroy)
305 {
306         struct agent_request *req;
307
308         req = g_new0(struct agent_request, 1);
309
310         req->agent = agent;
311         req->type = type;
312         req->cb = cb;
313         req->user_data = user_data;
314         req->destroy = destroy;
315
316         return req;
317 }
318
319 int agent_cancel(struct agent *agent)
320 {
321         if (!agent->request)
322                 return -EINVAL;
323
324         if (agent->request->call) {
325                 dbus_pending_call_cancel(agent->request->call);
326                 send_cancel_request(agent->request);
327         }
328
329         agent_request_free(agent->request, TRUE);
330         agent->request = NULL;
331
332         return 0;
333 }
334
335 static void simple_agent_reply(DBusPendingCall *call, void *user_data)
336 {
337         struct agent_request *req = user_data;
338         struct agent *agent = req->agent;
339         DBusMessage *message;
340         DBusError err;
341         agent_cb cb = req->cb;
342
343         /* steal_reply will always return non-NULL since the callback
344          * is only called after a reply has been received */
345         message = dbus_pending_call_steal_reply(call);
346
347         /* Protect from the callback freeing the agent */
348         agent_ref(agent);
349
350         dbus_error_init(&err);
351         if (dbus_set_error_from_message(&err, message)) {
352                 DBG("agent error reply: %s, %s", err.name, err.message);
353
354                 cb(agent, &err, req->user_data);
355
356                 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
357                         error("Timed out waiting for reply from agent");
358                         agent_cancel(agent);
359                         dbus_message_unref(message);
360                         dbus_error_free(&err);
361                         agent_unref(agent);
362                         return;
363                 }
364
365                 dbus_error_free(&err);
366                 goto done;
367         }
368
369         if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
370                 error("Wrong reply signature: %s", err.message);
371                 cb(agent, &err, req->user_data);
372                 dbus_error_free(&err);
373                 goto done;
374         }
375
376         cb(agent, NULL, req->user_data);
377 done:
378         dbus_message_unref(message);
379
380         agent->request = NULL;
381         agent_request_free(req, TRUE);
382         agent_unref(agent);
383 }
384
385 static int agent_call_authorize_service(struct agent_request *req,
386                                                 const char *device_path,
387                                                 const char *uuid)
388 {
389         struct agent *agent = req->agent;
390
391         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
392                                         AGENT_INTERFACE, "AuthorizeService");
393         if (!req->msg) {
394                 error("Couldn't allocate D-Bus message");
395                 return -ENOMEM;
396         }
397
398         dbus_message_append_args(req->msg,
399                                 DBUS_TYPE_OBJECT_PATH, &device_path,
400                                 DBUS_TYPE_STRING, &uuid,
401                                 DBUS_TYPE_INVALID);
402
403         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
404                                                 req->msg, &req->call,
405                                                 REQUEST_TIMEOUT) == FALSE) {
406                 error("D-Bus send failed");
407                 return -EIO;
408         }
409
410         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
411         return 0;
412 }
413
414 int agent_authorize_service(struct agent *agent, const char *path,
415                                 const char *uuid, agent_cb cb,
416                                 void *user_data, GDestroyNotify destroy)
417 {
418         struct agent_request *req;
419         int err;
420
421         if (agent->request)
422                 return -EBUSY;
423
424         req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE_SERVICE, cb,
425                                                         user_data, destroy);
426
427         err = agent_call_authorize_service(req, path, uuid);
428         if (err < 0) {
429                 agent_request_free(req, FALSE);
430                 return -ENOMEM;
431         }
432
433         agent->request = req;
434
435         DBG("authorize service request was sent for %s", path);
436
437         return 0;
438 }
439
440 static void pincode_reply(DBusPendingCall *call, void *user_data)
441 {
442         struct agent_request *req = user_data;
443         struct agent *agent = req->agent;
444         agent_pincode_cb cb = req->cb;
445         DBusMessage *message;
446         DBusError err;
447         size_t len;
448         char *pin;
449
450         /* steal_reply will always return non-NULL since the callback
451          * is only called after a reply has been received */
452         message = dbus_pending_call_steal_reply(call);
453
454         /* Protect from the callback freeing the agent */
455         agent_ref(agent);
456
457         dbus_error_init(&err);
458         if (dbus_set_error_from_message(&err, message)) {
459                 error("Agent %s replied with an error: %s, %s",
460                                 agent->path, err.name, err.message);
461
462                 cb(agent, &err, NULL, req->user_data);
463                 dbus_error_free(&err);
464                 goto done;
465         }
466
467         if (!dbus_message_get_args(message, &err,
468                                 DBUS_TYPE_STRING, &pin,
469                                 DBUS_TYPE_INVALID)) {
470                 error("Wrong passkey reply signature: %s", err.message);
471                 cb(agent, &err, NULL, req->user_data);
472                 dbus_error_free(&err);
473                 goto done;
474         }
475
476         len = strlen(pin);
477
478         if (len > 16 || len < 1) {
479                 error("Invalid PIN length (%zu) from agent", len);
480                 dbus_set_error_const(&err, ERROR_INTERFACE ".InvalidArgs",
481                                         "Invalid passkey length");
482                 cb(agent, &err, NULL, req->user_data);
483                 dbus_error_free(&err);
484                 goto done;
485         }
486
487         cb(agent, NULL, pin, req->user_data);
488
489 done:
490         if (message)
491                 dbus_message_unref(message);
492
493         dbus_pending_call_cancel(req->call);
494         agent->request = NULL;
495         agent_request_free(req, TRUE);
496         agent_unref(agent);
497 }
498
499 static int pincode_request_new(struct agent_request *req, const char *device_path,
500                                 dbus_bool_t secure)
501 {
502         struct agent *agent = req->agent;
503
504         /* TODO: Add a new method or a new param to Agent interface to request
505                 secure pin. */
506
507         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
508                                         AGENT_INTERFACE, "RequestPinCode");
509         if (req->msg == NULL) {
510                 error("Couldn't allocate D-Bus message");
511                 return -ENOMEM;
512         }
513
514         dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
515                                         DBUS_TYPE_INVALID);
516
517         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
518                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
519                 error("D-Bus send failed");
520                 return -EIO;
521         }
522
523         dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL);
524         return 0;
525 }
526
527 int agent_request_pincode(struct agent *agent, struct btd_device *device,
528                                 agent_pincode_cb cb, gboolean secure,
529                                 void *user_data, GDestroyNotify destroy)
530 {
531         struct agent_request *req;
532         const char *dev_path = device_get_path(device);
533         int err;
534
535         if (agent->request)
536                 return -EBUSY;
537
538         req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
539                                                         user_data, destroy);
540
541         err = pincode_request_new(req, dev_path, secure);
542         if (err < 0)
543                 goto failed;
544
545         agent->request = req;
546
547         return 0;
548
549 failed:
550         agent_request_free(req, FALSE);
551         return err;
552 }
553
554 static void passkey_reply(DBusPendingCall *call, void *user_data)
555 {
556         struct agent_request *req = user_data;
557         struct agent *agent = req->agent;
558         agent_passkey_cb cb = req->cb;
559         DBusMessage *message;
560         DBusError err;
561         uint32_t passkey;
562
563         /* steal_reply will always return non-NULL since the callback
564          * is only called after a reply has been received */
565         message = dbus_pending_call_steal_reply(call);
566
567         dbus_error_init(&err);
568         if (dbus_set_error_from_message(&err, message)) {
569                 error("Agent replied with an error: %s, %s",
570                                                 err.name, err.message);
571                 cb(agent, &err, 0, req->user_data);
572                 dbus_error_free(&err);
573                 goto done;
574         }
575
576         if (!dbus_message_get_args(message, &err,
577                                 DBUS_TYPE_UINT32, &passkey,
578                                 DBUS_TYPE_INVALID)) {
579                 error("Wrong passkey reply signature: %s", err.message);
580                 cb(agent, &err, 0, req->user_data);
581                 dbus_error_free(&err);
582                 goto done;
583         }
584
585         cb(agent, NULL, passkey, req->user_data);
586
587 done:
588         if (message)
589                 dbus_message_unref(message);
590
591         dbus_pending_call_cancel(req->call);
592         agent->request = NULL;
593         agent_request_free(req, TRUE);
594 }
595
596 static int passkey_request_new(struct agent_request *req,
597                                 const char *device_path)
598 {
599         struct agent *agent = req->agent;
600
601         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
602                                         AGENT_INTERFACE, "RequestPasskey");
603         if (req->msg == NULL) {
604                 error("Couldn't allocate D-Bus message");
605                 return -ENOMEM;
606         }
607
608         dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
609                                         DBUS_TYPE_INVALID);
610
611         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
612                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
613                 error("D-Bus send failed");
614                 return -EIO;
615         }
616
617         dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
618         return 0;
619 }
620
621 int agent_request_passkey(struct agent *agent, struct btd_device *device,
622                                 agent_passkey_cb cb, void *user_data,
623                                 GDestroyNotify destroy)
624 {
625         struct agent_request *req;
626         const char *dev_path = device_get_path(device);
627         int err;
628
629         if (agent->request)
630                 return -EBUSY;
631
632         DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
633                         agent->owner, agent->path);
634
635         req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
636                                                         user_data, destroy);
637
638         err = passkey_request_new(req, dev_path);
639         if (err < 0)
640                 goto failed;
641
642         agent->request = req;
643
644         return 0;
645
646 failed:
647         agent_request_free(req, FALSE);
648         return err;
649 }
650
651 static int confirmation_request_new(struct agent_request *req,
652                                         const char *device_path,
653                                         uint32_t passkey)
654 {
655         struct agent *agent = req->agent;
656
657         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
658                                 AGENT_INTERFACE, "RequestConfirmation");
659         if (req->msg == NULL) {
660                 error("Couldn't allocate D-Bus message");
661                 return -ENOMEM;
662         }
663
664         dbus_message_append_args(req->msg,
665                                 DBUS_TYPE_OBJECT_PATH, &device_path,
666                                 DBUS_TYPE_UINT32, &passkey,
667                                 DBUS_TYPE_INVALID);
668
669         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
670                                 &req->call, REQUEST_TIMEOUT) == FALSE) {
671                 error("D-Bus send failed");
672                 return -EIO;
673         }
674
675         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
676
677         return 0;
678 }
679
680 int agent_request_confirmation(struct agent *agent, struct btd_device *device,
681                                 uint32_t passkey, agent_cb cb,
682                                 void *user_data, GDestroyNotify destroy)
683 {
684         struct agent_request *req;
685         const char *dev_path = device_get_path(device);
686         int err;
687
688         if (agent->request)
689                 return -EBUSY;
690
691         DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
692                         agent->owner, agent->path, passkey);
693
694         req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
695                                 user_data, destroy);
696
697         err = confirmation_request_new(req, dev_path, passkey);
698         if (err < 0)
699                 goto failed;
700
701         agent->request = req;
702
703         return 0;
704
705 failed:
706         agent_request_free(req, FALSE);
707         return err;
708 }
709
710 static int authorization_request_new(struct agent_request *req,
711                                                 const char *device_path)
712 {
713         struct agent *agent = req->agent;
714
715         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
716                                 AGENT_INTERFACE, "RequestAuthorization");
717         if (req->msg == NULL) {
718                 error("Couldn't allocate D-Bus message");
719                 return -ENOMEM;
720         }
721
722         dbus_message_append_args(req->msg,
723                                 DBUS_TYPE_OBJECT_PATH, &device_path,
724                                 DBUS_TYPE_INVALID);
725
726         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
727                                 &req->call, REQUEST_TIMEOUT) == FALSE) {
728                 error("D-Bus send failed");
729                 return -EIO;
730         }
731
732         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
733
734         return 0;
735 }
736
737 int agent_request_authorization(struct agent *agent, struct btd_device *device,
738                                                 agent_cb cb, void *user_data,
739                                                 GDestroyNotify destroy)
740 {
741         struct agent_request *req;
742         const char *dev_path = device_get_path(device);
743         int err;
744
745         if (agent->request)
746                 return -EBUSY;
747
748         DBG("Calling Agent.RequestAuthorization: name=%s, path=%s",
749                                                 agent->owner, agent->path);
750
751         req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZATION, cb,
752                                 user_data, destroy);
753
754         err = authorization_request_new(req, dev_path);
755         if (err < 0)
756                 goto failed;
757
758         agent->request = req;
759
760         return 0;
761
762 failed:
763         agent_request_free(req, FALSE);
764         return err;
765 }
766
767 int agent_display_passkey(struct agent *agent, struct btd_device *device,
768                                 uint32_t passkey, uint16_t entered)
769 {
770         DBusMessage *message;
771         const char *dev_path = device_get_path(device);
772
773         message = dbus_message_new_method_call(agent->owner, agent->path,
774                                         AGENT_INTERFACE, "DisplayPasskey");
775         if (!message) {
776                 error("Couldn't allocate D-Bus message");
777                 return -1;
778         }
779
780         dbus_message_append_args(message,
781                                 DBUS_TYPE_OBJECT_PATH, &dev_path,
782                                 DBUS_TYPE_UINT32, &passkey,
783                                 DBUS_TYPE_UINT16, &entered,
784                                 DBUS_TYPE_INVALID);
785
786         if (!g_dbus_send_message(btd_get_dbus_connection(), message)) {
787                 error("D-Bus send failed");
788                 return -1;
789         }
790
791         return 0;
792 }
793
794 static void display_pincode_reply(DBusPendingCall *call, void *user_data)
795 {
796         struct agent_request *req = user_data;
797         struct agent *agent = req->agent;
798         DBusMessage *message;
799         DBusError err;
800         agent_cb cb = req->cb;
801
802         /* clear agent->request early; our callback will likely try
803          * another request */
804         agent->request = NULL;
805
806         /* steal_reply will always return non-NULL since the callback
807          * is only called after a reply has been received */
808         message = dbus_pending_call_steal_reply(call);
809
810         dbus_error_init(&err);
811         if (dbus_set_error_from_message(&err, message)) {
812                 error("Agent replied with an error: %s, %s",
813                                                 err.name, err.message);
814
815                 cb(agent, &err, req->user_data);
816
817                 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
818                         agent_cancel(agent);
819                         dbus_message_unref(message);
820                         dbus_error_free(&err);
821                         return;
822                 }
823
824                 dbus_error_free(&err);
825                 goto done;
826         }
827
828         if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
829                 error("Wrong reply signature: %s", err.message);
830                 cb(agent, &err, req->user_data);
831                 dbus_error_free(&err);
832                 goto done;
833         }
834
835         cb(agent, NULL, req->user_data);
836 done:
837         dbus_message_unref(message);
838
839         agent_request_free(req, TRUE);
840 }
841
842 static int display_pincode_request_new(struct agent_request *req,
843                                         const char *device_path,
844                                         const char *pincode)
845 {
846         struct agent *agent = req->agent;
847
848         req->msg = dbus_message_new_method_call(agent->owner, agent->path,
849                                         AGENT_INTERFACE, "DisplayPinCode");
850         if (req->msg == NULL) {
851                 error("Couldn't allocate D-Bus message");
852                 return -ENOMEM;
853         }
854
855         dbus_message_append_args(req->msg,
856                                         DBUS_TYPE_OBJECT_PATH, &device_path,
857                                         DBUS_TYPE_STRING, &pincode,
858                                         DBUS_TYPE_INVALID);
859
860         if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
861                                 &req->call, REQUEST_TIMEOUT) == FALSE) {
862                 error("D-Bus send failed");
863                 return -EIO;
864         }
865
866         dbus_pending_call_set_notify(req->call, display_pincode_reply,
867                                                                 req, NULL);
868
869         return 0;
870 }
871
872 int agent_display_pincode(struct agent *agent, struct btd_device *device,
873                                 const char *pincode, agent_cb cb,
874                                 void *user_data, GDestroyNotify destroy)
875 {
876         struct agent_request *req;
877         const char *dev_path = device_get_path(device);
878         int err;
879
880         if (agent->request)
881                 return -EBUSY;
882
883         DBG("Calling Agent.DisplayPinCode: name=%s, path=%s, pincode=%s",
884                                         agent->owner, agent->path, pincode);
885
886         req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb,
887                                                         user_data, destroy);
888
889         err = display_pincode_request_new(req, dev_path, pincode);
890         if (err < 0)
891                 goto failed;
892
893         agent->request = req;
894
895         return 0;
896
897 failed:
898         agent_request_free(req, FALSE);
899         return err;
900 }
901
902 uint8_t agent_get_io_capability(struct agent *agent)
903 {
904         return agent->capability;
905 }
906
907 static void agent_destroy(gpointer data)
908 {
909         struct agent *agent = data;
910
911         DBG("agent %s", agent->owner);
912
913         if (agent->watch > 0) {
914                 g_dbus_remove_watch(btd_get_dbus_connection(), agent->watch);
915                 agent->watch = 0;
916                 agent_release(agent);
917         }
918
919         remove_default_agent(agent);
920
921         agent_unref(agent);
922 }
923
924 static uint8_t parse_io_capability(const char *capability)
925 {
926         if (g_str_equal(capability, ""))
927                 return IO_CAPABILITY_DISPLAYYESNO;
928         if (g_str_equal(capability, "DisplayOnly"))
929                 return IO_CAPABILITY_DISPLAYONLY;
930         if (g_str_equal(capability, "DisplayYesNo"))
931                 return IO_CAPABILITY_DISPLAYYESNO;
932         if (g_str_equal(capability, "KeyboardOnly"))
933                 return IO_CAPABILITY_KEYBOARDONLY;
934         if (g_str_equal(capability, "NoInputNoOutput"))
935                 return IO_CAPABILITY_NOINPUTNOOUTPUT;
936         if (g_str_equal(capability, "KeyboardDisplay"))
937                 return IO_CAPABILITY_KEYBOARDDISPLAY;
938         return IO_CAPABILITY_INVALID;
939 }
940
941 static DBusMessage *register_agent(DBusConnection *conn,
942                                         DBusMessage *msg, void *user_data)
943 {
944         struct agent *agent;
945         const char *sender, *path, *capability;
946         uint8_t cap;
947
948         sender = dbus_message_get_sender(msg);
949
950         agent = g_hash_table_lookup(agent_list, sender);
951         if (agent)
952                 return btd_error_already_exists(msg);
953
954         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
955                                                 DBUS_TYPE_STRING, &capability,
956                                                 DBUS_TYPE_INVALID) == FALSE)
957                 return btd_error_invalid_args(msg);
958
959         cap = parse_io_capability(capability);
960         if (cap == IO_CAPABILITY_INVALID)
961                 return btd_error_invalid_args(msg);
962
963         agent = agent_create(sender, path, cap);
964         if (!agent)
965                 return btd_error_invalid_args(msg);
966
967         DBG("agent %s", agent->owner);
968
969         g_hash_table_replace(agent_list, agent->owner, agent);
970
971         return dbus_message_new_method_return(msg);
972 }
973
974 static DBusMessage *unregister_agent(DBusConnection *conn,
975                                         DBusMessage *msg, void *user_data)
976 {
977         struct agent *agent;
978         const char *sender, *path;
979
980         sender = dbus_message_get_sender(msg);
981
982         agent = g_hash_table_lookup(agent_list, sender);
983         if (!agent)
984                 return btd_error_does_not_exist(msg);
985
986         DBG("agent %s", agent->owner);
987
988         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
989                                                 DBUS_TYPE_INVALID) == FALSE)
990                 return btd_error_invalid_args(msg);
991
992         if (g_str_equal(path, agent->path) == FALSE)
993                 return btd_error_does_not_exist(msg);
994
995         agent_disconnect(conn, agent);
996
997         return dbus_message_new_method_return(msg);
998 }
999
1000 static DBusMessage *request_default(DBusConnection *conn, DBusMessage *msg,
1001                                                         void *user_data)
1002 {
1003         struct agent *agent;
1004         const char *sender, *path;
1005
1006         sender = dbus_message_get_sender(msg);
1007
1008         agent = g_hash_table_lookup(agent_list, sender);
1009         if (!agent)
1010                 return btd_error_does_not_exist(msg);
1011
1012         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1013                                                 DBUS_TYPE_INVALID) == FALSE)
1014                 return btd_error_invalid_args(msg);
1015
1016         if (g_str_equal(path, agent->path) == FALSE)
1017                 return btd_error_does_not_exist(msg);
1018
1019         if (!add_default_agent(agent))
1020                 return btd_error_failed(msg, "Failed to set as default");
1021
1022         return dbus_message_new_method_return(msg);
1023 }
1024
1025 static const GDBusMethodTable methods[] = {
1026         { GDBUS_METHOD("RegisterAgent",
1027                         GDBUS_ARGS({ "agent", "o"}, { "capability", "s" }),
1028                         NULL, register_agent) },
1029         { GDBUS_METHOD("UnregisterAgent", GDBUS_ARGS({ "agent", "o" }),
1030                         NULL, unregister_agent) },
1031         { GDBUS_METHOD("RequestDefaultAgent", GDBUS_ARGS({ "agent", "o" }),
1032                         NULL, request_default ) },
1033         { }
1034 };
1035
1036 void btd_agent_init(void)
1037 {
1038         agent_list = g_hash_table_new_full(g_str_hash, g_str_equal,
1039                                                 NULL, agent_destroy);
1040
1041         default_agents = queue_new();
1042
1043         g_dbus_register_interface(btd_get_dbus_connection(),
1044                                 "/org/bluez", "org.bluez.AgentManager1",
1045                                 methods, NULL, NULL, NULL, NULL);
1046 }
1047
1048 void btd_agent_cleanup(void)
1049 {
1050         g_dbus_unregister_interface(btd_get_dbus_connection(),
1051                                 "/org/bluez", "org.bluez.AgentManager1");
1052
1053         g_hash_table_destroy(agent_list);
1054         queue_destroy(default_agents, NULL);
1055 }