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