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