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