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