Remove unneeded enum connman_network_protocol
[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/technology.h>
37 #include <connman/device.h>
38 #include <connman/inet.h>
39 #include <connman/dbus.h>
40 #include <connman/log.h>
41
42 #define BLUEZ_SERVICE                   "org.bluez"
43 #define BLUEZ_MANAGER_INTERFACE         BLUEZ_SERVICE ".Manager"
44 #define BLUEZ_ADAPTER_INTERFACE         BLUEZ_SERVICE ".Adapter"
45 #define BLUEZ_DEVICE_INTERFACE          BLUEZ_SERVICE ".Device"
46 #define BLUEZ_NETWORK_INTERFACE         BLUEZ_SERVICE ".Network"
47
48 #define LIST_ADAPTERS                   "ListAdapters"
49 #define ADAPTER_ADDED                   "AdapterAdded"
50 #define ADAPTER_REMOVED                 "AdapterRemoved"
51 #define DEVICE_REMOVED                  "DeviceRemoved"
52
53 #define PROPERTY_CHANGED                "PropertyChanged"
54 #define GET_PROPERTIES                  "GetProperties"
55 #define SET_PROPERTY                    "SetProperty"
56
57 #define CONNECT                         "Connect"
58 #define DISCONNECT                      "Disconnect"
59
60 #define UUID_NAP        "00001116-0000-1000-8000-00805f9b34fb"
61
62 #define TIMEOUT 5000
63
64 static DBusConnection *connection;
65
66 static GHashTable *bluetooth_devices = NULL;
67 static GHashTable *bluetooth_networks = NULL;
68
69 static int pan_probe(struct connman_network *network)
70 {
71         DBG("network %p", network);
72
73         return 0;
74 }
75
76 static void pan_remove(struct connman_network *network)
77 {
78         DBG("network %p", network);
79 }
80
81 static void connect_reply(DBusPendingCall *call, void *user_data)
82 {
83         struct connman_network *network = user_data;
84         DBusMessage *reply;
85         DBusError error;
86         const char *interface = NULL;
87         int index;
88
89         DBG("network %p", network);
90
91         reply = dbus_pending_call_steal_reply(call);
92
93         dbus_error_init(&error);
94
95         if (dbus_set_error_from_message(&error, reply) == TRUE) {
96                 connman_error("%s", error.message);
97                 dbus_error_free(&error);
98                 goto done;
99         }
100
101         if (dbus_message_get_args(reply, &error,
102                                         DBUS_TYPE_STRING, &interface,
103                                                 DBUS_TYPE_INVALID) == FALSE) {
104                 if (dbus_error_is_set(&error) == TRUE) {
105                         connman_error("%s", error.message);
106                         dbus_error_free(&error);
107                 } else
108                         connman_error("Wrong arguments for connect");
109                 goto done;
110         }
111
112         if (interface == NULL)
113                 goto done;
114
115         DBG("interface %s", interface);
116
117         index = connman_inet_ifindex(interface);
118
119         connman_network_set_index(network, index);
120
121         connman_network_set_connected(network, TRUE);
122
123 done:
124         dbus_message_unref(reply);
125
126         dbus_pending_call_unref(call);
127 }
128
129 static int pan_connect(struct connman_network *network)
130 {
131         const char *path = connman_network_get_string(network, "Path");
132         const char *uuid = "nap";
133         DBusMessage *message;
134         DBusPendingCall *call;
135
136         DBG("network %p", network);
137
138         if (path == NULL)
139                 return -EINVAL;
140
141         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
142                                         BLUEZ_NETWORK_INTERFACE, CONNECT);
143         if (message == NULL)
144                 return -ENOMEM;
145
146         dbus_message_set_auto_start(message, FALSE);
147
148         dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
149                                                         DBUS_TYPE_INVALID);
150
151         if (dbus_connection_send_with_reply(connection, message,
152                                         &call, TIMEOUT * 10) == FALSE) {
153                 connman_error("Failed to connect service");
154                 dbus_message_unref(message);
155                 return -EINVAL;
156         }
157
158         if (call == NULL) {
159                 connman_error("D-Bus connection not available");
160                 dbus_message_unref(message);
161                 return -EINVAL;
162         }
163
164         dbus_pending_call_set_notify(call, connect_reply, network, NULL);
165
166         dbus_message_unref(message);
167
168         return -EINPROGRESS;
169 }
170
171 static void disconnect_reply(DBusPendingCall *call, void *user_data)
172 {
173         struct connman_network *network = user_data;
174         DBusMessage *reply;
175         DBusError error;
176
177         DBG("network %p", network);
178
179         reply = dbus_pending_call_steal_reply(call);
180
181         dbus_error_init(&error);
182
183         if (dbus_set_error_from_message(&error, reply) == TRUE) {
184                 connman_error("%s", error.message);
185                 dbus_error_free(&error);
186                 goto done;
187         }
188
189         if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
190                 if (dbus_error_is_set(&error) == TRUE) {
191                         connman_error("%s", error.message);
192                         dbus_error_free(&error);
193                 } else
194                         connman_error("Wrong arguments for disconnect");
195                 goto done;
196         }
197
198         connman_network_set_connected(network, FALSE);
199
200 done:
201         dbus_message_unref(reply);
202
203         dbus_pending_call_unref(call);
204
205         connman_network_unref(network);
206 }
207
208 static int pan_disconnect(struct connman_network *network)
209 {
210         const char *path = connman_network_get_string(network, "Path");
211         DBusMessage *message;
212         DBusPendingCall *call;
213
214         DBG("network %p", network);
215
216         if (path == NULL)
217                 return -EINVAL;
218
219         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
220                                         BLUEZ_NETWORK_INTERFACE, DISCONNECT);
221         if (message == NULL)
222                 return -ENOMEM;
223
224         dbus_message_set_auto_start(message, FALSE);
225
226         dbus_message_append_args(message, DBUS_TYPE_INVALID);
227
228         if (dbus_connection_send_with_reply(connection, message,
229                                                 &call, TIMEOUT) == FALSE) {
230                 connman_error("Failed to disconnect service");
231                 dbus_message_unref(message);
232                 return -EINVAL;
233         }
234
235         if (call == NULL) {
236                 connman_error("D-Bus connection not available");
237                 dbus_message_unref(message);
238                 return -EINVAL;
239         }
240
241         connman_network_ref(network);
242
243         connman_network_set_associating(network, FALSE);
244
245         dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
246
247         dbus_message_unref(message);
248
249         return 0;
250 }
251
252 static struct connman_network_driver pan_driver = {
253         .name           = "bluetooth-pan",
254         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
255         .probe          = pan_probe,
256         .remove         = pan_remove,
257         .connect        = pan_connect,
258         .disconnect     = pan_disconnect,
259 };
260
261 static gboolean network_changed(DBusConnection *connection,
262                                 DBusMessage *message, void *user_data)
263 {
264         const char *path = dbus_message_get_path(message);
265         struct connman_network *network;
266         DBusMessageIter iter, value;
267         const char *key;
268
269         DBG("path %s", path);
270
271         network = g_hash_table_lookup(bluetooth_networks, path);
272         if (network == NULL)
273                 return TRUE;
274
275         if (dbus_message_iter_init(message, &iter) == FALSE)
276                 return TRUE;
277
278         dbus_message_iter_get_basic(&iter, &key);
279
280         dbus_message_iter_next(&iter);
281         dbus_message_iter_recurse(&iter, &value);
282
283         if (g_str_equal(key, "Connected") == TRUE) {
284                 dbus_bool_t connected;
285
286                 dbus_message_iter_get_basic(&value, &connected);
287
288                 if (connected == TRUE)
289                         return TRUE;
290
291                 connman_network_set_associating(network, FALSE);
292                 connman_network_set_connected(network, FALSE);
293         }
294
295         return TRUE;
296 }
297
298 static void extract_properties(DBusMessage *reply, const char **parent,
299                                                 const char **address,
300                                                 const char **name,
301                                                 const char **alias,
302                                                 dbus_bool_t *powered,
303                                                 dbus_bool_t *scanning,
304                                                 DBusMessageIter *uuids,
305                                                 DBusMessageIter *networks)
306 {
307         DBusMessageIter array, dict;
308
309         if (dbus_message_iter_init(reply, &array) == FALSE)
310                 return;
311
312         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
313                 return;
314
315         dbus_message_iter_recurse(&array, &dict);
316
317         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
318                 DBusMessageIter entry, value;
319                 const char *key;
320
321                 dbus_message_iter_recurse(&dict, &entry);
322                 dbus_message_iter_get_basic(&entry, &key);
323
324                 dbus_message_iter_next(&entry);
325                 dbus_message_iter_recurse(&entry, &value);
326
327                 if (g_str_equal(key, "Adapter") == TRUE) {
328                         if (parent != NULL)
329                                 dbus_message_iter_get_basic(&value, parent);
330                 } else if (g_str_equal(key, "Address") == TRUE) {
331                         if (address != NULL)
332                                 dbus_message_iter_get_basic(&value, address);
333                 } else if (g_str_equal(key, "Name") == TRUE) {
334                         if (name != NULL)
335                                 dbus_message_iter_get_basic(&value, name);
336                 } else if (g_str_equal(key, "Alias") == TRUE) {
337                         if (alias != NULL)
338                                 dbus_message_iter_get_basic(&value, alias);
339                 } else if (g_str_equal(key, "Powered") == TRUE) {
340                         if (powered != NULL)
341                                 dbus_message_iter_get_basic(&value, powered);
342                 } else if (g_str_equal(key, "Discovering") == TRUE) {
343                         if (scanning != NULL)
344                                 dbus_message_iter_get_basic(&value, scanning);
345                 } else if (g_str_equal(key, "Devices") == TRUE) {
346                         if (networks != NULL)
347                                 memcpy(networks, &value, sizeof(value));
348                 } else if (g_str_equal(key, "UUIDs") == TRUE) {
349                         if (uuids != NULL)
350                                 memcpy(uuids, &value, sizeof(value));
351                 }
352
353                 dbus_message_iter_next(&dict);
354         }
355 }
356
357 static dbus_bool_t has_pan(DBusMessageIter *array)
358 {
359         DBusMessageIter value;
360
361         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
362                 return FALSE;
363
364         dbus_message_iter_recurse(array, &value);
365
366         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
367                 const char *uuid;
368
369                 dbus_message_iter_get_basic(&value, &uuid);
370
371                 if (g_strcmp0(uuid, UUID_NAP) == 0)
372                         return TRUE;
373
374                 dbus_message_iter_next(&value);
375         }
376
377         return FALSE;
378 }
379
380 static void network_properties_reply(DBusPendingCall *call, void *user_data)
381 {
382         char *path = user_data;
383         struct connman_device *device;
384         struct connman_network *network;
385         DBusMessage *reply;
386         DBusMessageIter uuids;
387         const char *parent = NULL, *address = NULL, *name = NULL;
388         struct ether_addr addr;
389         char ident[13];
390
391         reply = dbus_pending_call_steal_reply(call);
392
393         extract_properties(reply, &parent, &address, NULL, &name,
394                                                 NULL, NULL, &uuids, NULL);
395
396         if (parent == NULL)
397                 goto done;
398
399         device = g_hash_table_lookup(bluetooth_devices, parent);
400         if (device == NULL)
401                 goto done;
402
403         if (address == NULL)
404                 goto done;
405
406         ether_aton_r(address, &addr);
407
408         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
409                                                 addr.ether_addr_octet[0],
410                                                 addr.ether_addr_octet[1],
411                                                 addr.ether_addr_octet[2],
412                                                 addr.ether_addr_octet[3],
413                                                 addr.ether_addr_octet[4],
414                                                 addr.ether_addr_octet[5]);
415
416         if (has_pan(&uuids) == FALSE)
417                 goto done;
418
419         network = connman_device_get_network(device, ident);
420         if (network != NULL)
421                 goto done;
422
423         network = connman_network_create(ident,
424                                         CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
425         if (network == NULL)
426                 goto done;
427
428         connman_network_set_string(network, "Path", path);
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 gboolean device_removed(DBusConnection *connection,
537                                 DBusMessage *message, void *user_data)
538 {
539         const char *network_path, *identifier;
540         struct connman_network *network;
541         struct connman_device *device;
542         DBusMessageIter iter;
543
544         DBG("");
545
546         if (dbus_message_iter_init(message, &iter) == FALSE)
547                 return TRUE;
548
549         dbus_message_iter_get_basic(&iter, &network_path);
550
551         network = g_hash_table_lookup(bluetooth_networks, network_path);
552         if (network == NULL)
553                 return TRUE;
554
555         device = connman_network_get_device(network);
556         if (device == NULL)
557                 return TRUE;
558
559         identifier = connman_network_get_identifier(network);
560
561         g_hash_table_remove(bluetooth_networks, network_path);
562
563         connman_device_remove_network(device, identifier);
564
565         return TRUE;
566 }
567
568 static gboolean device_changed(DBusConnection *connection,
569                                 DBusMessage *message, void *user_data)
570 {
571         const char *path = dbus_message_get_path(message);
572         DBusMessageIter iter, value;
573         const char *key;
574
575         DBG("path %s", path);
576
577         if (dbus_message_iter_init(message, &iter) == FALSE)
578                 return TRUE;
579
580         dbus_message_iter_get_basic(&iter, &key);
581
582         dbus_message_iter_next(&iter);
583         dbus_message_iter_recurse(&iter, &value);
584
585         DBG("key %s", key);
586
587         if (g_str_equal(key, "UUIDs") == TRUE)
588                 add_network(NULL, path);
589
590         return TRUE;
591 }
592
593 static void adapter_properties_reply(DBusPendingCall *call, void *user_data)
594 {
595         char *path = user_data;
596         struct connman_device *device;
597         DBusMessage *reply;
598         DBusMessageIter networks;
599         const char *address = NULL, *name = NULL;
600         dbus_bool_t powered = FALSE, scanning = FALSE;
601         struct ether_addr addr;
602         char ident[13];
603
604         DBG("path %s", path);
605
606         reply = dbus_pending_call_steal_reply(call);
607
608         if (path == NULL)
609                 goto done;
610
611         extract_properties(reply, NULL, &address, &name, NULL,
612                                         &powered, &scanning, NULL, &networks);
613
614         if (address == NULL)
615                 goto done;
616
617         if (g_strcmp0(address, "00:00:00:00:00:00") == 0)
618                 goto done;
619
620         device = g_hash_table_lookup(bluetooth_devices, path);
621         if (device != NULL)
622                 goto update;
623
624         ether_aton_r(address, &addr);
625
626         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
627                                                 addr.ether_addr_octet[0],
628                                                 addr.ether_addr_octet[1],
629                                                 addr.ether_addr_octet[2],
630                                                 addr.ether_addr_octet[3],
631                                                 addr.ether_addr_octet[4],
632                                                 addr.ether_addr_octet[5]);
633
634         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
635         if (device == NULL)
636                 goto done;
637
638         connman_device_set_ident(device, ident);
639
640         connman_device_set_string(device, "Path", path);
641
642         if (connman_device_register(device) < 0) {
643                 connman_device_unref(device);
644                 goto done;
645         }
646
647         g_hash_table_insert(bluetooth_devices, g_strdup(path), device);
648
649 update:
650         connman_device_set_string(device, "Address", address);
651         connman_device_set_string(device, "Name", name);
652         connman_device_set_string(device, "Path", path);
653
654         connman_device_set_powered(device, powered);
655         connman_device_set_scanning(device, scanning);
656
657         if (powered == TRUE)
658                 check_networks(device, &networks);
659
660 done:
661         dbus_message_unref(reply);
662
663         dbus_pending_call_unref(call);
664 }
665
666 static void add_adapter(DBusConnection *connection, const char *path)
667 {
668         DBusMessage *message;
669         DBusPendingCall *call;
670
671         DBG("path %s", path);
672
673         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
674                                 BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
675         if (message == NULL)
676                 return;
677
678         dbus_message_set_auto_start(message, FALSE);
679
680         if (dbus_connection_send_with_reply(connection, message,
681                                                 &call, TIMEOUT) == FALSE) {
682                 connman_error("Failed to get adapter properties for %s", path);
683                 goto done;
684         }
685
686         if (call == NULL) {
687                 connman_error("D-Bus connection not available");
688                 goto done;
689         }
690
691         dbus_pending_call_set_notify(call, adapter_properties_reply,
692                                                 g_strdup(path), g_free);
693
694 done:
695         dbus_message_unref(message);
696 }
697
698 static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
699                                 void *user_data)
700 {
701         const char *path;
702
703         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
704                                 DBUS_TYPE_INVALID);
705         add_adapter(connection, path);
706         return TRUE;
707 }
708
709 static void remove_adapter(DBusConnection *connection, const char *path)
710 {
711         DBG("path %s", path);
712
713         g_hash_table_remove(bluetooth_devices, path);
714 }
715
716 static gboolean adapter_removed(DBusConnection *connection, DBusMessage *message,
717                                 void *user_data)
718 {
719         const char *path;
720
721         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
722                                 DBUS_TYPE_INVALID);
723         remove_adapter(connection, path);
724         return TRUE;
725 }
726
727 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
728 {
729         DBusMessage *reply;
730         DBusError error;
731         char **adapters;
732         int i, num_adapters;
733
734         DBG("");
735
736         reply = dbus_pending_call_steal_reply(call);
737
738         dbus_error_init(&error);
739
740         if (dbus_set_error_from_message(&error, reply) == TRUE) {
741                 connman_error("%s", error.message);
742                 dbus_error_free(&error);
743                 goto done;
744         }
745
746         if (dbus_message_get_args(reply, &error,
747                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
748                                                 &adapters, &num_adapters,
749                                                 DBUS_TYPE_INVALID) == FALSE) {
750                 if (dbus_error_is_set(&error) == TRUE) {
751                         connman_error("%s", error.message);
752                         dbus_error_free(&error);
753                 } else
754                         connman_error("Wrong arguments for adapter list");
755                 goto done;
756         }
757
758         for (i = 0; i < num_adapters; i++)
759                 add_adapter(connection, adapters[i]);
760
761         g_strfreev(adapters);
762
763 done:
764         dbus_message_unref(reply);
765
766         dbus_pending_call_unref(call);
767 }
768
769 static void unregister_device(gpointer data)
770 {
771         struct connman_device *device = data;
772
773         DBG("");
774
775         connman_device_unregister(device);
776         connman_device_unref(device);
777 }
778
779 static void bluetooth_connect(DBusConnection *connection, void *user_data)
780 {
781         DBusMessage *message;
782         DBusPendingCall *call;
783
784         DBG("connection %p", connection);
785
786         bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
787                                                 g_free, unregister_device);
788
789         bluetooth_networks = g_hash_table_new_full(g_str_hash, g_str_equal,
790                                                 g_free, NULL);
791
792         message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
793                                 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
794         if (message == NULL)
795                 return;
796
797         dbus_message_set_auto_start(message, FALSE);
798
799         if (dbus_connection_send_with_reply(connection, message,
800                                                 &call, TIMEOUT) == FALSE) {
801                 connman_error("Failed to get Bluetooth adapters");
802                 goto done;
803         }
804
805         if (call == NULL) {
806                 connman_error("D-Bus connection not available");
807                 goto done;
808         }
809
810         dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL);
811
812 done:
813         dbus_message_unref(message);
814 }
815
816 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
817 {
818         DBG("connection %p", connection);
819
820         if (bluetooth_devices == NULL)
821                 return;
822
823         g_hash_table_destroy(bluetooth_networks);
824         g_hash_table_destroy(bluetooth_devices);
825         bluetooth_devices = NULL;
826 }
827
828 static int bluetooth_probe(struct connman_device *device)
829 {
830         DBG("device %p", device);
831
832         return 0;
833 }
834
835 static void bluetooth_remove(struct connman_device *device)
836 {
837         DBG("device %p", device);
838 }
839
840 static void powered_reply(DBusPendingCall *call, void *user_data)
841 {
842         DBusError error;
843         DBusMessage *reply;
844
845         DBG("");
846
847         reply = dbus_pending_call_steal_reply(call);
848
849         dbus_error_init(&error);
850
851         if (dbus_set_error_from_message(&error, reply) == TRUE) {
852                 connman_error("%s", error.message);
853                 dbus_error_free(&error);
854                 dbus_message_unref(reply);
855                 dbus_pending_call_unref(call);
856                 return;
857         }
858
859         dbus_message_unref(reply);
860         dbus_pending_call_unref(call);
861
862         add_adapter(connection, user_data);
863 }
864
865 static int change_powered(DBusConnection *connection, const char *path,
866                                                         dbus_bool_t powered)
867 {
868         DBusMessage *message;
869         DBusMessageIter iter;
870         DBusPendingCall *call;
871
872         DBG("");
873
874         if (path == NULL)
875                 return -EINVAL;
876
877         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
878                                         BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
879         if (message == NULL)
880                 return -ENOMEM;
881
882         dbus_message_set_auto_start(message, FALSE);
883
884         dbus_message_iter_init_append(message, &iter);
885         connman_dbus_property_append_basic(&iter, "Powered",
886                                                 DBUS_TYPE_BOOLEAN, &powered);
887
888         if (dbus_connection_send_with_reply(connection, message,
889                                                 &call, TIMEOUT) == FALSE) {
890                 connman_error("Failed to change Powered property");
891                 dbus_message_unref(message);
892                 return -EINVAL;
893         }
894
895         if (call == NULL) {
896                 connman_error("D-Bus connection not available");
897                 dbus_message_unref(message);
898                 return -EINVAL;
899         }
900
901         dbus_pending_call_set_notify(call, powered_reply,
902                                         g_strdup(path), g_free);
903
904         dbus_message_unref(message);
905
906         return -EINPROGRESS;
907 }
908
909 static int bluetooth_enable(struct connman_device *device)
910 {
911         const char *path = connman_device_get_string(device, "Path");
912
913         DBG("device %p", device);
914
915         return change_powered(connection, path, TRUE);
916 }
917
918 static int bluetooth_disable(struct connman_device *device)
919 {
920         const char *path = connman_device_get_string(device, "Path");
921
922         DBG("device %p", device);
923
924         return change_powered(connection, path, FALSE);
925 }
926
927 static struct connman_device_driver bluetooth_driver = {
928         .name           = "bluetooth",
929         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
930         .probe          = bluetooth_probe,
931         .remove         = bluetooth_remove,
932         .enable         = bluetooth_enable,
933         .disable        = bluetooth_disable,
934 };
935
936 static int tech_probe(struct connman_technology *technology)
937 {
938         return 0;
939 }
940
941 static void tech_remove(struct connman_technology *technology)
942 {
943 }
944
945 static int tech_set_tethering(struct connman_technology *technology,
946                                                 connman_bool_t enabled)
947 {
948         return 0;
949 }
950
951 static struct connman_technology_driver tech_driver = {
952         .name           = "bluetooth",
953         .type           = CONNMAN_SERVICE_TYPE_BLUETOOTH,
954         .probe          = tech_probe,
955         .remove         = tech_remove,
956         .set_tethering  = tech_set_tethering,
957 };
958
959 static guint watch;
960 static guint added_watch;
961 static guint removed_watch;
962 static guint adapter_watch;
963 static guint device_watch;
964 static guint device_removed_watch;
965 static guint network_watch;
966
967 static int bluetooth_init(void)
968 {
969         int err;
970
971         connection = connman_dbus_get_connection();
972         if (connection == NULL)
973                 return -EIO;
974
975         watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
976                         bluetooth_connect, bluetooth_disconnect, NULL, NULL);
977
978         added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
979                                                 BLUEZ_MANAGER_INTERFACE,
980                                                 ADAPTER_ADDED, adapter_added,
981                                                 NULL, NULL);
982
983         removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
984                                                 BLUEZ_MANAGER_INTERFACE,
985                                                 ADAPTER_REMOVED, adapter_removed,
986                                                 NULL, NULL);
987
988         adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
989                                                 BLUEZ_ADAPTER_INTERFACE,
990                                                 PROPERTY_CHANGED, adapter_changed,
991                                                 NULL, NULL);
992
993         device_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
994                                                 BLUEZ_ADAPTER_INTERFACE,
995                                                 DEVICE_REMOVED, device_removed,
996                                                 NULL, NULL);
997
998         device_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
999                                                 BLUEZ_DEVICE_INTERFACE,
1000                                                 PROPERTY_CHANGED, device_changed,
1001                                                 NULL, NULL);
1002
1003         network_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1004                                                 BLUEZ_NETWORK_INTERFACE,
1005                                                 PROPERTY_CHANGED, network_changed,
1006                                                 NULL, NULL);
1007
1008         if (watch == 0 || added_watch == 0 || removed_watch == 0
1009                         || adapter_watch == 0 || network_watch == 0
1010                                 || device_watch == 0
1011                                         || device_removed_watch == 0) {
1012                 err = -EIO;
1013                 goto remove;
1014         }
1015
1016         err = connman_network_driver_register(&pan_driver);
1017         if (err < 0)
1018                 goto remove;
1019
1020         err = connman_device_driver_register(&bluetooth_driver);
1021         if (err < 0) {
1022                 connman_network_driver_unregister(&pan_driver);
1023                 goto remove;
1024         }
1025
1026         err = connman_technology_driver_register(&tech_driver);
1027         if (err < 0) {
1028                 connman_device_driver_unregister(&bluetooth_driver);
1029                 connman_network_driver_unregister(&pan_driver);
1030                 return err;
1031         }
1032
1033         return 0;
1034
1035 remove:
1036         g_dbus_remove_watch(connection, watch);
1037         g_dbus_remove_watch(connection, added_watch);
1038         g_dbus_remove_watch(connection, removed_watch);
1039         g_dbus_remove_watch(connection, adapter_watch);
1040         g_dbus_remove_watch(connection, device_removed_watch);
1041         g_dbus_remove_watch(connection, device_watch);
1042         g_dbus_remove_watch(connection, network_watch);
1043
1044         dbus_connection_unref(connection);
1045
1046         return err;
1047 }
1048
1049 static void bluetooth_exit(void)
1050 {
1051         g_dbus_remove_watch(connection, watch);
1052         g_dbus_remove_watch(connection, added_watch);
1053         g_dbus_remove_watch(connection, removed_watch);
1054         g_dbus_remove_watch(connection, adapter_watch);
1055         g_dbus_remove_watch(connection, device_removed_watch);
1056         g_dbus_remove_watch(connection, device_watch);
1057         g_dbus_remove_watch(connection, network_watch);
1058
1059         bluetooth_disconnect(connection, NULL);
1060
1061         connman_technology_driver_unregister(&tech_driver);
1062
1063         connman_device_driver_unregister(&bluetooth_driver);
1064         connman_network_driver_unregister(&pan_driver);
1065
1066         dbus_connection_unref(connection);
1067 }
1068
1069 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
1070                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)