Tethering: Add hidden access point support in technology
[platform/upstream/connman.git] / plugins / bluetooth.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2013  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 <errno.h>
27 #include <string.h>
28
29 #define CONNMAN_API_SUBJECT_TO_CHANGE
30 #include <connman/plugin.h>
31 #include <connman/dbus.h>
32 #include <connman/technology.h>
33 #include <connman/device.h>
34 #include <connman/inet.h>
35 #include <gdbus.h>
36
37 #define BLUEZ_SERVICE                   "org.bluez"
38 #define BLUEZ_PATH                      "/org/bluez"
39 #define BLUETOOTH_PAN_NAP               "00001116-0000-1000-8000-00805f9b34fb"
40
41 #define BLUETOOTH_ADDR_LEN              6
42
43 static DBusConnection *connection;
44 static GDBusClient *client;
45 static GHashTable *devices;
46 static GHashTable *networks;
47 static bool bluetooth_tethering;
48
49 struct bluetooth_pan {
50         struct connman_network *network;
51         GDBusProxy *btdevice_proxy;
52         GDBusProxy *btnetwork_proxy;
53 };
54
55 static void address2ident(const char *address, char *ident)
56 {
57         int i;
58
59         for (i = 0; i < BLUETOOTH_ADDR_LEN; i++) {
60                 ident[i * 2] = address[i * 3];
61                 ident[i * 2 + 1] = address[i * 3 + 1];
62         }
63         ident[BLUETOOTH_ADDR_LEN * 2] = '\0';
64 }
65
66 static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
67 {
68         DBusMessageIter iter;
69         const char *str;
70
71         if (!g_dbus_proxy_get_property(proxy, property, &iter))
72                 return NULL;
73         dbus_message_iter_get_basic(&iter, &str);
74         return str;
75 }
76
77 static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
78 {
79         DBusMessageIter iter;
80         dbus_bool_t value;
81
82         if (!g_dbus_proxy_get_property(proxy, property, &iter))
83                 return false;
84         dbus_message_iter_get_basic(&iter, &value);
85         return value;
86 }
87
88 static bool proxy_get_nap(GDBusProxy *proxy)
89 {
90         DBusMessageIter iter, value;
91
92         if (!proxy)
93                 return false;
94
95         if (!g_dbus_proxy_get_property(proxy, "UUIDs", &iter))
96                 return false;
97
98         dbus_message_iter_recurse(&iter, &value);
99         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
100                 const char *uuid;
101
102                 dbus_message_iter_get_basic(&value, &uuid);
103                 if (strcmp(uuid, BLUETOOTH_PAN_NAP) == 0)
104                         return true;
105
106                 dbus_message_iter_next(&value);
107         }
108
109         return false;
110 }
111
112 static int bluetooth_pan_probe(struct connman_network *network)
113 {
114         GHashTableIter iter;
115         gpointer key, value;
116
117         DBG("network %p", network);
118
119         g_hash_table_iter_init(&iter, networks);
120
121         while (g_hash_table_iter_next(&iter, &key, &value)) {
122                 struct bluetooth_pan *pan = value;
123
124                 if (network == pan->network)
125                         return 0;
126         }
127
128         return -EOPNOTSUPP;
129 }
130
131 static void pan_remove_nap(struct bluetooth_pan *pan)
132 {
133         struct connman_device *device;
134         struct connman_network *network = pan->network;
135
136         DBG("network %p pan %p", pan->network, pan);
137
138         if (!network)
139                 return;
140
141         pan->network = NULL;
142         connman_network_set_data(network, NULL);
143
144         device = connman_network_get_device(network);
145         if (device)
146                 connman_device_remove_network(device, network);
147
148         connman_network_unref(network);
149 }
150
151 static void bluetooth_pan_remove(struct connman_network *network)
152 {
153         struct bluetooth_pan *pan = connman_network_get_data(network);
154
155         DBG("network %p pan %p", network, pan);
156
157         connman_network_set_data(network, NULL);
158
159         if (pan)
160                 pan_remove_nap(pan);
161 }
162
163 static bool pan_connect(struct bluetooth_pan *pan,
164                 const char *iface)
165 {
166         int index;
167
168         if (!iface) {
169                 if (!proxy_get_bool(pan->btnetwork_proxy, "Connected"))
170                         return false;
171                 iface = proxy_get_string(pan->btnetwork_proxy, "Interface");
172         }
173
174         if (!iface)
175                 return false;
176
177         index = connman_inet_ifindex(iface);
178         if (index < 0) {
179                 DBG("network %p invalid index %d", pan->network, index);
180                 return false;
181         }
182
183         connman_network_set_index(pan->network, index);
184         connman_network_set_connected(pan->network, true);
185
186         return true;
187 }
188
189 static void pan_connect_cb(DBusMessage *message, void *user_data)
190 {
191         const char *path = user_data;
192         const char *iface = NULL;
193         struct bluetooth_pan *pan;
194         DBusMessageIter iter;
195
196         pan = g_hash_table_lookup(networks, path);
197         if (!pan) {
198                 DBG("network already removed");
199                 return;
200         }
201
202         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
203                 const char *dbus_error = dbus_message_get_error_name(message);
204
205                 DBG("network %p %s", pan->network, dbus_error);
206
207                 if (strcmp(dbus_error,
208                                 "org.bluez.Error.AlreadyConnected") != 0) {
209                         connman_network_set_error(pan->network,
210                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
211                         return;
212                 }
213         } else {
214                 if (dbus_message_iter_init(message, &iter) &&
215                                 dbus_message_iter_get_arg_type(&iter) ==
216                                 DBUS_TYPE_STRING)
217                         dbus_message_iter_get_basic(&iter, &iface);
218         }
219
220         DBG("network %p interface %s", pan->network, iface);
221
222         pan_connect(pan, iface);
223 }
224
225 static void pan_connect_append(DBusMessageIter *iter,
226                 void *user_data)
227 {
228         const char *role = BLUETOOTH_PAN_NAP;
229
230         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &role);
231 }
232
233 static int bluetooth_pan_connect(struct connman_network *network)
234 {
235         struct bluetooth_pan *pan = connman_network_get_data(network);
236         const char *path;
237
238         DBG("network %p", network);
239
240         if (!pan)
241                 return -EINVAL;
242
243         path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
244
245         if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Connect",
246                         pan_connect_append, pan_connect_cb,
247                         g_strdup(path), g_free))
248                 return -EIO;
249
250         connman_network_set_associating(pan->network, true);
251
252         return -EINPROGRESS;
253 }
254
255 static void pan_disconnect_cb(DBusMessage *message, void *user_data)
256 {
257         const char *path = user_data;
258         struct bluetooth_pan *pan;
259
260         pan = g_hash_table_lookup(networks, path);
261         if (!pan) {
262                 DBG("network already removed");
263                 return;
264         }
265
266         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
267                 const char *dbus_error = dbus_message_get_error_name(message);
268
269                 DBG("network %p %s", pan->network, dbus_error);
270         }
271
272         DBG("network %p", pan->network);
273
274         connman_network_set_connected(pan->network, false);
275 }
276
277 static int bluetooth_pan_disconnect(struct connman_network *network)
278 {
279         struct bluetooth_pan *pan = connman_network_get_data(network);
280         const char *path;
281
282         DBG("network %p", network);
283
284         if (!pan)
285                 return -EINVAL;
286
287         path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
288
289         if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Disconnect",
290                         NULL, pan_disconnect_cb, g_strdup(path), g_free))
291                 return -EIO;
292
293        return -EINPROGRESS;
294 }
295
296 static void btnetwork_property_change(GDBusProxy *proxy, const char *name,
297                 DBusMessageIter *iter, void *user_data)
298 {
299         struct bluetooth_pan *pan;
300         dbus_bool_t connected;
301         bool proxy_connected, network_connected;
302
303         if (strcmp(name, "Connected") != 0)
304                 return;
305
306         pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
307         if (!pan || !pan->network)
308                 return;
309
310         dbus_message_iter_get_basic(iter, &connected);
311         proxy_connected = connected;
312
313         network_connected = connman_network_get_connected(pan->network);
314
315         DBG("network %p network connected %d proxy connected %d",
316                         pan->network, network_connected, proxy_connected);
317
318        if (network_connected != proxy_connected)
319                connman_network_set_connected(pan->network, proxy_connected);
320 }
321
322 static void pan_create_nap(struct bluetooth_pan *pan)
323 {
324         struct connman_device *device;
325
326         if (!proxy_get_nap(pan->btdevice_proxy)) {
327                 pan_remove_nap(pan);
328                 return;
329         }
330
331         device = g_hash_table_lookup(devices,
332                         proxy_get_string(pan->btdevice_proxy, "Adapter"));
333
334         if (!device || !connman_device_get_powered(device))
335                 return;
336
337         if (!pan->network) {
338                 const char *address;
339                 char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
340                 const char *name, *path;
341
342                 address = proxy_get_string(pan->btdevice_proxy, "Address");
343                 if (!address) {
344                         connman_warn("Bluetooth device address missing");
345                         return;
346                 }
347
348                 address2ident(address, ident);
349
350                 pan->network = connman_network_create(ident,
351                                 CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
352
353                 name = proxy_get_string(pan->btdevice_proxy, "Alias");
354                 path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
355
356                 DBG("network %p %s %s", pan->network, path, name);
357
358                 if (!pan->network) {
359                         connman_warn("Bluetooth network %s creation failed",
360                                         path);
361                         return;
362                 }
363
364                 connman_network_set_data(pan->network, pan);
365                 connman_network_set_name(pan->network, name);
366                 connman_network_set_group(pan->network, ident);
367         }
368
369         connman_device_add_network(device, pan->network);
370
371         if (pan_connect(pan, NULL))
372                 DBG("network %p already connected", pan->network);
373 }
374
375 static void btdevice_property_change(GDBusProxy *proxy, const char *name,
376                 DBusMessageIter *iter, void *user_data)
377 {
378         struct bluetooth_pan *pan;
379         bool pan_nap = false;
380
381         if (strcmp(name, "UUIDs") != 0)
382                 return;
383
384         pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
385         if (!pan)
386                 return;
387
388         if (pan->network &&
389                         connman_network_get_device(pan->network))
390                 pan_nap = true;
391
392         DBG("network %p network nap %d proxy nap %d", pan->network, pan_nap,
393                         proxy_get_nap(pan->btdevice_proxy));
394
395         if (proxy_get_nap(pan->btdevice_proxy) == pan_nap)
396                 return;
397
398         pan_create_nap(pan);
399 }
400
401 static void pan_free(gpointer data)
402 {
403         struct bluetooth_pan *pan = data;
404
405         if (pan->btnetwork_proxy) {
406                 g_dbus_proxy_unref(pan->btnetwork_proxy);
407                 pan->btnetwork_proxy = NULL;
408         }
409
410         if (pan->btdevice_proxy) {
411                 g_dbus_proxy_unref(pan->btdevice_proxy);
412                 pan->btdevice_proxy = NULL;
413         }
414
415         pan_remove_nap(pan);
416
417         g_free(pan);
418 }
419
420 static void pan_create(GDBusProxy *network_proxy)
421 {
422         const char *path = g_dbus_proxy_get_path(network_proxy);
423         struct bluetooth_pan *pan;
424
425         pan = g_try_new0(struct bluetooth_pan, 1);
426
427         if (!pan) {
428                 connman_error("Out of memory creating PAN NAP");
429                 return;
430         }
431
432         g_hash_table_replace(networks, g_strdup(path), pan);
433
434         pan->btnetwork_proxy = g_dbus_proxy_ref(network_proxy);
435         pan->btdevice_proxy = g_dbus_proxy_new(client, path,
436                         "org.bluez.Device1");
437
438         if (!pan->btdevice_proxy) {
439                 connman_error("Cannot create BT PAN watcher %s", path);
440                 g_hash_table_remove(networks, path);
441                 return;
442         }
443
444         g_dbus_proxy_set_property_watch(pan->btnetwork_proxy,
445                         btnetwork_property_change, NULL);
446
447         g_dbus_proxy_set_property_watch(pan->btdevice_proxy,
448                         btdevice_property_change, NULL);
449
450         DBG("pan %p %s nap %d", pan, path, proxy_get_nap(pan->btdevice_proxy));
451
452         pan_create_nap(pan);
453 }
454
455 static struct connman_network_driver network_driver = {
456         .name           = "bluetooth",
457         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
458         .probe          = bluetooth_pan_probe,
459         .remove         = bluetooth_pan_remove,
460         .connect        = bluetooth_pan_connect,
461         .disconnect     = bluetooth_pan_disconnect,
462 };
463
464 static void enable_device(struct connman_device *device, const char *path)
465 {
466         GHashTableIter iter;
467         gpointer key, value;
468
469         DBG("device %p %s", device, path);
470         connman_device_set_powered(device, true);
471
472         g_hash_table_iter_init(&iter, networks);
473         while (g_hash_table_iter_next(&iter, &key, &value)) {
474                 struct bluetooth_pan *pan = value;
475
476                 if (g_strcmp0(proxy_get_string(pan->btdevice_proxy, "Adapter"),
477                                                 path) == 0) {
478
479                         DBG("enable network %p", pan->network);
480                         pan_create_nap(pan);
481                 }
482         }
483 }
484
485 static void device_enable_cb(const DBusError *error, void *user_data)
486 {
487         char *path = user_data;
488         struct connman_device *device;
489
490         device = g_hash_table_lookup(devices, path);
491         if (!device) {
492                 DBG("device already removed");
493                 goto out;
494         }
495
496         if (dbus_error_is_set(error)) {
497                 connman_warn("Bluetooth device %s not enabled %s",
498                                 path, error->message);
499                 goto out;
500         }
501
502         enable_device(device, path);
503 out:
504         g_free(path);
505 }
506
507 static int bluetooth_device_enable(struct connman_device *device)
508 {
509         GDBusProxy *proxy = connman_device_get_data(device);
510         dbus_bool_t device_powered = TRUE;
511         const char *path;
512
513         if (!proxy)
514                 return 0;
515
516         path = g_dbus_proxy_get_path(proxy);
517
518         if (proxy_get_bool(proxy, "Powered")) {
519                 DBG("already enabled %p %s", device, path);
520                 return -EALREADY;
521         }
522
523         DBG("device %p %s", device, path);
524
525         g_dbus_proxy_set_property_basic(proxy, "Powered",
526                         DBUS_TYPE_BOOLEAN, &device_powered,
527                         device_enable_cb, g_strdup(path), NULL);
528
529         return -EINPROGRESS;
530 }
531
532 static void disable_device(struct connman_device *device, const char *path)
533 {
534         GHashTableIter iter;
535         gpointer key, value;
536
537         DBG("device %p %s", device, path);
538         connman_device_set_powered(device, false);
539
540         g_hash_table_iter_init(&iter, networks);
541         while (g_hash_table_iter_next(&iter, &key, &value)) {
542                 struct bluetooth_pan *pan = value;
543
544                 if (pan->network && connman_network_get_device(pan->network)
545                                 == device) {
546                         DBG("disable network %p", pan->network);
547                         connman_device_remove_network(device, pan->network);
548                 }
549         }
550 }
551
552 static void device_disable_cb(const DBusError *error, void *user_data)
553 {
554         char *path = user_data;
555         struct connman_device *device;
556
557         device = g_hash_table_lookup(devices, path);
558         if (!device) {
559                 DBG("device already removed");
560                 goto out;
561         }
562
563         if (dbus_error_is_set(error)) {
564                 connman_warn("Bluetooth device %s not disabled: %s",
565                                 path, error->message);
566                 goto out;
567         }
568
569         disable_device(device, path);
570
571 out:
572         g_free(path);
573 }
574
575 static int bluetooth_device_disable(struct connman_device *device)
576 {
577         GDBusProxy *proxy = connman_device_get_data(device);
578         dbus_bool_t device_powered = FALSE;
579         const char *path;
580
581         if (!proxy)
582                 return 0;
583
584         path = g_dbus_proxy_get_path(proxy);
585
586         if (!proxy_get_bool(proxy, "Powered")) {
587                 DBG("already disabled %p %s", device, path);
588                 return -EALREADY;
589         }
590
591         DBG("device %p %s", device, path);
592
593         g_dbus_proxy_set_property_basic(proxy, "Powered",
594                         DBUS_TYPE_BOOLEAN, &device_powered,
595                         device_disable_cb, g_strdup(path), NULL);
596
597         return -EINPROGRESS;
598 }
599
600 static void adapter_property_change(GDBusProxy *proxy, const char *name,
601                 DBusMessageIter *iter, void *user_data)
602 {
603         struct connman_device *device;
604         const char *path;
605         bool adapter_powered, device_powered;
606
607         if (strcmp(name, "Powered") != 0)
608                 return;
609
610         path = g_dbus_proxy_get_path(proxy);
611         device = g_hash_table_lookup(devices, path);
612
613         adapter_powered = proxy_get_bool(proxy, "Powered");
614         device_powered = connman_device_get_powered(device);
615
616         DBG("device %p %s device powered %d adapter powered %d", device, path,
617                         device_powered, adapter_powered);
618
619         if (device_powered != adapter_powered) {
620                 if (adapter_powered)
621                         enable_device(device, path);
622                 else
623                         disable_device(device, path);
624         }
625 }
626
627 static void device_free(gpointer data)
628 {
629         struct connman_device *device = data;
630         GDBusProxy *proxy = connman_device_get_data(device);
631
632         connman_device_set_data(device, NULL);
633         if (proxy)
634                 g_dbus_proxy_unref(proxy);
635
636         connman_device_unregister(device);
637         connman_device_unref(device);
638 }
639
640 struct tethering_info {
641         struct connman_technology *technology;
642         char *bridge;
643         bool enable;
644 };
645
646 static void tethering_free(void *user_data)
647 {
648         struct tethering_info *tethering = user_data;
649
650         g_free(tethering->bridge);
651         g_free(tethering);
652 }
653
654 static void tethering_create_cb(DBusMessage *message, void *user_data)
655 {
656         struct tethering_info *tethering = user_data;
657
658         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
659                 const char *dbus_error = dbus_message_get_error_name(message);
660
661                 DBG("%s tethering failed: %s",
662                                 tethering->enable ? "enable" : "disable",
663                                 dbus_error);
664                 return;
665         }
666
667         DBG("bridge %s %s", tethering->bridge, tethering->enable ?
668                         "enabled": "disabled");
669
670         if (tethering->technology)
671                 connman_technology_tethering_notify(tethering->technology,
672                                 tethering->enable);
673 }
674
675 static void tethering_append(DBusMessageIter *iter, void *user_data)
676 {
677         struct tethering_info *tethering = user_data;
678         const char *nap = "nap";
679
680         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &nap);
681         if (tethering->enable)
682                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
683                                 &tethering->bridge);
684 }
685
686 static bool tethering_create(const char *path,
687                 struct connman_technology *technology, const char *bridge,
688                 bool enabled)
689 {
690         struct tethering_info *tethering = g_new0(struct tethering_info, 1);
691         GDBusProxy *proxy;
692         const char *method;
693         bool result;
694
695         DBG("path %s bridge %s", path, bridge);
696
697         if (!bridge)
698                 return -EINVAL;
699
700         proxy = g_dbus_proxy_new(client, path, "org.bluez.NetworkServer1");
701         if (!proxy)
702                 return false;
703
704         tethering->technology = technology;
705         tethering->bridge = g_strdup(bridge);
706         tethering->enable = enabled;
707
708         if (tethering->enable)
709                 method = "Register";
710         else
711                 method = "Unregister";
712
713         result = g_dbus_proxy_method_call(proxy, method, tethering_append,
714                         tethering_create_cb, tethering, tethering_free);
715
716         g_dbus_proxy_unref(proxy);
717
718         return result;
719 }
720
721 static void device_create(GDBusProxy *proxy)
722 {
723         struct connman_device *device = NULL;
724         const char *path = g_dbus_proxy_get_path(proxy);
725         const char *address;
726         char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
727         bool powered;
728
729         address = proxy_get_string(proxy, "Address");
730         if (!address)
731                 return;
732
733         address2ident(address, ident);
734
735         device = connman_device_create("bluetooth",
736                         CONNMAN_DEVICE_TYPE_BLUETOOTH);
737         if (!device)
738                 return;
739
740         connman_device_set_data(device, g_dbus_proxy_ref(proxy));
741         connman_device_set_ident(device, ident);
742
743         g_hash_table_replace(devices, g_strdup(path), device);
744
745         DBG("device %p %s device powered %d adapter powered %d", device,
746                         path, connman_device_get_powered(device),
747                         proxy_get_bool(proxy, "Powered"));
748
749         if (connman_device_register(device) < 0) {
750                 g_hash_table_remove(devices, device);
751                 return;
752         }
753
754         g_dbus_proxy_set_property_watch(proxy, adapter_property_change, NULL);
755
756         powered = proxy_get_bool(proxy, "Powered");
757         connman_device_set_powered(device, powered);
758
759         if (proxy_get_nap(proxy) && !bluetooth_tethering)
760                 tethering_create(path, NULL, NULL, false);
761 }
762
763 static void object_added(GDBusProxy *proxy, void *user_data)
764 {
765         const char *interface;
766
767         interface = g_dbus_proxy_get_interface(proxy);
768         if (!interface) {
769                 connman_warn("Interface or proxy missing when adding "
770                                                         "bluetooth object");
771                 return;
772         }
773
774         if (strcmp(interface, "org.bluez.Adapter1") == 0) {
775                 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
776                 device_create(proxy);
777                 return;
778         }
779
780         if (strcmp(interface, "org.bluez.Network1") == 0) {
781                 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
782                 pan_create(proxy);
783                 return;
784         }
785 }
786
787 static void object_removed(GDBusProxy *proxy, void *user_data)
788 {
789         const char *interface, *path;
790
791         interface = g_dbus_proxy_get_interface(proxy);
792         if (!interface) {
793                 connman_warn("Interface or proxy missing when removing "
794                                                         "bluetooth object");
795                 return;
796         }
797
798         if (strcmp(interface, "org.bluez.Adapter1") == 0) {
799                 path = g_dbus_proxy_get_path(proxy);
800                 DBG("%s %s", interface, path);
801
802                 g_hash_table_remove(devices, path);
803         }
804
805         if (strcmp(interface, "org.bluez.Network1") == 0) {
806                 path = g_dbus_proxy_get_path(proxy);
807                 DBG("%s %s", interface, path);
808
809                 g_hash_table_remove(networks, path);
810         }
811
812 }
813
814 static int bluetooth_device_probe(struct connman_device *device)
815 {
816         GHashTableIter iter;
817         gpointer key, value;
818
819         g_hash_table_iter_init(&iter, devices);
820
821         while (g_hash_table_iter_next(&iter, &key, &value)) {
822                 struct connman_device *known = value;
823
824                 if (device == known)
825                         return 0;
826         }
827
828         return -EOPNOTSUPP;
829 }
830
831 static void bluetooth_device_remove(struct connman_device *device)
832 {
833         DBG("%p", device);
834 }
835
836 static struct connman_device_driver device_driver = {
837         .name           = "bluetooth",
838         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
839         .probe          = bluetooth_device_probe,
840         .remove         = bluetooth_device_remove,
841         .enable         = bluetooth_device_enable,
842         .disable        = bluetooth_device_disable,
843 };
844
845 static int bluetooth_tech_probe(struct connman_technology *technology)
846 {
847         return 0;
848 }
849
850 static void bluetooth_tech_remove(struct connman_technology *technology)
851 {
852
853 }
854
855 static int bluetooth_tech_set_tethering(struct connman_technology *technology,
856                 const char *identifier, const char *passphrase,
857                 const char *bridge, bool enabled, bool hidden)
858 {
859         GHashTableIter hash_iter;
860         gpointer key, value;
861         int i = 0;
862
863         bluetooth_tethering = enabled;
864
865         g_hash_table_iter_init(&hash_iter, devices);
866
867         while (g_hash_table_iter_next(&hash_iter, &key, &value)) {
868                 const char *path = key;
869                 struct connman_device *device = value;
870
871                 DBG("device %p", device);
872
873                 if (tethering_create(path, technology, bridge, enabled)
874                                 )
875                         i++;
876         }
877
878         DBG("%s %d device(s)", enabled ? "enabled" : "disabled", i);
879
880         if (i == 0)
881                 return -ENODEV;
882
883         return 0;
884 }
885
886 static struct connman_technology_driver tech_driver = {
887         .name           = "bluetooth",
888         .type           = CONNMAN_SERVICE_TYPE_BLUETOOTH,
889         .probe          = bluetooth_tech_probe,
890         .remove         = bluetooth_tech_remove,
891         .set_tethering  = bluetooth_tech_set_tethering,
892 };
893
894 static int bluetooth_init(void)
895 {
896         connection = connman_dbus_get_connection();
897         if (!connection)
898                 goto out;
899
900         if (connman_technology_driver_register(&tech_driver) < 0) {
901                 connman_warn("Failed to initialize technology for Bluez 5");
902                 goto out;
903         }
904
905         devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
906                         device_free);
907
908         if (connman_device_driver_register(&device_driver) < 0) {
909                 connman_warn("Failed to initialize device driver for "
910                                 BLUEZ_SERVICE);
911                 connman_technology_driver_unregister(&tech_driver);
912                 goto out;
913         }
914
915         if (connman_network_driver_register(&network_driver) < 0) {
916                 connman_technology_driver_unregister(&tech_driver);
917                 connman_device_driver_unregister(&device_driver);
918                 goto out;
919         }
920
921         networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
922                         pan_free);
923
924         client = g_dbus_client_new(connection, BLUEZ_SERVICE, BLUEZ_PATH);
925         if (!client) {
926                 connman_warn("Failed to initialize D-Bus client for "
927                                 BLUEZ_SERVICE);
928                 goto out;
929         }
930
931         g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
932                         NULL, NULL);
933
934         return 0;
935
936 out:
937         if (networks)
938                 g_hash_table_destroy(networks);
939
940         if (devices)
941                 g_hash_table_destroy(devices);
942
943         if (client)
944                 g_dbus_client_unref(client);
945
946         if (connection)
947                 dbus_connection_unref(connection);
948
949         return -EIO;
950 }
951
952 static void bluetooth_exit(void)
953 {
954         /*
955          * We unset the disabling of the Bluetooth device when shutting down
956          * so that non-PAN BT connections are not affected.
957          */
958         device_driver.disable = NULL;
959
960         connman_network_driver_unregister(&network_driver);
961         g_hash_table_destroy(networks);
962
963         connman_device_driver_unregister(&device_driver);
964         g_hash_table_destroy(devices);
965
966         connman_technology_driver_unregister(&tech_driver);
967         dbus_connection_unref(connection);
968 }
969
970 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
971                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)