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