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