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