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