9a73e96f1e063c1b109a3415e7be2aba93c8c0e8
[framework/connectivity/connman.git] / plugins / bluetooth.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <netinet/ether.h>
31
32 #include <gdbus.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/technology.h>
37 #include <connman/device.h>
38 #include <connman/inet.h>
39 #include <connman/dbus.h>
40 #include <connman/log.h>
41
42 #define BLUEZ_SERVICE                   "org.bluez"
43 #define BLUEZ_MANAGER_INTERFACE         BLUEZ_SERVICE ".Manager"
44 #define BLUEZ_ADAPTER_INTERFACE         BLUEZ_SERVICE ".Adapter"
45 #define BLUEZ_DEVICE_INTERFACE          BLUEZ_SERVICE ".Device"
46 #define BLUEZ_NETWORK_INTERFACE         BLUEZ_SERVICE ".Network"
47 #define BLUEZ_NETWORK_SERVER            BLUEZ_SERVICE ".NetworkServer"
48
49 #define LIST_ADAPTERS                   "ListAdapters"
50 #define ADAPTER_ADDED                   "AdapterAdded"
51 #define ADAPTER_REMOVED                 "AdapterRemoved"
52 #define DEVICE_REMOVED                  "DeviceRemoved"
53
54 #define PROPERTY_CHANGED                "PropertyChanged"
55 #define GET_PROPERTIES                  "GetProperties"
56 #define SET_PROPERTY                    "SetProperty"
57
58 #define CONNECT                         "Connect"
59 #define DISCONNECT                      "Disconnect"
60
61 #define REGISTER                        "Register"
62 #define UNREGISTER                      "Unregister"
63
64 #define UUID_NAP        "00001116-0000-1000-8000-00805f9b34fb"
65
66 #define TIMEOUT 5000
67
68 static DBusConnection *connection;
69
70 static GHashTable *bluetooth_devices = NULL;
71 static GHashTable *bluetooth_networks = NULL;
72
73 static int pan_probe(struct connman_network *network)
74 {
75         DBG("network %p", network);
76
77         return 0;
78 }
79
80 static void pan_remove(struct connman_network *network)
81 {
82         DBG("network %p", network);
83 }
84
85 static void connect_reply(DBusPendingCall *call, void *user_data)
86 {
87         struct connman_network *network = user_data;
88         DBusMessage *reply;
89         DBusError error;
90         const char *interface = NULL;
91         int index;
92
93         DBG("network %p", network);
94
95         reply = dbus_pending_call_steal_reply(call);
96
97         dbus_error_init(&error);
98
99         if (dbus_set_error_from_message(&error, reply) == TRUE) {
100                 connman_error("%s", error.message);
101                 dbus_error_free(&error);
102                 goto done;
103         }
104
105         if (dbus_message_get_args(reply, &error,
106                                         DBUS_TYPE_STRING, &interface,
107                                                 DBUS_TYPE_INVALID) == FALSE) {
108                 if (dbus_error_is_set(&error) == TRUE) {
109                         connman_error("%s", error.message);
110                         dbus_error_free(&error);
111                 } else
112                         connman_error("Wrong arguments for connect");
113                 goto done;
114         }
115
116         if (interface == NULL)
117                 goto done;
118
119         DBG("interface %s", interface);
120
121         index = connman_inet_ifindex(interface);
122
123         connman_network_set_index(network, index);
124
125         connman_network_set_connected(network, TRUE);
126
127 done:
128         dbus_message_unref(reply);
129
130         dbus_pending_call_unref(call);
131 }
132
133 static int pan_connect(struct connman_network *network)
134 {
135         const char *path = connman_network_get_string(network, "Path");
136         const char *uuid = "nap";
137         DBusMessage *message;
138         DBusPendingCall *call;
139
140         DBG("network %p", network);
141
142         if (path == NULL)
143                 return -EINVAL;
144
145         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
146                                         BLUEZ_NETWORK_INTERFACE, CONNECT);
147         if (message == NULL)
148                 return -ENOMEM;
149
150         dbus_message_set_auto_start(message, FALSE);
151
152         dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
153                                                         DBUS_TYPE_INVALID);
154
155         if (dbus_connection_send_with_reply(connection, message,
156                                         &call, TIMEOUT * 10) == FALSE) {
157                 connman_error("Failed to connect service");
158                 dbus_message_unref(message);
159                 return -EINVAL;
160         }
161
162         if (call == NULL) {
163                 connman_error("D-Bus connection not available");
164                 dbus_message_unref(message);
165                 return -EINVAL;
166         }
167
168         dbus_pending_call_set_notify(call, connect_reply, network, NULL);
169
170         dbus_message_unref(message);
171
172         return -EINPROGRESS;
173 }
174
175 static void disconnect_reply(DBusPendingCall *call, void *user_data)
176 {
177         struct connman_network *network = user_data;
178         DBusMessage *reply;
179         DBusError error;
180
181         DBG("network %p", network);
182
183         reply = dbus_pending_call_steal_reply(call);
184
185         dbus_error_init(&error);
186
187         if (dbus_set_error_from_message(&error, reply) == TRUE) {
188                 connman_error("%s", error.message);
189                 dbus_error_free(&error);
190                 goto done;
191         }
192
193         if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
194                 if (dbus_error_is_set(&error) == TRUE) {
195                         connman_error("%s", error.message);
196                         dbus_error_free(&error);
197                 } else
198                         connman_error("Wrong arguments for disconnect");
199                 goto done;
200         }
201
202         connman_network_set_connected(network, FALSE);
203
204 done:
205         dbus_message_unref(reply);
206
207         dbus_pending_call_unref(call);
208
209         connman_network_unref(network);
210 }
211
212 static int pan_disconnect(struct connman_network *network)
213 {
214         const char *path = connman_network_get_string(network, "Path");
215         DBusMessage *message;
216         DBusPendingCall *call;
217
218         DBG("network %p", network);
219
220         if (path == NULL)
221                 return -EINVAL;
222
223         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
224                                         BLUEZ_NETWORK_INTERFACE, DISCONNECT);
225         if (message == NULL)
226                 return -ENOMEM;
227
228         dbus_message_set_auto_start(message, FALSE);
229
230         dbus_message_append_args(message, DBUS_TYPE_INVALID);
231
232         if (dbus_connection_send_with_reply(connection, message,
233                                                 &call, TIMEOUT) == FALSE) {
234                 connman_error("Failed to disconnect service");
235                 dbus_message_unref(message);
236                 return -EINVAL;
237         }
238
239         if (call == NULL) {
240                 connman_error("D-Bus connection not available");
241                 dbus_message_unref(message);
242                 return -EINVAL;
243         }
244
245         connman_network_ref(network);
246
247         connman_network_set_associating(network, FALSE);
248
249         dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
250
251         dbus_message_unref(message);
252
253         return 0;
254 }
255
256 static struct connman_network_driver pan_driver = {
257         .name           = "bluetooth-pan",
258         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
259         .probe          = pan_probe,
260         .remove         = pan_remove,
261         .connect        = pan_connect,
262         .disconnect     = pan_disconnect,
263 };
264
265 static gboolean network_changed(DBusConnection *connection,
266                                 DBusMessage *message, void *user_data)
267 {
268         const char *path = dbus_message_get_path(message);
269         struct connman_network *network;
270         DBusMessageIter iter, value;
271         const char *key;
272
273         DBG("path %s", path);
274
275         network = g_hash_table_lookup(bluetooth_networks, path);
276         if (network == NULL)
277                 return TRUE;
278
279         if (dbus_message_iter_init(message, &iter) == FALSE)
280                 return TRUE;
281
282         dbus_message_iter_get_basic(&iter, &key);
283
284         dbus_message_iter_next(&iter);
285         dbus_message_iter_recurse(&iter, &value);
286
287         if (g_str_equal(key, "Connected") == TRUE) {
288                 dbus_bool_t connected;
289
290                 dbus_message_iter_get_basic(&value, &connected);
291
292                 if (connected == TRUE)
293                         return TRUE;
294
295                 connman_network_set_associating(network, FALSE);
296                 connman_network_set_connected(network, FALSE);
297         }
298
299         return TRUE;
300 }
301
302 static void extract_properties(DBusMessage *reply, const char **parent,
303                                                 const char **address,
304                                                 const char **name,
305                                                 const char **alias,
306                                                 dbus_bool_t *powered,
307                                                 dbus_bool_t *scanning,
308                                                 DBusMessageIter *uuids,
309                                                 DBusMessageIter *networks)
310 {
311         DBusMessageIter array, dict;
312
313         if (dbus_message_iter_init(reply, &array) == FALSE)
314                 return;
315
316         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
317                 return;
318
319         dbus_message_iter_recurse(&array, &dict);
320
321         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
322                 DBusMessageIter entry, value;
323                 const char *key;
324
325                 dbus_message_iter_recurse(&dict, &entry);
326                 dbus_message_iter_get_basic(&entry, &key);
327
328                 dbus_message_iter_next(&entry);
329                 dbus_message_iter_recurse(&entry, &value);
330
331                 if (g_str_equal(key, "Adapter") == TRUE) {
332                         if (parent != NULL)
333                                 dbus_message_iter_get_basic(&value, parent);
334                 } else if (g_str_equal(key, "Address") == TRUE) {
335                         if (address != NULL)
336                                 dbus_message_iter_get_basic(&value, address);
337                 } else if (g_str_equal(key, "Name") == TRUE) {
338                         if (name != NULL)
339                                 dbus_message_iter_get_basic(&value, name);
340                 } else if (g_str_equal(key, "Alias") == TRUE) {
341                         if (alias != NULL)
342                                 dbus_message_iter_get_basic(&value, alias);
343                 } else if (g_str_equal(key, "Powered") == TRUE) {
344                         if (powered != NULL)
345                                 dbus_message_iter_get_basic(&value, powered);
346                 } else if (g_str_equal(key, "Discovering") == TRUE) {
347                         if (scanning != NULL)
348                                 dbus_message_iter_get_basic(&value, scanning);
349                 } else if (g_str_equal(key, "Devices") == TRUE) {
350                         if (networks != NULL)
351                                 memcpy(networks, &value, sizeof(value));
352                 } else if (g_str_equal(key, "UUIDs") == TRUE) {
353                         if (uuids != NULL)
354                                 memcpy(uuids, &value, sizeof(value));
355                 }
356
357                 dbus_message_iter_next(&dict);
358         }
359 }
360
361 static dbus_bool_t has_pan(DBusMessageIter *array)
362 {
363         DBusMessageIter value;
364
365         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
366                 return FALSE;
367
368         dbus_message_iter_recurse(array, &value);
369
370         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
371                 const char *uuid;
372
373                 dbus_message_iter_get_basic(&value, &uuid);
374
375                 if (g_strcmp0(uuid, UUID_NAP) == 0)
376                         return TRUE;
377
378                 dbus_message_iter_next(&value);
379         }
380
381         return FALSE;
382 }
383
384 static void network_properties_reply(DBusPendingCall *call, void *user_data)
385 {
386         char *path = user_data;
387         struct connman_device *device;
388         struct connman_network *network;
389         DBusMessage *reply;
390         DBusMessageIter uuids;
391         const char *parent = NULL, *address = NULL, *name = NULL;
392         struct ether_addr addr;
393         char ident[13];
394
395         reply = dbus_pending_call_steal_reply(call);
396
397         extract_properties(reply, &parent, &address, NULL, &name,
398                                                 NULL, NULL, &uuids, NULL);
399
400         if (parent == NULL)
401                 goto done;
402
403         device = g_hash_table_lookup(bluetooth_devices, parent);
404         if (device == NULL)
405                 goto done;
406
407         if (address == NULL)
408                 goto done;
409
410         ether_aton_r(address, &addr);
411
412         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
413                                                 addr.ether_addr_octet[0],
414                                                 addr.ether_addr_octet[1],
415                                                 addr.ether_addr_octet[2],
416                                                 addr.ether_addr_octet[3],
417                                                 addr.ether_addr_octet[4],
418                                                 addr.ether_addr_octet[5]);
419
420         if (has_pan(&uuids) == FALSE)
421                 goto done;
422
423         network = connman_device_get_network(device, ident);
424         if (network != NULL)
425                 goto done;
426
427         network = connman_network_create(ident,
428                                         CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
429         if (network == NULL)
430                 goto done;
431
432         connman_network_set_string(network, "Path", path);
433
434         connman_network_set_name(network, name);
435
436         connman_device_add_network(device, network);
437
438         connman_network_set_group(network, ident);
439
440         g_hash_table_insert(bluetooth_networks, g_strdup(path), network);
441
442 done:
443         dbus_message_unref(reply);
444
445         dbus_pending_call_unref(call);
446 }
447
448 static void add_network(struct connman_device *device, const char *path)
449 {
450         DBusMessage *message;
451         DBusPendingCall *call;
452
453         DBG("path %s", path);
454
455         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
456                                 BLUEZ_DEVICE_INTERFACE, GET_PROPERTIES);
457         if (message == NULL)
458                 return;
459
460         dbus_message_set_auto_start(message, FALSE);
461
462         if (dbus_connection_send_with_reply(connection, message,
463                                                 &call, TIMEOUT) == FALSE) {
464                 connman_error("Failed to get network properties for %s", path);
465                 goto done;
466         }
467
468         if (call == NULL) {
469                 connman_error("D-Bus connection not available");
470                 goto done;
471         }
472
473         dbus_pending_call_set_notify(call, network_properties_reply,
474                                                 g_strdup(path), g_free);
475
476 done:
477         dbus_message_unref(message);
478 }
479
480 static void check_networks(struct connman_device *device,
481                                                 DBusMessageIter *array)
482 {
483         DBusMessageIter value;
484
485         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
486                 return;
487
488         dbus_message_iter_recurse(array, &value);
489
490         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
491                 const char *path;
492
493                 dbus_message_iter_get_basic(&value, &path);
494
495                 add_network(device, path);
496
497                 dbus_message_iter_next(&value);
498         }
499 }
500
501 static gboolean adapter_changed(DBusConnection *connection,
502                                 DBusMessage *message, void *user_data)
503 {
504         const char *path = dbus_message_get_path(message);
505         struct connman_device *device;
506         DBusMessageIter iter, value;
507         const char *key;
508
509         DBG("path %s", path);
510
511         device = g_hash_table_lookup(bluetooth_devices, path);
512         if (device == NULL)
513                 return TRUE;
514
515         if (dbus_message_iter_init(message, &iter) == FALSE)
516                 return TRUE;
517
518         dbus_message_iter_get_basic(&iter, &key);
519
520         dbus_message_iter_next(&iter);
521         dbus_message_iter_recurse(&iter, &value);
522
523         if (g_str_equal(key, "Powered") == TRUE) {
524                 dbus_bool_t val;
525
526                 dbus_message_iter_get_basic(&value, &val);
527                 connman_device_set_powered(device, val);
528         } else if (g_str_equal(key, "Discovering") == TRUE) {
529                 dbus_bool_t val;
530
531                 dbus_message_iter_get_basic(&value, &val);
532                 connman_device_set_scanning(device, val);
533         } else if (g_str_equal(key, "Devices") == TRUE) {
534                 check_networks(device, &value);
535         }
536
537         return TRUE;
538 }
539
540 static gboolean device_removed(DBusConnection *connection,
541                                 DBusMessage *message, void *user_data)
542 {
543         const char *network_path, *identifier;
544         struct connman_network *network;
545         struct connman_device *device;
546         DBusMessageIter iter;
547
548         DBG("");
549
550         if (dbus_message_iter_init(message, &iter) == FALSE)
551                 return TRUE;
552
553         dbus_message_iter_get_basic(&iter, &network_path);
554
555         network = g_hash_table_lookup(bluetooth_networks, network_path);
556         if (network == NULL)
557                 return TRUE;
558
559         device = connman_network_get_device(network);
560         if (device == NULL)
561                 return TRUE;
562
563         identifier = connman_network_get_identifier(network);
564
565         g_hash_table_remove(bluetooth_networks, network_path);
566
567         connman_device_remove_network(device, identifier);
568
569         return TRUE;
570 }
571
572 static gboolean device_changed(DBusConnection *connection,
573                                 DBusMessage *message, void *user_data)
574 {
575         const char *path = dbus_message_get_path(message);
576         DBusMessageIter iter, value;
577         const char *key;
578
579         DBG("path %s", path);
580
581         if (dbus_message_iter_init(message, &iter) == FALSE)
582                 return TRUE;
583
584         dbus_message_iter_get_basic(&iter, &key);
585
586         dbus_message_iter_next(&iter);
587         dbus_message_iter_recurse(&iter, &value);
588
589         DBG("key %s", key);
590
591         if (g_str_equal(key, "UUIDs") == TRUE)
592                 add_network(NULL, path);
593
594         return TRUE;
595 }
596
597 static void adapter_properties_reply(DBusPendingCall *call, void *user_data)
598 {
599         char *path = user_data;
600         struct connman_device *device;
601         DBusMessage *reply;
602         DBusMessageIter networks;
603         const char *address = NULL, *name = NULL;
604         dbus_bool_t powered = FALSE, scanning = FALSE;
605         struct ether_addr addr;
606         char ident[13];
607
608         DBG("path %s", path);
609
610         reply = dbus_pending_call_steal_reply(call);
611
612         if (path == NULL)
613                 goto done;
614
615         extract_properties(reply, NULL, &address, &name, NULL,
616                                         &powered, &scanning, NULL, &networks);
617
618         if (address == NULL)
619                 goto done;
620
621         if (g_strcmp0(address, "00:00:00:00:00:00") == 0)
622                 goto done;
623
624         device = g_hash_table_lookup(bluetooth_devices, path);
625         if (device != NULL)
626                 goto update;
627
628         ether_aton_r(address, &addr);
629
630         snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
631                                                 addr.ether_addr_octet[0],
632                                                 addr.ether_addr_octet[1],
633                                                 addr.ether_addr_octet[2],
634                                                 addr.ether_addr_octet[3],
635                                                 addr.ether_addr_octet[4],
636                                                 addr.ether_addr_octet[5]);
637
638         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
639         if (device == NULL)
640                 goto done;
641
642         connman_device_set_ident(device, ident);
643
644         connman_device_set_string(device, "Path", path);
645
646         if (connman_device_register(device) < 0) {
647                 connman_device_unref(device);
648                 goto done;
649         }
650
651         g_hash_table_insert(bluetooth_devices, g_strdup(path), device);
652
653 update:
654         connman_device_set_string(device, "Address", address);
655         connman_device_set_string(device, "Name", name);
656         connman_device_set_string(device, "Path", path);
657
658         connman_device_set_powered(device, powered);
659         connman_device_set_scanning(device, scanning);
660
661         if (powered == TRUE)
662                 check_networks(device, &networks);
663
664 done:
665         dbus_message_unref(reply);
666
667         dbus_pending_call_unref(call);
668 }
669
670 static void add_adapter(DBusConnection *connection, const char *path)
671 {
672         DBusMessage *message;
673         DBusPendingCall *call;
674
675         DBG("path %s", path);
676
677         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
678                                 BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
679         if (message == NULL)
680                 return;
681
682         dbus_message_set_auto_start(message, FALSE);
683
684         if (dbus_connection_send_with_reply(connection, message,
685                                                 &call, TIMEOUT) == FALSE) {
686                 connman_error("Failed to get adapter properties for %s", path);
687                 goto done;
688         }
689
690         if (call == NULL) {
691                 connman_error("D-Bus connection not available");
692                 goto done;
693         }
694
695         dbus_pending_call_set_notify(call, adapter_properties_reply,
696                                                 g_strdup(path), g_free);
697
698 done:
699         dbus_message_unref(message);
700 }
701
702 static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
703                                 void *user_data)
704 {
705         const char *path;
706
707         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
708                                 DBUS_TYPE_INVALID);
709         add_adapter(connection, path);
710         return TRUE;
711 }
712
713 static void remove_adapter(DBusConnection *connection, const char *path)
714 {
715         DBG("path %s", path);
716
717         g_hash_table_remove(bluetooth_devices, path);
718 }
719
720 static gboolean adapter_removed(DBusConnection *connection, DBusMessage *message,
721                                 void *user_data)
722 {
723         const char *path;
724
725         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
726                                 DBUS_TYPE_INVALID);
727         remove_adapter(connection, path);
728         return TRUE;
729 }
730
731 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
732 {
733         DBusMessage *reply;
734         DBusError error;
735         char **adapters;
736         int i, num_adapters;
737
738         DBG("");
739
740         reply = dbus_pending_call_steal_reply(call);
741
742         dbus_error_init(&error);
743
744         if (dbus_set_error_from_message(&error, reply) == TRUE) {
745                 connman_error("%s", error.message);
746                 dbus_error_free(&error);
747                 goto done;
748         }
749
750         if (dbus_message_get_args(reply, &error,
751                                 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
752                                                 &adapters, &num_adapters,
753                                                 DBUS_TYPE_INVALID) == FALSE) {
754                 if (dbus_error_is_set(&error) == TRUE) {
755                         connman_error("%s", error.message);
756                         dbus_error_free(&error);
757                 } else
758                         connman_error("Wrong arguments for adapter list");
759                 goto done;
760         }
761
762         for (i = 0; i < num_adapters; i++)
763                 add_adapter(connection, adapters[i]);
764
765         g_strfreev(adapters);
766
767 done:
768         dbus_message_unref(reply);
769
770         dbus_pending_call_unref(call);
771 }
772
773 static void unregister_device(gpointer data)
774 {
775         struct connman_device *device = data;
776
777         DBG("");
778
779         connman_device_unregister(device);
780         connman_device_unref(device);
781 }
782
783 static void bluetooth_connect(DBusConnection *connection, void *user_data)
784 {
785         DBusMessage *message;
786         DBusPendingCall *call;
787
788         DBG("connection %p", connection);
789
790         bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
791                                                 g_free, unregister_device);
792
793         bluetooth_networks = g_hash_table_new_full(g_str_hash, g_str_equal,
794                                                 g_free, NULL);
795
796         message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
797                                 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
798         if (message == NULL)
799                 return;
800
801         dbus_message_set_auto_start(message, FALSE);
802
803         if (dbus_connection_send_with_reply(connection, message,
804                                                 &call, TIMEOUT) == FALSE) {
805                 connman_error("Failed to get Bluetooth adapters");
806                 goto done;
807         }
808
809         if (call == NULL) {
810                 connman_error("D-Bus connection not available");
811                 goto done;
812         }
813
814         dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL);
815
816 done:
817         dbus_message_unref(message);
818 }
819
820 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
821 {
822         DBG("connection %p", connection);
823
824         if (bluetooth_devices == NULL)
825                 return;
826
827         g_hash_table_destroy(bluetooth_networks);
828         g_hash_table_destroy(bluetooth_devices);
829         bluetooth_devices = NULL;
830 }
831
832 static int bluetooth_probe(struct connman_device *device)
833 {
834         DBG("device %p", device);
835
836         return 0;
837 }
838
839 static void bluetooth_remove(struct connman_device *device)
840 {
841         DBG("device %p", device);
842 }
843
844 static void powered_reply(DBusPendingCall *call, void *user_data)
845 {
846         DBusError error;
847         DBusMessage *reply;
848
849         DBG("");
850
851         reply = dbus_pending_call_steal_reply(call);
852
853         dbus_error_init(&error);
854
855         if (dbus_set_error_from_message(&error, reply) == TRUE) {
856                 connman_error("%s", error.message);
857                 dbus_error_free(&error);
858                 dbus_message_unref(reply);
859                 dbus_pending_call_unref(call);
860                 return;
861         }
862
863         dbus_message_unref(reply);
864         dbus_pending_call_unref(call);
865
866         add_adapter(connection, user_data);
867 }
868
869 static int change_powered(DBusConnection *connection, const char *path,
870                                                         dbus_bool_t powered)
871 {
872         DBusMessage *message;
873         DBusMessageIter iter;
874         DBusPendingCall *call;
875
876         DBG("");
877
878         if (path == NULL)
879                 return -EINVAL;
880
881         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
882                                         BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
883         if (message == NULL)
884                 return -ENOMEM;
885
886         dbus_message_set_auto_start(message, FALSE);
887
888         dbus_message_iter_init_append(message, &iter);
889         connman_dbus_property_append_basic(&iter, "Powered",
890                                                 DBUS_TYPE_BOOLEAN, &powered);
891
892         if (dbus_connection_send_with_reply(connection, message,
893                                                 &call, TIMEOUT) == FALSE) {
894                 connman_error("Failed to change Powered property");
895                 dbus_message_unref(message);
896                 return -EINVAL;
897         }
898
899         if (call == NULL) {
900                 connman_error("D-Bus connection not available");
901                 dbus_message_unref(message);
902                 return -EINVAL;
903         }
904
905         dbus_pending_call_set_notify(call, powered_reply,
906                                         g_strdup(path), g_free);
907
908         dbus_message_unref(message);
909
910         return -EINPROGRESS;
911 }
912
913 static int bluetooth_enable(struct connman_device *device)
914 {
915         const char *path = connman_device_get_string(device, "Path");
916
917         DBG("device %p", device);
918
919         return change_powered(connection, path, TRUE);
920 }
921
922 static int bluetooth_disable(struct connman_device *device)
923 {
924         const char *path = connman_device_get_string(device, "Path");
925
926         DBG("device %p", device);
927
928         return change_powered(connection, path, FALSE);
929 }
930
931 static struct connman_device_driver bluetooth_driver = {
932         .name           = "bluetooth",
933         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
934         .probe          = bluetooth_probe,
935         .remove         = bluetooth_remove,
936         .enable         = bluetooth_enable,
937         .disable        = bluetooth_disable,
938 };
939
940 static int tech_probe(struct connman_technology *technology)
941 {
942         return 0;
943 }
944
945 static void tech_remove(struct connman_technology *technology)
946 {
947 }
948
949 static void server_register_reply(DBusPendingCall *call, void *user_data)
950 {
951         DBusError error;
952         DBusMessage *reply;
953
954         DBG("");
955
956         reply = dbus_pending_call_steal_reply(call);
957
958         dbus_error_init(&error);
959
960         if (dbus_set_error_from_message(&error, reply) == TRUE) {
961                 connman_error("%s", error.message);
962                 dbus_error_free(&error);
963                 dbus_message_unref(reply);
964                 dbus_pending_call_unref(call);
965                 return;
966         }
967
968         dbus_message_unref(reply);
969         dbus_pending_call_unref(call);
970
971 }
972
973 static void server_register(const char *path, const char *uuid,
974                                 const char *bridge, connman_bool_t enabled)
975 {
976         DBusMessage *message;
977         DBusPendingCall *call;
978         char *command;
979
980         DBG("path %s enabled %d", path, enabled);
981
982         command = enabled ? REGISTER : UNREGISTER;
983
984         message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
985                                         BLUEZ_NETWORK_SERVER, command);
986         if (message == NULL)
987                 return;
988
989         dbus_message_set_auto_start(message, FALSE);
990
991         dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
992                                                         DBUS_TYPE_INVALID);
993
994         if (enabled == TRUE)
995                 dbus_message_append_args(message, DBUS_TYPE_STRING, &bridge,
996                                                         DBUS_TYPE_INVALID);
997
998         if (dbus_connection_send_with_reply(connection, message,
999                                                 &call, TIMEOUT) == FALSE) {
1000                 connman_error("Failed to enable PAN server");
1001                 dbus_message_unref(message);
1002                 return;
1003         }
1004
1005         if (call == NULL) {
1006                 connman_error("D-Bus connection not available");
1007                 dbus_message_unref(message);
1008                 return;
1009         }
1010
1011         dbus_pending_call_set_notify(call, server_register_reply,
1012                                         g_strdup(path), g_free);
1013
1014         dbus_message_unref(message);
1015 }
1016
1017 static void enable_nap(gpointer key, gpointer value,
1018                                                 gpointer user_data)
1019 {
1020         struct connman_device *device = value;
1021         const char *bridge = user_data;
1022         const char *path;
1023
1024         path = connman_device_get_string(device, "Path");
1025
1026         server_register(path, "nap", bridge, TRUE);
1027 }
1028
1029 static void disable_nap(gpointer key, gpointer value,
1030                                                 gpointer user_data)
1031 {
1032         struct connman_device *device = value;
1033         const char *bridge = user_data;
1034         const char *path;
1035
1036         path = connman_device_get_string(device, "Path");
1037
1038         server_register(path, "nap", bridge, FALSE);
1039 }
1040
1041 static int tech_set_tethering(struct connman_technology *technology,
1042                                 const char *bridge, connman_bool_t enabled)
1043 {
1044         char *bridge_name = g_strdup(bridge);
1045
1046         DBG("bridge %s", bridge);
1047
1048         if (bridge_name == NULL)
1049                 return -ENOMEM;
1050
1051         if (enabled)
1052                 g_hash_table_foreach(bluetooth_devices,
1053                                         enable_nap, bridge_name);
1054         else
1055                 g_hash_table_foreach(bluetooth_devices,
1056                                         disable_nap, bridge_name);
1057
1058         g_free(bridge_name);
1059
1060         return 0;
1061 }
1062
1063 static struct connman_technology_driver tech_driver = {
1064         .name           = "bluetooth",
1065         .type           = CONNMAN_SERVICE_TYPE_BLUETOOTH,
1066         .probe          = tech_probe,
1067         .remove         = tech_remove,
1068         .set_tethering  = tech_set_tethering,
1069 };
1070
1071 static guint watch;
1072 static guint added_watch;
1073 static guint removed_watch;
1074 static guint adapter_watch;
1075 static guint device_watch;
1076 static guint device_removed_watch;
1077 static guint network_watch;
1078
1079 static int bluetooth_init(void)
1080 {
1081         int err;
1082
1083         connection = connman_dbus_get_connection();
1084         if (connection == NULL)
1085                 return -EIO;
1086
1087         watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
1088                         bluetooth_connect, bluetooth_disconnect, NULL, NULL);
1089
1090         added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1091                                                 BLUEZ_MANAGER_INTERFACE,
1092                                                 ADAPTER_ADDED, adapter_added,
1093                                                 NULL, NULL);
1094
1095         removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1096                                                 BLUEZ_MANAGER_INTERFACE,
1097                                                 ADAPTER_REMOVED, adapter_removed,
1098                                                 NULL, NULL);
1099
1100         adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1101                                                 BLUEZ_ADAPTER_INTERFACE,
1102                                                 PROPERTY_CHANGED, adapter_changed,
1103                                                 NULL, NULL);
1104
1105         device_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1106                                                 BLUEZ_ADAPTER_INTERFACE,
1107                                                 DEVICE_REMOVED, device_removed,
1108                                                 NULL, NULL);
1109
1110         device_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1111                                                 BLUEZ_DEVICE_INTERFACE,
1112                                                 PROPERTY_CHANGED, device_changed,
1113                                                 NULL, NULL);
1114
1115         network_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1116                                                 BLUEZ_NETWORK_INTERFACE,
1117                                                 PROPERTY_CHANGED, network_changed,
1118                                                 NULL, NULL);
1119
1120         if (watch == 0 || added_watch == 0 || removed_watch == 0
1121                         || adapter_watch == 0 || network_watch == 0
1122                                 || device_watch == 0
1123                                         || device_removed_watch == 0) {
1124                 err = -EIO;
1125                 goto remove;
1126         }
1127
1128         err = connman_network_driver_register(&pan_driver);
1129         if (err < 0)
1130                 goto remove;
1131
1132         err = connman_device_driver_register(&bluetooth_driver);
1133         if (err < 0) {
1134                 connman_network_driver_unregister(&pan_driver);
1135                 goto remove;
1136         }
1137
1138         err = connman_technology_driver_register(&tech_driver);
1139         if (err < 0) {
1140                 connman_device_driver_unregister(&bluetooth_driver);
1141                 connman_network_driver_unregister(&pan_driver);
1142                 return err;
1143         }
1144
1145         return 0;
1146
1147 remove:
1148         g_dbus_remove_watch(connection, watch);
1149         g_dbus_remove_watch(connection, added_watch);
1150         g_dbus_remove_watch(connection, removed_watch);
1151         g_dbus_remove_watch(connection, adapter_watch);
1152         g_dbus_remove_watch(connection, device_removed_watch);
1153         g_dbus_remove_watch(connection, device_watch);
1154         g_dbus_remove_watch(connection, network_watch);
1155
1156         dbus_connection_unref(connection);
1157
1158         return err;
1159 }
1160
1161 static void bluetooth_exit(void)
1162 {
1163         g_dbus_remove_watch(connection, watch);
1164         g_dbus_remove_watch(connection, added_watch);
1165         g_dbus_remove_watch(connection, removed_watch);
1166         g_dbus_remove_watch(connection, adapter_watch);
1167         g_dbus_remove_watch(connection, device_removed_watch);
1168         g_dbus_remove_watch(connection, device_watch);
1169         g_dbus_remove_watch(connection, network_watch);
1170
1171         bluetooth_disconnect(connection, NULL);
1172
1173         connman_technology_driver_unregister(&tech_driver);
1174
1175         connman_device_driver_unregister(&bluetooth_driver);
1176         connman_network_driver_unregister(&pan_driver);
1177
1178         dbus_connection_unref(connection);
1179 }
1180
1181 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
1182                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)