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