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