Git init
[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 <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_type_t;
58
59 struct agent {
60         struct btd_adapter *adapter;
61         char *name;
62         char *path;
63         uint8_t capability;
64         struct agent_request *request;
65         int exited;
66         agent_remove_cb remove_cb;
67         void *remove_cb_data;
68         guint listener_id;
69 };
70
71 struct agent_request {
72         agent_request_type_t type;
73         struct agent *agent;
74         DBusMessage *msg;
75         DBusPendingCall *call;
76         void *cb;
77         void *user_data;
78         GDestroyNotify destroy;
79 };
80
81 static DBusConnection *connection = NULL;
82
83 static int request_fallback(struct agent_request *req,
84                                 DBusPendingCallNotifyFunction function);
85
86 static void agent_release(struct agent *agent)
87 {
88         DBusMessage *message;
89
90         DBG("Releasing agent %s, %s", agent->name, agent->path);
91
92         if (agent->request)
93                 agent_cancel(agent);
94
95         message = dbus_message_new_method_call(agent->name, agent->path,
96                         "org.bluez.Agent", "Release");
97         if (message == NULL) {
98                 error("Couldn't allocate D-Bus message");
99                 return;
100         }
101
102         g_dbus_send_message(connection, message);
103 }
104
105 static int send_cancel_request(struct agent_request *req)
106 {
107         DBusMessage *message;
108
109         DBG("Sending Cancel request to %s, %s", req->agent->name,
110                                                         req->agent->path);
111
112         message = dbus_message_new_method_call(req->agent->name, req->agent->path,
113                                                 "org.bluez.Agent", "Cancel");
114         if (message == NULL) {
115                 error("Couldn't allocate D-Bus message");
116                 return -ENOMEM;
117         }
118
119         g_dbus_send_message(connection, message);
120
121         return 0;
122 }
123
124 static void agent_request_free(struct agent_request *req, gboolean destroy)
125 {
126         if (req->msg)
127                 dbus_message_unref(req->msg);
128         if (req->call)
129                 dbus_pending_call_unref(req->call);
130         if (req->agent && req->agent->request)
131                 req->agent->request = NULL;
132         if (destroy && req->destroy)
133                 req->destroy(req->user_data);
134         g_free(req);
135 }
136
137 static void agent_exited(DBusConnection *conn, void *user_data)
138 {
139         struct agent *agent = user_data;
140
141         DBG("Agent exited without calling Unregister");
142
143         agent->exited = TRUE;
144
145         agent_free(agent);
146 }
147
148 void agent_free(struct agent *agent)
149 {
150         if (!agent)
151                 return;
152
153         if (agent->remove_cb)
154                 agent->remove_cb(agent, agent->remove_cb_data);
155
156         if (agent->request) {
157                 DBusError err;
158                 agent_pincode_cb pincode_cb;
159                 agent_cb cb;
160
161                 dbus_error_init(&err);
162                 dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled");
163
164                 switch (agent->request->type) {
165                 case AGENT_REQUEST_PINCODE:
166                         pincode_cb = agent->request->cb;
167                         pincode_cb(agent, &err, NULL, agent->request->user_data);
168                         break;
169                 default:
170                         cb = agent->request->cb;
171                         cb(agent, &err, agent->request->user_data);
172                 }
173
174                 dbus_error_free(&err);
175
176                 agent_cancel(agent);
177         }
178
179         if (!agent->exited) {
180                 g_dbus_remove_watch(connection, agent->listener_id);
181                 agent_release(agent);
182         }
183
184         g_free(agent->name);
185         g_free(agent->path);
186
187         g_free(agent);
188 }
189
190 struct agent *agent_create(struct btd_adapter *adapter, const char *name,
191                                 const char *path, uint8_t capability,
192                                 agent_remove_cb cb, void *remove_cb_data)
193 {
194         struct agent *agent;
195
196         agent = g_new0(struct agent, 1);
197
198         agent->adapter = adapter;
199         agent->name = g_strdup(name);
200         agent->path = g_strdup(path);
201         agent->capability = capability;
202         agent->remove_cb = cb;
203         agent->remove_cb_data = remove_cb_data;
204
205         agent->listener_id = g_dbus_add_disconnect_watch(connection, name,
206                                                         agent_exited, agent,
207                                                         NULL);
208
209         return agent;
210 }
211
212 static struct agent_request *agent_request_new(struct agent *agent,
213                                                 agent_request_type_t type,
214                                                 void *cb,
215                                                 void *user_data,
216                                                 GDestroyNotify destroy)
217 {
218         struct agent_request *req;
219
220         req = g_new0(struct agent_request, 1);
221
222         req->agent = agent;
223         req->type = type;
224         req->cb = cb;
225         req->user_data = user_data;
226         req->destroy = destroy;
227
228         return req;
229 }
230
231 int agent_cancel(struct agent *agent)
232 {
233         if (!agent->request)
234                 return -EINVAL;
235
236         if (agent->request->call)
237                 dbus_pending_call_cancel(agent->request->call);
238
239         if (!agent->exited)
240                 send_cancel_request(agent->request);
241
242         agent_request_free(agent->request, TRUE);
243         agent->request = NULL;
244
245         return 0;
246 }
247
248 static void simple_agent_reply(DBusPendingCall *call, void *user_data)
249 {
250         struct agent_request *req = user_data;
251         struct agent *agent = req->agent;
252         DBusMessage *message;
253         DBusError err;
254         agent_cb cb = req->cb;
255
256         /* steal_reply will always return non-NULL since the callback
257          * is only called after a reply has been received */
258         message = dbus_pending_call_steal_reply(call);
259
260         dbus_error_init(&err);
261         if (dbus_set_error_from_message(&err, message)) {
262                 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
263                                 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
264                                 request_fallback(req, simple_agent_reply) == 0) {
265                         dbus_error_free(&err);
266                         return;
267                 }
268
269                 error("Agent replied with an error: %s, %s",
270                                 err.name, err.message);
271
272 #ifdef __TIZEN_PATCH__
273                 if (strcmp(err.message, "CanceledbyUser") == 0)
274                 {
275                         set_cancel_from_authentication_req(req->user_data);
276                 }
277 #endif
278                 cb(agent, &err, req->user_data);
279
280                 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
281                         agent_cancel(agent);
282                         dbus_message_unref(message);
283                         dbus_error_free(&err);
284                         return;
285                 }
286
287                 dbus_error_free(&err);
288                 goto done;
289         }
290
291         dbus_error_init(&err);
292         if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
293                 error("Wrong reply signature: %s", err.message);
294                 cb(agent, &err, req->user_data);
295                 dbus_error_free(&err);
296                 goto done;
297         }
298
299         cb(agent, NULL, req->user_data);
300 done:
301         dbus_message_unref(message);
302
303         agent->request = NULL;
304         agent_request_free(req, TRUE);
305 }
306
307 static int agent_call_authorize(struct agent_request *req,
308                                 const char *device_path,
309                                 const char *uuid)
310 {
311         struct agent *agent = req->agent;
312
313         req->msg = dbus_message_new_method_call(agent->name, agent->path,
314                                 "org.bluez.Agent", "Authorize");
315         if (!req->msg) {
316                 error("Couldn't allocate D-Bus message");
317                 return -ENOMEM;
318         }
319
320         dbus_message_append_args(req->msg,
321                                 DBUS_TYPE_OBJECT_PATH, &device_path,
322                                 DBUS_TYPE_STRING, &uuid,
323                                 DBUS_TYPE_INVALID);
324
325         if (dbus_connection_send_with_reply(connection, req->msg,
326                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
327                 error("D-Bus send failed");
328                 return -EIO;
329         }
330
331         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
332         return 0;
333 }
334
335 int agent_authorize(struct agent *agent,
336                         const char *path,
337                         const char *uuid,
338                         agent_cb cb,
339                         void *user_data,
340                         GDestroyNotify destroy)
341 {
342         struct agent_request *req;
343         int err;
344
345         info("agent_authorize");
346         if (agent->request)
347                 return -EBUSY;
348
349         req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb,
350                                                         user_data, destroy);
351
352         err = agent_call_authorize(req, path, uuid);
353         if (err < 0) {
354                 agent_request_free(req, FALSE);
355                 return -ENOMEM;
356         }
357
358         agent->request = req;
359
360         DBG("authorize request was sent for %s", path);
361
362         return 0;
363 }
364
365 static void pincode_reply(DBusPendingCall *call, void *user_data)
366 {
367         struct agent_request *req = user_data;
368         struct agent *agent = req->agent;
369         struct btd_adapter *adapter = agent->adapter;
370         agent_pincode_cb cb = req->cb;
371         DBusMessage *message;
372         DBusError err;
373         bdaddr_t sba;
374         size_t len;
375         char *pin;
376
377         adapter_get_address(adapter, &sba);
378
379         /* steal_reply will always return non-NULL since the callback
380          * is only called after a reply has been received */
381         message = dbus_pending_call_steal_reply(call);
382
383         dbus_error_init(&err);
384         if (dbus_set_error_from_message(&err, message)) {
385                 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
386                                 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
387                                 request_fallback(req, pincode_reply) == 0) {
388                         dbus_error_free(&err);
389                         return;
390                 }
391
392                 error("Agent replied with an error: %s, %s",
393                                 err.name, err.message);
394
395 #ifdef __TIZEN_PATCH__
396                 if (strcmp(err.message, "CanceledbyUser") == 0)
397                 {
398                         set_cancel_from_authentication_req(req->user_data);
399                 }
400 #endif
401
402                 cb(agent, &err, NULL, req->user_data);
403                 dbus_error_free(&err);
404                 goto done;
405         }
406
407         dbus_error_init(&err);
408         if (!dbus_message_get_args(message, &err,
409                                 DBUS_TYPE_STRING, &pin,
410                                 DBUS_TYPE_INVALID)) {
411                 error("Wrong passkey reply signature: %s", err.message);
412                 cb(agent, &err, NULL, req->user_data);
413                 dbus_error_free(&err);
414                 goto done;
415         }
416
417         len = strlen(pin);
418
419         dbus_error_init(&err);
420         if (len > 16 || len < 1) {
421                 error("Invalid PIN length (%zu) from agent", len);
422                 dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs",
423                                         "Invalid passkey length");
424                 cb(agent, &err, NULL, req->user_data);
425                 dbus_error_free(&err);
426                 goto done;
427         }
428
429         cb(agent, NULL, pin, req->user_data);
430
431 done:
432         if (message)
433                 dbus_message_unref(message);
434
435         dbus_pending_call_cancel(req->call);
436         agent->request = NULL;
437         agent_request_free(req, TRUE);
438 }
439
440 static int pincode_request_new(struct agent_request *req, const char *device_path,
441                                 dbus_bool_t numeric)
442 {
443         struct agent *agent = req->agent;
444
445         req->msg = dbus_message_new_method_call(agent->name, agent->path,
446                                         "org.bluez.Agent", "RequestPinCode");
447         if (req->msg == NULL) {
448                 error("Couldn't allocate D-Bus message");
449                 return -ENOMEM;
450         }
451
452         dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
453                                         DBUS_TYPE_INVALID);
454
455         if (dbus_connection_send_with_reply(connection, req->msg,
456                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
457                 error("D-Bus send failed");
458                 return -EIO;
459         }
460
461         dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL);
462         return 0;
463 }
464
465 int agent_request_pincode(struct agent *agent, struct btd_device *device,
466                                 agent_pincode_cb cb, void *user_data,
467                                 GDestroyNotify destroy)
468 {
469         struct agent_request *req;
470         const gchar *dev_path = device_get_path(device);
471         int err;
472
473         if (agent->request)
474                 return -EBUSY;
475
476         req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
477                                                         user_data, destroy);
478
479         err = pincode_request_new(req, dev_path, FALSE);
480         if (err < 0)
481                 goto failed;
482
483         agent->request = req;
484
485         return 0;
486
487 failed:
488         g_free(req);
489         return err;
490 }
491
492 static int confirm_mode_change_request_new(struct agent_request *req,
493                                                 const char *mode)
494 {
495         struct agent *agent = req->agent;
496
497         req->msg = dbus_message_new_method_call(agent->name, agent->path,
498                                 "org.bluez.Agent", "ConfirmModeChange");
499         if (req->msg == NULL) {
500                 error("Couldn't allocate D-Bus message");
501                 return -ENOMEM;
502         }
503
504         dbus_message_append_args(req->msg,
505                                 DBUS_TYPE_STRING, &mode,
506                                 DBUS_TYPE_INVALID);
507
508         if (dbus_connection_send_with_reply(connection, req->msg,
509                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
510                 error("D-Bus send failed");
511                 return -EIO;
512         }
513
514         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
515         return 0;
516 }
517
518 int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
519                                 agent_cb cb, void *user_data,
520                                 GDestroyNotify destroy)
521 {
522         struct agent_request *req;
523         int err;
524
525         if (agent->request)
526                 return -EBUSY;
527
528         DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
529                         agent->name, agent->path, new_mode);
530
531         req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,
532                                 cb, user_data, destroy);
533
534         err = confirm_mode_change_request_new(req, new_mode);
535         if (err < 0)
536                 goto failed;
537
538         agent->request = req;
539
540         return 0;
541
542 failed:
543         agent_request_free(req, FALSE);
544         return err;
545 }
546
547 static void passkey_reply(DBusPendingCall *call, void *user_data)
548 {
549         struct agent_request *req = user_data;
550         struct agent *agent = req->agent;
551         agent_passkey_cb cb = req->cb;
552         DBusMessage *message;
553         DBusError err;
554         uint32_t passkey;
555
556         /* steal_reply will always return non-NULL since the callback
557          * is only called after a reply has been received */
558         message = dbus_pending_call_steal_reply(call);
559
560         dbus_error_init(&err);
561         if (dbus_set_error_from_message(&err, message)) {
562                 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
563                                 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
564                                 request_fallback(req, passkey_reply) == 0) {
565                         dbus_error_free(&err);
566                         return;
567                 }
568
569                 error("Agent replied with an error: %s, %s",
570                                 err.name, err.message);
571 #ifdef __TIZEN_PATCH__
572                 if (strcmp(err.message, "CanceledbyUser") == 0)
573                 {
574                         set_cancel_from_authentication_req(req->user_data);
575                 }
576 #endif
577
578                 cb(agent, &err, 0, req->user_data);
579                 dbus_error_free(&err);
580                 goto done;
581         }
582
583         dbus_error_init(&err);
584         if (!dbus_message_get_args(message, &err,
585                                 DBUS_TYPE_UINT32, &passkey,
586                                 DBUS_TYPE_INVALID)) {
587                 error("Wrong passkey reply signature: %s", err.message);
588                 cb(agent, &err, 0, req->user_data);
589                 dbus_error_free(&err);
590                 goto done;
591         }
592
593         cb(agent, NULL, passkey, req->user_data);
594
595 done:
596         if (message)
597                 dbus_message_unref(message);
598
599         dbus_pending_call_cancel(req->call);
600         agent->request = NULL;
601         agent_request_free(req, TRUE);
602 }
603
604 static int passkey_request_new(struct agent_request *req,
605                                 const char *device_path)
606 {
607         struct agent *agent = req->agent;
608
609         req->msg = dbus_message_new_method_call(agent->name, agent->path,
610                                         "org.bluez.Agent", "RequestPasskey");
611         if (req->msg == NULL) {
612                 error("Couldn't allocate D-Bus message");
613                 return -ENOMEM;
614         }
615
616         dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
617                                         DBUS_TYPE_INVALID);
618
619         if (dbus_connection_send_with_reply(connection, req->msg,
620                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
621                 error("D-Bus send failed");
622                 return -EIO;
623         }
624
625         dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
626         return 0;
627 }
628
629 int agent_request_passkey(struct agent *agent, struct btd_device *device,
630                                 agent_passkey_cb cb, void *user_data,
631                                 GDestroyNotify destroy)
632 {
633         struct agent_request *req;
634         const gchar *dev_path = device_get_path(device);
635         int err;
636
637         if (agent->request)
638                 return -EBUSY;
639
640         DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
641                         agent->name, agent->path);
642
643         req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
644                                                         user_data, destroy);
645
646         err = passkey_request_new(req, dev_path);
647         if (err < 0)
648                 goto failed;
649
650         agent->request = req;
651
652         return 0;
653
654 failed:
655         agent_request_free(req, FALSE);
656         return err;
657 }
658
659 static int confirmation_request_new(struct agent_request *req,
660                                         const char *device_path,
661                                         uint32_t passkey)
662 {
663         struct agent *agent = req->agent;
664
665         req->msg = dbus_message_new_method_call(agent->name, agent->path,
666                                 "org.bluez.Agent", "RequestConfirmation");
667         if (req->msg == NULL) {
668                 error("Couldn't allocate D-Bus message");
669                 return -ENOMEM;
670         }
671
672         dbus_message_append_args(req->msg,
673                                 DBUS_TYPE_OBJECT_PATH, &device_path,
674                                 DBUS_TYPE_UINT32, &passkey,
675                                 DBUS_TYPE_INVALID);
676
677         if (dbus_connection_send_with_reply(connection, req->msg,
678                                 &req->call, REQUEST_TIMEOUT) == FALSE) {
679                 error("D-Bus send failed");
680                 return -EIO;
681         }
682
683         dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
684
685         return 0;
686 }
687
688 int agent_request_confirmation(struct agent *agent, struct btd_device *device,
689                                 uint32_t passkey, agent_cb cb,
690                                 void *user_data, GDestroyNotify destroy)
691 {
692         struct agent_request *req;
693         const gchar *dev_path = device_get_path(device);
694         int err;
695
696         if (agent->request)
697                 return -EBUSY;
698
699         DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
700                         agent->name, agent->path, passkey);
701
702         req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
703                                 user_data, destroy);
704
705         err = confirmation_request_new(req, dev_path, passkey);
706         if (err < 0)
707                 goto failed;
708
709         agent->request = req;
710
711         return 0;
712
713 failed:
714         agent_request_free(req, FALSE);
715         return err;
716 }
717
718 static int request_fallback(struct agent_request *req,
719                                 DBusPendingCallNotifyFunction function)
720 {
721         struct btd_adapter *adapter = req->agent->adapter;
722         struct agent *adapter_agent = adapter_get_agent(adapter);
723         DBusMessage *msg;
724
725         if (req->agent == adapter_agent || adapter_agent == NULL)
726                 return -EINVAL;
727
728         dbus_pending_call_cancel(req->call);
729         dbus_pending_call_unref(req->call);
730
731         msg = dbus_message_copy(req->msg);
732
733         dbus_message_set_destination(msg, adapter_agent->name);
734         dbus_message_set_path(msg, adapter_agent->path);
735
736         if (dbus_connection_send_with_reply(connection, msg,
737                                         &req->call, REQUEST_TIMEOUT) == FALSE) {
738                 error("D-Bus send failed");
739                 dbus_message_unref(msg);
740                 return -EIO;
741         }
742
743         req->agent->request = NULL;
744         req->agent = adapter_agent;
745         req->agent->request = req;
746
747         dbus_message_unref(req->msg);
748         req->msg = msg;
749
750         dbus_pending_call_set_notify(req->call, function, req, NULL);
751
752         return 0;
753 }
754
755 int agent_display_passkey(struct agent *agent, struct btd_device *device,
756                                 uint32_t passkey)
757 {
758         DBusMessage *message;
759         const gchar *dev_path = device_get_path(device);
760
761         message = dbus_message_new_method_call(agent->name, agent->path,
762                                 "org.bluez.Agent", "DisplayPasskey");
763         if (!message) {
764                 error("Couldn't allocate D-Bus message");
765                 return -1;
766         }
767
768         dbus_message_append_args(message,
769                                 DBUS_TYPE_OBJECT_PATH, &dev_path,
770                                 DBUS_TYPE_UINT32, &passkey,
771                                 DBUS_TYPE_INVALID);
772
773         if (!g_dbus_send_message(connection, message)) {
774                 error("D-Bus send failed");
775                 dbus_message_unref(message);
776                 return -1;
777         }
778
779         return 0;
780 }
781
782 uint8_t agent_get_io_capability(struct agent *agent)
783 {
784         return agent->capability;
785 }
786
787 gboolean agent_matches(struct agent *agent, const char *name, const char *path)
788 {
789         if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path))
790                 return TRUE;
791
792         return FALSE;
793 }
794
795 gboolean agent_is_busy(struct agent *agent, void *user_data)
796 {
797         if (!agent->request)
798                 return FALSE;
799
800         if (user_data && user_data != agent->request->user_data)
801                 return FALSE;
802
803         return TRUE;
804 }
805
806 void agent_exit(void)
807 {
808         dbus_connection_unref(connection);
809         connection = NULL;
810 }
811
812 void agent_init(void)
813 {
814         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
815 }