5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
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
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>
37 #define BLUEZ_SERVICE "org.bluez"
38 #define BLUEZ_PATH "/org/bluez"
39 #define BLUETOOTH_PAN_NAP "00001116-0000-1000-8000-00805f9b34fb"
41 #define BLUETOOTH_ADDR_LEN 6
43 static DBusConnection *connection;
44 static GDBusClient *client;
45 static GHashTable *devices;
46 static GHashTable *networks;
47 static connman_bool_t bluetooth_tethering;
49 struct bluetooth_pan {
50 struct connman_network *network;
51 GDBusProxy *btdevice_proxy;
52 GDBusProxy *btnetwork_proxy;
55 static void address2ident(const char *address, char *ident)
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];
63 ident[BLUETOOTH_ADDR_LEN * 2] = '\0';
66 static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
71 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
73 dbus_message_iter_get_basic(&iter, &str);
77 static connman_bool_t proxy_get_bool(GDBusProxy *proxy, const char *property)
82 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
84 dbus_message_iter_get_basic(&iter, &value);
88 static connman_bool_t proxy_get_nap(GDBusProxy *proxy)
90 DBusMessageIter iter, value;
95 if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
98 dbus_message_iter_recurse(&iter, &value);
99 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
102 dbus_message_iter_get_basic(&value, &uuid);
103 if (strcmp(uuid, BLUETOOTH_PAN_NAP) == 0)
106 dbus_message_iter_next(&value);
111 static int bluetooth_pan_probe(struct connman_network *network)
116 DBG("network %p", network);
118 g_hash_table_iter_init(&iter, networks);
120 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
121 struct bluetooth_pan *pan = value;
123 if (network == pan->network)
130 static void pan_remove_nap(struct bluetooth_pan *pan)
132 struct connman_device *device;
133 struct connman_network *network = pan->network;
135 DBG("network %p pan %p", pan->network, pan);
141 connman_network_set_data(network, NULL);
143 device = connman_network_get_device(network);
145 connman_device_remove_network(device, network);
147 connman_network_unref(network);
150 static void bluetooth_pan_remove(struct connman_network *network)
152 struct bluetooth_pan *pan = connman_network_get_data(network);
154 DBG("network %p pan %p", network, pan);
156 connman_network_set_data(network, NULL);
162 static connman_bool_t pan_connect(struct bluetooth_pan *pan,
168 if (proxy_get_bool(pan->btnetwork_proxy, "Connected") == FALSE)
170 iface = proxy_get_string(pan->btnetwork_proxy, "Interface");
176 index = connman_inet_ifindex(iface);
178 DBG("network %p invalid index %d", pan->network, index);
182 connman_network_set_index(pan->network, index);
183 connman_network_set_connected(pan->network, TRUE);
188 static void pan_connect_cb(DBusMessage *message, void *user_data)
190 const char *path = user_data;
191 const char *iface = NULL;
192 struct bluetooth_pan *pan;
193 DBusMessageIter iter;
195 pan = g_hash_table_lookup(networks, path);
197 DBG("network already removed");
201 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
202 const char *dbus_error = dbus_message_get_error_name(message);
204 DBG("network %p %s", pan->network, dbus_error);
206 if (strcmp(dbus_error,
207 "org.bluez.Error.AlreadyConnected") != 0) {
208 connman_network_set_error(pan->network,
209 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
213 if (dbus_message_iter_init(message, &iter) == TRUE &&
214 dbus_message_iter_get_arg_type(&iter) ==
216 dbus_message_iter_get_basic(&iter, &iface);
219 DBG("network %p interface %s", pan->network, iface);
221 pan_connect(pan, iface);
224 static void pan_connect_append(DBusMessageIter *iter,
227 const char *role = BLUETOOTH_PAN_NAP;
229 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &role);
232 static int bluetooth_pan_connect(struct connman_network *network)
234 struct bluetooth_pan *pan = connman_network_get_data(network);
237 DBG("network %p", network);
242 path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
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)
249 connman_network_set_associating(pan->network, TRUE);
254 static void pan_disconnect_cb(DBusMessage *message, void *user_data)
256 const char *path = user_data;
257 struct bluetooth_pan *pan;
259 pan = g_hash_table_lookup(networks, path);
261 DBG("network already removed");
265 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
266 const char *dbus_error = dbus_message_get_error_name(message);
268 DBG("network %p %s", pan->network, dbus_error);
271 DBG("network %p", pan->network);
273 connman_network_set_connected(pan->network, FALSE);
276 static int bluetooth_pan_disconnect(struct connman_network *network)
278 struct bluetooth_pan *pan = connman_network_get_data(network);
281 DBG("network %p", network);
286 path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
288 if (g_dbus_proxy_method_call(pan->btnetwork_proxy, "Disconnect",
289 NULL, pan_disconnect_cb,
290 g_strdup(path), g_free) == FALSE)
296 static void btnetwork_property_change(GDBusProxy *proxy, const char *name,
297 DBusMessageIter *iter, void *user_data)
299 struct bluetooth_pan *pan;
300 connman_bool_t proxy_connected, network_connected;
302 if (strcmp(name, "Connected") != 0)
305 pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
306 if (pan == NULL || pan->network == NULL)
309 dbus_message_iter_get_basic(iter, &proxy_connected);
310 network_connected = connman_network_get_connected(pan->network);
312 DBG("network %p network connected %d proxy connected %d",
313 pan->network, network_connected, proxy_connected);
315 if (network_connected != proxy_connected)
316 connman_network_set_connected(pan->network, proxy_connected);
319 static void pan_create_nap(struct bluetooth_pan *pan)
321 struct connman_device *device;
323 if (proxy_get_nap(pan->btdevice_proxy) == FALSE) {
328 device = g_hash_table_lookup(devices,
329 proxy_get_string(pan->btdevice_proxy, "Adapter"));
331 if (device == NULL || connman_device_get_powered(device) == FALSE)
334 if (pan->network == NULL) {
336 char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
337 const char *name, *path;
339 address = proxy_get_string(pan->btdevice_proxy, "Address");
340 address2ident(address, ident);
342 pan->network = connman_network_create(ident,
343 CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
345 name = proxy_get_string(pan->btdevice_proxy, "Alias");
346 path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
348 DBG("network %p %s %s", pan->network, path, name);
350 if (pan->network == NULL) {
351 connman_warn("Bluetooth network %s creation failed",
356 connman_network_set_data(pan->network, pan);
357 connman_network_set_name(pan->network, name);
358 connman_network_set_group(pan->network, ident);
361 connman_device_add_network(device, pan->network);
363 if (pan_connect(pan, NULL) == TRUE)
364 DBG("network %p already connected", pan->network);
367 static void btdevice_property_change(GDBusProxy *proxy, const char *name,
368 DBusMessageIter *iter, void *user_data)
370 struct bluetooth_pan *pan;
371 connman_bool_t pan_nap = FALSE;
373 if (strcmp(name, "UUIDs") != 0)
376 pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
380 if (pan->network != NULL &&
381 connman_network_get_device(pan->network) != NULL)
384 DBG("network %p network nap %d proxy nap %d", pan->network, pan_nap,
385 proxy_get_nap(pan->btdevice_proxy));
387 if (proxy_get_nap(pan->btdevice_proxy) == pan_nap)
393 static void pan_free(gpointer data)
395 struct bluetooth_pan *pan = data;
397 if (pan->btnetwork_proxy != NULL) {
398 g_dbus_proxy_unref(pan->btnetwork_proxy);
399 pan->btnetwork_proxy = NULL;
402 if (pan->btdevice_proxy != NULL) {
403 g_dbus_proxy_unref(pan->btdevice_proxy);
404 pan->btdevice_proxy = NULL;
412 static void pan_create(GDBusProxy *network_proxy)
414 const char *path = g_dbus_proxy_get_path(network_proxy);
415 struct bluetooth_pan *pan;
417 pan = g_try_new0(struct bluetooth_pan, 1);
420 connman_error("Out of memory creating PAN NAP");
424 g_hash_table_replace(networks, g_strdup(path), pan);
426 pan->btnetwork_proxy = g_dbus_proxy_ref(network_proxy);
427 pan->btdevice_proxy = g_dbus_proxy_new(client, path,
428 "org.bluez.Device1");
430 if (pan->btdevice_proxy == NULL) {
431 connman_error("Cannot create BT PAN watcher %s", path);
432 g_hash_table_remove(networks, path);
436 g_dbus_proxy_set_property_watch(pan->btnetwork_proxy,
437 btnetwork_property_change, NULL);
439 g_dbus_proxy_set_property_watch(pan->btdevice_proxy,
440 btdevice_property_change, NULL);
442 DBG("pan %p %s nap %d", pan, path, proxy_get_nap(pan->btdevice_proxy));
447 static struct connman_network_driver network_driver = {
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,
456 static void device_enable_cb(const DBusError *error, void *user_data)
458 char *path = user_data;
459 struct connman_device *device;
463 device = g_hash_table_lookup(devices, path);
464 if (device == NULL) {
465 DBG("device already removed");
469 if (dbus_error_is_set(error) == TRUE) {
470 connman_warn("Bluetooth device %s not enabled %s",
471 path, error->message);
475 DBG("device %p %s", device, path);
477 connman_device_set_powered(device, TRUE);
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;
483 if (g_strcmp0(proxy_get_string(pan->btdevice_proxy, "Adapter"),
486 DBG("enable network %p", pan->network);
495 static int bluetooth_device_enable(struct connman_device *device)
497 GDBusProxy *proxy = connman_device_get_data(device);
498 connman_bool_t device_powered = TRUE;
504 path = g_dbus_proxy_get_path(proxy);
506 if (proxy_get_bool(proxy, "Powered") == TRUE) {
507 DBG("already enabled %p %s", device, path);
511 DBG("device %p %s", device, path);
513 g_dbus_proxy_set_property_basic(proxy, "Powered",
514 DBUS_TYPE_BOOLEAN, &device_powered,
515 device_enable_cb, g_strdup(path), NULL);
520 static void device_disable_cb(const DBusError *error, void *user_data)
522 char *path = user_data;
523 struct connman_device *device;
527 device = g_hash_table_lookup(devices, path);
528 if (device == NULL) {
529 DBG("device already removed");
533 if (dbus_error_is_set(error) == TRUE) {
534 connman_warn("Bluetooth device %s not disabled: %s",
535 path, error->message);
539 DBG("device %p %s", device, path);
540 connman_device_set_powered(device, FALSE);
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;
546 if (connman_network_get_device(pan->network) == device) {
547 DBG("disable network %p", pan->network);
548 connman_device_remove_network(device, pan->network);
556 static int bluetooth_device_disable(struct connman_device *device)
558 GDBusProxy *proxy = connman_device_get_data(device);
559 connman_bool_t device_powered = FALSE;
565 path = g_dbus_proxy_get_path(proxy);
567 if (proxy_get_bool(proxy, "Powered") == FALSE) {
568 DBG("already disabled %p %s", device, path);
572 DBG("device %p %s", device, path);
574 g_dbus_proxy_set_property_basic(proxy, "Powered",
575 DBUS_TYPE_BOOLEAN, &device_powered,
576 device_disable_cb, g_strdup(path), NULL);
581 static void adapter_property_change(GDBusProxy *proxy, const char *name,
582 DBusMessageIter *iter, void *user_data)
584 struct connman_device *device;
586 connman_bool_t adapter_powered, device_powered;
588 if (strcmp(name, "Powered") != 0)
591 path = g_dbus_proxy_get_path(proxy);
592 device = g_hash_table_lookup(devices, path);
594 adapter_powered = proxy_get_bool(proxy, "Powered");
595 device_powered = connman_device_get_powered(device);
597 DBG("device %p %s device powered %d adapter powered %d", device, path,
598 device_powered, adapter_powered);
600 if (device_powered != adapter_powered) {
601 DBG("powering adapter");
602 if (device_powered == TRUE)
603 bluetooth_device_enable(device);
605 bluetooth_device_disable(device);
609 static void device_free(gpointer data)
611 struct connman_device *device = data;
612 GDBusProxy *proxy = connman_device_get_data(device);
614 connman_device_set_data(device, NULL);
616 g_dbus_proxy_unref(proxy);
618 connman_device_unregister(device);
619 connman_device_unref(device);
622 struct tethering_info {
623 struct connman_technology *technology;
625 connman_bool_t enable;
628 static void tethering_free(void *user_data)
630 struct tethering_info *tethering = user_data;
632 g_free(tethering->bridge);
636 static void tethering_create_cb(DBusMessage *message, void *user_data)
638 struct tethering_info *tethering = user_data;
640 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
641 const char *dbus_error = dbus_message_get_error_name(message);
643 DBG("%s tethering failed: %s",
644 tethering->enable == TRUE? "enable": "disable",
649 DBG("bridge %s %s", tethering->bridge, tethering->enable == TRUE?
650 "enabled": "disabled");
652 if (tethering->technology != NULL)
653 connman_technology_tethering_notify(tethering->technology,
657 static void tethering_append(DBusMessageIter *iter, void *user_data)
659 struct tethering_info *tethering = user_data;
660 const char *nap = "nap";
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,
668 static connman_bool_t tethering_create(const char *path,
669 struct connman_technology *technology, const char *bridge,
670 connman_bool_t enabled)
672 struct tethering_info *tethering = g_new0(struct tethering_info, 1);
675 connman_bool_t result;
677 DBG("path %s bridge %s", path, bridge);
682 proxy = g_dbus_proxy_new(client, path, "org.bluez.NetworkServer1");
686 tethering->technology = technology;
687 tethering->bridge = g_strdup(bridge);
688 tethering->enable = enabled;
690 if (tethering->enable)
693 method = "Unregister";
695 result = g_dbus_proxy_method_call(proxy, method, tethering_append,
696 tethering_create_cb, tethering, tethering_free);
698 g_dbus_proxy_unref(proxy);
703 static void device_create(GDBusProxy *proxy)
705 struct connman_device *device = NULL;
706 const char *path = g_dbus_proxy_get_path(proxy);
708 char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
709 connman_bool_t powered;
711 address = proxy_get_string(proxy, "Address");
715 address2ident(address, ident);
717 device = connman_device_create("bluetooth",
718 CONNMAN_DEVICE_TYPE_BLUETOOTH);
722 connman_device_set_data(device, g_dbus_proxy_ref(proxy));
723 connman_device_set_ident(device, ident);
725 g_hash_table_replace(devices, g_strdup(path), device);
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"));
731 if (connman_device_register(device) < 0) {
732 g_hash_table_remove(devices, device);
736 g_dbus_proxy_set_property_watch(proxy, adapter_property_change, NULL);
738 powered = proxy_get_bool(proxy, "Powered");
739 connman_device_set_powered(device, powered);
741 if (proxy_get_nap(proxy) == TRUE && bluetooth_tethering == FALSE)
742 tethering_create(path, NULL, NULL, FALSE);
745 static void object_added(GDBusProxy *proxy, void *user_data)
747 const char *interface;
749 interface = g_dbus_proxy_get_interface(proxy);
751 if (strcmp(interface, "org.bluez.Adapter1") == 0) {
752 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
753 device_create(proxy);
757 if (strcmp(interface, "org.bluez.Network1") == 0) {
758 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
764 static void object_removed(GDBusProxy *proxy, void *user_data)
766 const char *interface, *path;
768 interface = g_dbus_proxy_get_interface(proxy);
770 if (strcmp(interface, "org.bluez.Adapter1") == 0) {
771 path = g_dbus_proxy_get_path(proxy);
772 DBG("%s %s", interface, path);
774 g_hash_table_remove(devices, path);
777 if (strcmp(interface, "org.bluez.Network1") == 0) {
778 path = g_dbus_proxy_get_path(proxy);
779 DBG("%s %s", interface, path);
781 g_hash_table_remove(networks, path);
786 static int bluetooth_device_probe(struct connman_device *device)
791 g_hash_table_iter_init(&iter, devices);
793 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
794 struct connman_device *known = value;
803 static void bluetooth_device_remove(struct connman_device *device)
808 static struct connman_device_driver device_driver = {
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,
817 static int bluetooth_tech_probe(struct connman_technology *technology)
822 static void bluetooth_tech_remove(struct connman_technology *technology)
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)
831 GHashTableIter hash_iter;
835 bluetooth_tethering = enabled;
837 g_hash_table_iter_init(&hash_iter, devices);
839 while (g_hash_table_iter_next(&hash_iter, &key, &value) == TRUE) {
840 const char *path = key;
841 struct connman_device *device = value;
843 DBG("device %p", device);
845 if (tethering_create(path, technology, bridge, enabled)
850 DBG("%s %d device(s)", enabled == TRUE? "enabled": "disabled", i);
858 static struct connman_technology_driver tech_driver = {
860 .type = CONNMAN_SERVICE_TYPE_BLUETOOTH,
861 .probe = bluetooth_tech_probe,
862 .remove = bluetooth_tech_remove,
863 .set_tethering = bluetooth_tech_set_tethering,
866 static int bluetooth_init(void)
868 connection = connman_dbus_get_connection();
869 if (connection == NULL)
872 if (connman_technology_driver_register(&tech_driver) < 0) {
873 connman_warn("Failed to initialize technology for Bluez 5");
877 devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
880 if (connman_device_driver_register(&device_driver) < 0) {
881 connman_warn("Failed to initialize device driver for "
883 connman_technology_driver_unregister(&tech_driver);
887 if (connman_network_driver_register(&network_driver) < 0) {
888 connman_technology_driver_unregister(&tech_driver);
889 connman_device_driver_unregister(&device_driver);
893 networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
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 "
903 g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
909 if (networks != NULL)
910 g_hash_table_destroy(networks);
913 g_hash_table_destroy(devices);
916 g_dbus_client_unref(client);
918 if (connection != NULL)
919 dbus_connection_unref(connection);
924 static void bluetooth_exit(void)
926 connman_network_driver_unregister(&network_driver);
927 g_hash_table_destroy(networks);
929 connman_device_driver_unregister(&device_driver);
930 g_hash_table_destroy(devices);
932 connman_technology_driver_unregister(&tech_driver);
933 dbus_connection_unref(connection);
936 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
937 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)