Remove obsolete file.
[connman] / plugins / bluetooth.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28
29 #include <gdbus.h>
30
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/device.h>
34 #include <connman/inet.h>
35 #include <connman/dbus.h>
36 #include <connman/log.h>
37
38 #define BLUEZ_SERVICE                   "org.bluez"
39 #define BLUEZ_MANAGER_INTERFACE         BLUEZ_SERVICE ".Manager"
40 #define BLUEZ_ADAPTER_INTERFACE         BLUEZ_SERVICE ".Adapter"
41 #define BLUEZ_DEVICE_INTERFACE          BLUEZ_SERVICE ".Device"
42 #define BLUEZ_NETWORK_INTERFACE         BLUEZ_SERVICE ".Network"
43
44 #define LIST_ADAPTERS                   "ListAdapters"
45 #define ADAPTER_ADDED                   "AdapterAdded"
46 #define ADAPTER_REMOVED                 "AdapterRemoved"
47
48 #define PROPERTY_CHANGED                "PropertyChanged"
49 #define GET_PROPERTIES                  "GetProperties"
50 #define SET_PROPERTY                    "SetProperty"
51
52 #define CONNECT                         "Connect"
53 #define DISCONNECT                      "Disconnect"
54
55 #define TIMEOUT 5000
56
57 typedef void (* properties_callback_t) (DBusConnection *connection,
58                                                         const char *path,
59                                                         DBusMessage *message,
60                                                         void *user_data);
61
62 struct properties_data {
63         DBusConnection *connection;
64         DBusMessage *message;
65         properties_callback_t callback;
66         void *user_data;
67 };
68
69 static void get_properties_reply(DBusPendingCall *call, void *user_data)
70 {
71         struct properties_data *data = user_data;
72         DBusMessage *reply;
73         const char *path;
74
75         reply = dbus_pending_call_steal_reply(call);
76         if (reply == NULL)
77                 goto done;
78
79         path = dbus_message_get_path(data->message);
80
81         data->callback(data->connection, path, reply, data->user_data);
82
83         dbus_message_unref(reply);
84
85 done:
86         dbus_message_unref(data->message);
87         g_free(data);
88 }
89
90 static void get_properties(DBusConnection *connection,
91                                 const char *path, const char *interface,
92                                 properties_callback_t callback, void *user_data)
93 {
94         struct properties_data *data;
95         DBusMessage *message;
96         DBusPendingCall *call;
97
98         DBG("path %s interface %s", path, interface);
99
100         data = g_try_new0(struct properties_data, 1);
101         if (data == NULL)
102                 return;
103
104         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
105                                                 interface, GET_PROPERTIES);
106         if (message == NULL) {
107                 g_free(data);
108                 return;
109         }
110
111         if (dbus_connection_send_with_reply(connection, message,
112                                                 &call, TIMEOUT) == FALSE) {
113                 connman_error("Failed to get properties for %s", interface);
114                 dbus_message_unref(message);
115                 g_free(data);
116                 return;
117         }
118
119         if (call == NULL) {
120                 connman_error("D-Bus connection not available");
121                 dbus_message_unref(message);
122                 g_free(data);
123                 return;
124         }
125
126         data->connection = connection;
127         data->message    = message;
128         data->callback   = callback;
129         data->user_data  = user_data;
130
131         dbus_pending_call_set_notify(call, get_properties_reply, data, NULL);
132 }
133
134 struct adapter_data {
135         DBusConnection *connection;
136 };
137
138 struct network_data {
139         DBusConnection *connection;
140         char *interface;
141 };
142
143 static int pan_probe(struct connman_network *network)
144 {
145         struct connman_device *device = connman_network_get_device(network);
146         struct adapter_data *adapter;
147         struct network_data *data;
148
149         DBG("network %p", network);
150
151         if (device == NULL)
152                 return -EINVAL;
153
154         adapter = connman_device_get_data(device);
155         if (adapter == NULL)
156                 return -EINVAL;
157
158         data = g_try_new0(struct network_data, 1);
159         if (data == NULL)
160                 return -ENOMEM;
161
162         data->connection = adapter->connection;
163
164         connman_network_set_data(network, data);
165
166         return 0;
167 }
168
169 static void pan_remove(struct connman_network *network)
170 {
171         struct network_data *data = connman_network_get_data(network);
172
173         DBG("network %p", network);
174
175         connman_network_set_data(network, NULL);
176
177         g_free(data);
178 }
179
180 static void connect_reply(DBusPendingCall *call, void *user_data)
181 {
182         struct connman_network *network = user_data;
183         struct network_data *data = connman_network_get_data(network);
184         DBusMessage *reply;
185         DBusError error;
186         const char *interface = NULL;
187         int index;
188
189         DBG("network %p", network);
190
191         reply = dbus_pending_call_steal_reply(call);
192         if (reply == NULL)
193                 return;
194
195         dbus_error_init(&error);
196
197         if (dbus_message_get_args(reply, &error,
198                                         DBUS_TYPE_STRING, &interface,
199                                                 DBUS_TYPE_INVALID) == FALSE) {
200                 if (dbus_error_is_set(&error) == TRUE) {
201                         connman_error("%s", error.message);
202                         dbus_error_free(&error);
203                 } else
204                         connman_error("Wrong arguments for connect");
205                 goto done;
206         }
207
208         if (interface == NULL)
209                 goto done;
210
211         DBG("interface %s", interface);
212
213         data->interface = g_strdup(interface);
214
215         index = connman_inet_ifindex(interface);
216
217         connman_network_set_index(network, index);
218         connman_network_set_connected(network, TRUE);
219
220 done:
221         dbus_message_unref(reply);
222 }
223
224 static int pan_connect(struct connman_network *network)
225 {
226         struct network_data *data = connman_network_get_data(network);
227         const char *path = connman_network_get_string(network, "Node");
228         const char *uuid = "nap";
229         DBusMessage *message;
230         DBusPendingCall *call;
231
232         DBG("network %p", network);
233
234         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
235                                         BLUEZ_NETWORK_INTERFACE, CONNECT);
236         if (message == NULL)
237                 return -ENOMEM;
238
239         dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
240                                                         DBUS_TYPE_INVALID);
241
242         if (dbus_connection_send_with_reply(data->connection, message,
243                                         &call, TIMEOUT * 10) == FALSE) {
244                 connman_error("Failed to connect service");
245                 dbus_message_unref(message);
246                 return -EINVAL;
247         }
248
249         if (call == NULL) {
250                 connman_error("D-Bus connection not available");
251                 dbus_message_unref(message);
252                 return -EINVAL;
253         }
254
255         dbus_pending_call_set_notify(call, connect_reply, network, NULL);
256
257         dbus_message_unref(message);
258
259         return -EINPROGRESS;
260 }
261
262 static void disconnect_reply(DBusPendingCall *call, void *user_data)
263 {
264         struct connman_network *network = user_data;
265         struct network_data *data = connman_network_get_data(network);
266         DBusMessage *reply;
267         DBusError error;
268
269         DBG("network %p", network);
270
271         reply = dbus_pending_call_steal_reply(call);
272         if (reply == NULL)
273                 return;
274
275         dbus_error_init(&error);
276
277         if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
278                 if (dbus_error_is_set(&error) == TRUE) {
279                         connman_error("%s", error.message);
280                         dbus_error_free(&error);
281                 } else
282                         connman_error("Wrong arguments for disconnect");
283                 goto done;
284         }
285
286         g_free(data->interface);
287         data->interface = NULL;
288
289         connman_network_set_connected(network, FALSE);
290         connman_network_set_index(network, -1);
291
292 done:
293         dbus_message_unref(reply);
294 }
295
296 static int pan_disconnect(struct connman_network *network)
297 {
298         struct network_data *data = connman_network_get_data(network);
299         const char *path = connman_network_get_string(network, "Node");
300         DBusMessage *message;
301         DBusPendingCall *call;
302
303         DBG("network %p", network);
304
305         if (data->interface == NULL)
306                 return -EINVAL;
307
308         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
309                                         BLUEZ_NETWORK_INTERFACE, DISCONNECT);
310         if (message == NULL)
311                 return -ENOMEM;
312
313         dbus_message_append_args(message, DBUS_TYPE_INVALID);
314
315         if (dbus_connection_send_with_reply(data->connection, message,
316                                                 &call, TIMEOUT) == FALSE) {
317                 connman_error("Failed to disconnect service");
318                 dbus_message_unref(message);
319                 return -EINVAL;
320         }
321
322         if (call == NULL) {
323                 connman_error("D-Bus connection not available");
324                 dbus_message_unref(message);
325                 return -EINVAL;
326         }
327
328         dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
329
330         dbus_message_unref(message);
331
332         return -EINPROGRESS;
333 }
334
335 static struct connman_network_driver pan_driver = {
336         .name           = "bluetooth-pan",
337         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
338         .probe          = pan_probe,
339         .remove         = pan_remove,
340         .connect        = pan_connect,
341         .disconnect     = pan_disconnect,
342 };
343
344 static int bluetooth_probe(struct connman_device *adapter)
345 {
346         struct adapter_data *data;
347
348         DBG("adapter %p", adapter);
349
350         data = g_try_new0(struct adapter_data, 1);
351         if (data == NULL)
352                 return -ENOMEM;
353
354         data->connection = connman_dbus_get_connection();
355         if (data->connection == NULL) {
356                 g_free(data);
357                 return -EIO;
358         }
359
360         connman_device_set_data(adapter, data);
361
362         return 0;
363 }
364
365 static void bluetooth_remove(struct connman_device *adapter)
366 {
367         struct adapter_data *data = connman_device_get_data(adapter);
368
369         DBG("adapter %p", adapter);
370
371         connman_device_set_data(adapter, NULL);
372
373         dbus_connection_unref(data->connection);
374
375         g_free(data);
376 }
377
378 static void powered_reply(DBusPendingCall *call, void *user_data)
379 {
380         DBusMessage *reply;
381
382         DBG("");
383
384         reply = dbus_pending_call_steal_reply(call);
385
386         dbus_message_unref(reply);
387 }
388
389 static int change_powered(DBusConnection *connection, const char *path,
390                                                         dbus_bool_t powered)
391 {
392         DBusMessage *message;
393         DBusMessageIter iter;
394         DBusPendingCall *call;
395
396         DBG("");
397
398         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
399                                         BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
400         if (message == NULL)
401                 return -ENOMEM;
402
403         dbus_message_iter_init_append(message, &iter);
404         connman_dbus_property_append_variant(&iter, "Powered",
405                                                 DBUS_TYPE_BOOLEAN, &powered);
406
407         if (dbus_connection_send_with_reply(connection, message,
408                                                 &call, TIMEOUT) == FALSE) {
409                 connman_error("Failed to change Powered property");
410                 dbus_message_unref(message);
411                 return -EINVAL;
412         }
413
414         if (call == NULL) {
415                 connman_error("D-Bus connection not available");
416                 dbus_message_unref(message);
417                 return -EINVAL;
418         }
419
420         dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
421
422         dbus_message_unref(message);
423
424         return -EINPROGRESS;
425 }
426
427 static int bluetooth_enable(struct connman_device *adapter)
428 {
429         struct adapter_data *data = connman_device_get_data(adapter);
430         const char *path = connman_device_get_string(adapter, "Node");
431
432         DBG("adapter %p", adapter);
433
434         return change_powered(data->connection, path, TRUE);
435 }
436
437 static int bluetooth_disable(struct connman_device *adapter)
438 {
439         struct adapter_data *data = connman_device_get_data(adapter);
440         const char *path = connman_device_get_string(adapter, "Node");
441
442         DBG("adapter %p", adapter);
443
444         return change_powered(data->connection, path, FALSE);
445 }
446
447 static int bluetooth_scan(struct connman_device *adapter)
448 {
449         DBG("adapter %p", adapter);
450
451         return -EIO;
452 }
453
454 static struct connman_device_driver bluetooth_driver = {
455         .name           = "bluetooth",
456         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
457         .probe          = bluetooth_probe,
458         .remove         = bluetooth_remove,
459         .enable         = bluetooth_enable,
460         .disable        = bluetooth_disable,
461         .scan           = bluetooth_scan,
462 };
463
464 static GSList *adapter_list = NULL;
465
466 static void free_adapters(void)
467 {
468         GSList *list;
469
470         DBG("");
471
472         for (list = adapter_list; list; list = list->next) {
473                 struct connman_device *adapter = list->data;
474
475                 connman_device_unregister(adapter);
476                 connman_device_unref(adapter);
477         }
478
479         g_slist_free(adapter_list);
480         adapter_list = NULL;
481 }
482
483 static struct connman_device *find_adapter(const char *path)
484 {
485         GSList *list;
486
487         DBG("path %s", path);
488
489         for (list = adapter_list; list; list = list->next) {
490                 struct connman_device *adapter = list->data;
491                 const char *adapter_path = connman_device_get_string(adapter,
492                                                                         "Node");
493
494                 if (adapter_path == NULL)
495                         continue;
496
497                 if (g_str_equal(adapter_path, path) == TRUE)
498                         return adapter;
499         }
500
501         return NULL;
502 }
503
504 static void device_properties(DBusConnection *connection, const char *path,
505                                 DBusMessage *message, void *user_data)
506 {
507         struct connman_device *device = user_data;
508         const char *node = g_basename(path);
509         struct connman_network *network;
510
511         DBG("path %s", path);
512
513         network = connman_device_get_network(device, node);
514         if (network != NULL)
515                 return;
516
517         network = connman_network_create(node,
518                                         CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
519         if (network == NULL)
520                 return;
521
522         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
523
524         connman_network_set_string(network, "Node", path);
525
526         connman_device_add_network(device, network);
527 }
528
529 static void check_devices(struct connman_device *adapter,
530                         DBusConnection *connection, DBusMessageIter *array)
531 {
532         DBusMessageIter value;
533
534         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
535                 return;
536
537         dbus_message_iter_recurse(array, &value);
538
539         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
540                 const char *path;
541
542                 dbus_message_iter_get_basic(&value, &path);
543
544                 get_properties(connection, path, BLUEZ_DEVICE_INTERFACE,
545                                                 device_properties, adapter);
546
547                 dbus_message_iter_next(&value);
548         }
549 }
550
551 static void property_changed(DBusConnection *connection, DBusMessage *message)
552 {
553         const char *path = dbus_message_get_path(message);
554         struct connman_device *adapter;
555         DBusMessageIter iter, value;
556         const char *key;
557
558         DBG("path %s", path);
559
560         adapter = find_adapter(path);
561         if (adapter == NULL)
562                 return;
563
564         if (dbus_message_iter_init(message, &iter) == FALSE)
565                 return;
566
567         dbus_message_iter_get_basic(&iter, &key);
568
569         dbus_message_iter_next(&iter);
570         dbus_message_iter_recurse(&iter, &value);
571
572         if (g_str_equal(key, "Powered") == TRUE) {
573                 gboolean val;
574
575                 dbus_message_iter_get_basic(&value, &val);
576                 connman_device_set_powered(adapter, val);
577         } else if (g_str_equal(key, "Discovering") == TRUE) {
578                 gboolean val;
579
580                 dbus_message_iter_get_basic(&value, &val);
581                 connman_device_set_scanning(adapter, val);
582         }
583 }
584
585 static void parse_adapter_properties(struct connman_device *adapter,
586                                                 DBusConnection *connection,
587                                                         DBusMessage *reply)
588 {
589         DBusMessageIter array, dict;
590
591         if (dbus_message_iter_init(reply, &array) == FALSE)
592                 return;
593
594         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
595                 return;
596
597         dbus_message_iter_recurse(&array, &dict);
598
599         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
600                 DBusMessageIter entry, value;
601                 const char *key;
602
603                 dbus_message_iter_recurse(&dict, &entry);
604                 dbus_message_iter_get_basic(&entry, &key);
605
606                 dbus_message_iter_next(&entry);
607                 dbus_message_iter_recurse(&entry, &value);
608
609                 if (g_str_equal(key, "Powered") == TRUE) {
610                         gboolean val;
611
612                         dbus_message_iter_get_basic(&value, &val);
613                         connman_device_set_powered(adapter, val);
614                 } else if (g_str_equal(key, "Discovering") == TRUE) {
615                         gboolean val;
616
617                         dbus_message_iter_get_basic(&value, &val);
618                         connman_device_set_scanning(adapter, val);
619                 } else if (g_str_equal(key, "Devices") == TRUE) {
620                         check_devices(adapter, connection, &value);
621                 }
622
623                 dbus_message_iter_next(&dict);
624         }
625 }
626
627 static void adapter_properties(DBusConnection *connection, const char *path,
628                                 DBusMessage *message, void *user_data)
629 {
630         const char *node = g_basename(path);
631         struct connman_device *adapter;
632
633         DBG("path %s", path);
634
635         adapter = find_adapter(path);
636         if (adapter != NULL)
637                 goto done;
638
639         adapter = connman_device_create(node, CONNMAN_DEVICE_TYPE_BLUETOOTH);
640         if (adapter == NULL)
641                 return;
642
643         connman_device_set_string(adapter, "Node", path);
644
645         if (node != NULL && g_str_has_prefix(node, "hci") == TRUE) {
646                 int index;
647                 errno = 0;
648                 index = atoi(node + 3);
649                 if (errno == 0)
650                         connman_device_set_index(adapter, index);
651         }
652
653         connman_device_set_interface(adapter, node);
654
655         connman_device_set_policy(adapter, CONNMAN_DEVICE_POLICY_MANUAL);
656         connman_device_set_mode(adapter, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
657
658         if (connman_device_register(adapter) < 0) {
659                 connman_device_unref(adapter);
660                 return;
661         }
662
663         adapter_list = g_slist_append(adapter_list, adapter);
664
665 done:
666         parse_adapter_properties(adapter, connection, message);
667 }
668
669 static void add_adapter(DBusConnection *connection, const char *path)
670 {
671         DBG("path %s", path);
672
673         get_properties(connection, path, BLUEZ_ADAPTER_INTERFACE,
674                                                 adapter_properties, NULL);
675 }
676
677 static void remove_adapter(DBusConnection *connection, const char *path)
678 {
679         struct connman_device *adapter;
680
681         DBG("path %s", path);
682
683         adapter = find_adapter(path);
684         if (adapter == NULL)
685                 return;
686
687         adapter_list = g_slist_remove(adapter_list, adapter);
688
689         connman_device_unregister(adapter);
690         connman_device_unref(adapter);
691 }
692
693 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
694 {
695         DBusConnection *connection = user_data;
696         DBusMessage *reply;
697         DBusError error;
698         char **adapters;
699         int i, num_adapters;
700
701         DBG("");
702
703         reply = dbus_pending_call_steal_reply(call);
704
705         dbus_error_init(&error);
706
707         if (dbus_message_get_args(reply, &error,
708                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
709                                                 &adapters, &num_adapters,
710                                                 DBUS_TYPE_INVALID) == FALSE) {
711                 if (dbus_error_is_set(&error) == TRUE) {
712                         connman_error("%s", error.message);
713                         dbus_error_free(&error);
714                 } else
715                         connman_error("Wrong arguments for adapter list");
716                 goto done;
717         }
718
719         for (i = 0; i < num_adapters; i++)
720                 get_properties(connection, adapters[i],
721                                         BLUEZ_ADAPTER_INTERFACE,
722                                                 adapter_properties, NULL);
723
724         g_strfreev(adapters);
725
726 done:
727         dbus_message_unref(reply);
728 }
729
730 static void bluetooth_connect(DBusConnection *connection, void *user_data)
731 {
732         DBusMessage *message;
733         DBusPendingCall *call;
734
735         DBG("connection %p", connection);
736
737         message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
738                                 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
739         if (message == NULL)
740                 return;
741
742         if (dbus_connection_send_with_reply(connection, message,
743                                                 &call, TIMEOUT) == FALSE) {
744                 connman_error("Failed to get Bluetooth adapters");
745                 goto done;
746         }
747
748         if (call == NULL) {
749                 connman_error("D-Bus connection not available");
750                 goto done;
751         }
752
753         dbus_pending_call_set_notify(call, list_adapters_reply,
754                                                         connection, NULL);
755
756 done:
757         dbus_message_unref(message);
758 }
759
760 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
761 {
762         DBG("connection %p", connection);
763
764         free_adapters();
765 }
766
767 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
768                                         DBusMessage *message, void *user_data)
769 {
770         if (dbus_message_has_interface(message,
771                         BLUEZ_MANAGER_INTERFACE) == FALSE &&
772                                 dbus_message_has_interface(message,
773                                         BLUEZ_ADAPTER_INTERFACE) == FALSE)
774                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
775
776         DBG("connection %p", connection);
777
778         if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
779                                                 PROPERTY_CHANGED) == TRUE) {
780                 property_changed(connection, message);
781         } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
782                                                 ADAPTER_ADDED) == TRUE) {
783                 const char *path;
784                 dbus_message_get_args(message, NULL,
785                                         DBUS_TYPE_OBJECT_PATH, &path,
786                                                         DBUS_TYPE_INVALID);
787                 add_adapter(connection, path);
788         } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
789                                                 ADAPTER_REMOVED) == TRUE) {
790                 const char *path;
791                 dbus_message_get_args(message, NULL,
792                                         DBUS_TYPE_OBJECT_PATH, &path,
793                                                         DBUS_TYPE_INVALID);
794                 remove_adapter(connection, path);
795         }
796
797         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
798 }
799
800 static DBusConnection *connection;
801 static guint watch;
802
803 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
804                                         ",interface=" BLUEZ_MANAGER_INTERFACE;
805 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
806                                         ",interface=" BLUEZ_MANAGER_INTERFACE;
807
808 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
809                                         ",interface=" BLUEZ_ADAPTER_INTERFACE;
810
811 static int bluetooth_init(void)
812 {
813         int err = -EIO;
814
815         connection = connman_dbus_get_connection();
816         if (connection == NULL)
817                 return -EIO;
818
819         if (dbus_connection_add_filter(connection, bluetooth_signal,
820                                                         NULL, NULL) == FALSE)
821                 goto unref;
822
823         err = connman_network_driver_register(&pan_driver);
824         if (err < 0)
825                 goto remove;
826
827         err = connman_device_driver_register(&bluetooth_driver);
828         if (err < 0) {
829                 connman_network_driver_unregister(&pan_driver);
830                 goto remove;
831         }
832
833         watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
834                         bluetooth_connect, bluetooth_disconnect, NULL, NULL);
835         if (watch == 0) {
836                 connman_device_driver_unregister(&bluetooth_driver);
837                 connman_network_driver_unregister(&pan_driver);
838                 err = -EIO;
839                 goto remove;
840         }
841
842         if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
843                 bluetooth_connect(connection, NULL);
844
845         dbus_bus_add_match(connection, added_rule, NULL);
846         dbus_bus_add_match(connection, removed_rule, NULL);
847         dbus_bus_add_match(connection, adapter_rule, NULL);
848         dbus_connection_flush(connection);
849
850         return 0;
851
852 remove:
853         dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
854
855 unref:
856         dbus_connection_unref(connection);
857
858         return err;
859 }
860
861 static void bluetooth_exit(void)
862 {
863         dbus_bus_remove_match(connection, adapter_rule, NULL);
864         dbus_bus_remove_match(connection, removed_rule, NULL);
865         dbus_bus_remove_match(connection, added_rule, NULL);
866         dbus_connection_flush(connection);
867
868         g_dbus_remove_watch(connection, watch);
869
870         free_adapters();
871
872         connman_device_driver_unregister(&bluetooth_driver);
873         connman_network_driver_unregister(&pan_driver);
874
875         dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
876
877         dbus_connection_unref(connection);
878 }
879
880 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
881                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)