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;
48 struct bluetooth_pan {
49 struct connman_network *network;
50 GDBusProxy *btdevice_proxy;
51 GDBusProxy *btnetwork_proxy;
54 static void address2ident(const char *address, char *ident)
58 for (i = 0; i < BLUETOOTH_ADDR_LEN; i++) {
59 ident[i * 2] = address[i * 3];
60 ident[i * 2 + 1] = address[i * 3 + 1];
62 ident[BLUETOOTH_ADDR_LEN * 2] = '\0';
65 static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
70 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
72 dbus_message_iter_get_basic(&iter, &str);
76 static connman_bool_t proxy_get_bool(GDBusProxy *proxy, const char *property)
81 if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
83 dbus_message_iter_get_basic(&iter, &value);
87 static connman_bool_t proxy_get_nap(GDBusProxy *proxy)
89 DBusMessageIter iter, value;
94 if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
97 dbus_message_iter_recurse(&iter, &value);
98 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
101 dbus_message_iter_get_basic(&value, &uuid);
102 if (strcmp(uuid, BLUETOOTH_PAN_NAP) == 0)
105 dbus_message_iter_next(&value);
110 static int bluetooth_pan_probe(struct connman_network *network)
115 DBG("network %p", network);
117 g_hash_table_iter_init(&iter, networks);
119 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
120 struct bluetooth_pan *pan = value;
122 if (network == pan->network)
129 static void pan_remove_nap(struct bluetooth_pan *pan)
131 struct connman_device *device;
132 struct connman_network *network = pan->network;
134 DBG("network %p pan %p", pan->network, pan);
140 connman_network_set_data(network, NULL);
142 device = connman_network_get_device(network);
144 connman_device_remove_network(device, network);
146 connman_network_unref(network);
149 static void bluetooth_pan_remove(struct connman_network *network)
151 struct bluetooth_pan *pan = connman_network_get_data(network);
153 DBG("network %p pan %p", network, pan);
155 connman_network_set_data(network, NULL);
161 static int bluetooth_pan_connect(struct connman_network *network)
166 static int bluetooth_pan_disconnect(struct connman_network *network)
171 static void btnetwork_property_change(GDBusProxy *proxy, const char *name,
172 DBusMessageIter *iter, void *user_data)
174 struct bluetooth_pan *pan;
175 connman_bool_t proxy_connected;
177 if (strcmp(name, "Connected") != 0)
180 pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
184 dbus_message_iter_get_basic(iter, &proxy_connected);
186 DBG("proxy connected %d", proxy_connected);
189 static void pan_create_nap(struct bluetooth_pan *pan)
191 struct connman_device *device;
193 if (proxy_get_nap(pan->btdevice_proxy) == FALSE) {
198 device = g_hash_table_lookup(devices,
199 proxy_get_string(pan->btdevice_proxy, "Adapter"));
201 if (device == NULL || connman_device_get_powered(device) == FALSE)
204 if (pan->network == NULL) {
206 char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
207 const char *name, *path;
209 address = proxy_get_string(pan->btdevice_proxy, "Address");
210 address2ident(address, ident);
212 pan->network = connman_network_create(ident,
213 CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
215 name = proxy_get_string(pan->btdevice_proxy, "Alias");
216 path = g_dbus_proxy_get_path(pan->btnetwork_proxy);
218 DBG("network %p %s %s", pan->network, path, name);
220 if (pan->network == NULL) {
221 connman_warn("Bluetooth network %s creation failed",
226 connman_network_set_data(pan->network, pan);
227 connman_network_set_name(pan->network, name);
228 connman_network_set_group(pan->network, ident);
231 connman_device_add_network(device, pan->network);
234 static void btdevice_property_change(GDBusProxy *proxy, const char *name,
235 DBusMessageIter *iter, void *user_data)
237 struct bluetooth_pan *pan;
238 connman_bool_t pan_nap = FALSE;
240 if (strcmp(name, "UUIDs") != 0)
243 pan = g_hash_table_lookup(networks, g_dbus_proxy_get_path(proxy));
247 if (pan->network != NULL &&
248 connman_network_get_device(pan->network) != NULL)
251 DBG("network %p network nap %d proxy nap %d", pan->network, pan_nap,
252 proxy_get_nap(pan->btdevice_proxy));
254 if (proxy_get_nap(pan->btdevice_proxy) == pan_nap)
260 static void pan_free(gpointer data)
262 struct bluetooth_pan *pan = data;
264 if (pan->btnetwork_proxy != NULL) {
265 g_dbus_proxy_unref(pan->btnetwork_proxy);
266 pan->btnetwork_proxy = NULL;
269 if (pan->btdevice_proxy != NULL) {
270 g_dbus_proxy_unref(pan->btdevice_proxy);
271 pan->btdevice_proxy = NULL;
279 static void pan_create(GDBusProxy *network_proxy)
281 const char *path = g_dbus_proxy_get_path(network_proxy);
282 struct bluetooth_pan *pan;
284 pan = g_try_new0(struct bluetooth_pan, 1);
287 connman_error("Out of memory creating PAN NAP");
291 g_hash_table_replace(networks, g_strdup(path), pan);
293 pan->btnetwork_proxy = g_dbus_proxy_ref(network_proxy);
294 pan->btdevice_proxy = g_dbus_proxy_new(client, path,
295 "org.bluez.Device1");
297 if (pan->btdevice_proxy == NULL) {
298 connman_error("Cannot create BT PAN watcher %s", path);
299 g_hash_table_remove(networks, path);
303 g_dbus_proxy_set_property_watch(pan->btnetwork_proxy,
304 btnetwork_property_change, NULL);
306 g_dbus_proxy_set_property_watch(pan->btdevice_proxy,
307 btdevice_property_change, NULL);
309 DBG("pan %p %s nap %d", pan, path, proxy_get_nap(pan->btdevice_proxy));
314 static struct connman_network_driver network_driver = {
316 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
317 .probe = bluetooth_pan_probe,
318 .remove = bluetooth_pan_remove,
319 .connect = bluetooth_pan_connect,
320 .disconnect = bluetooth_pan_disconnect,
323 static void device_enable_cb(const DBusError *error, void *user_data)
325 char *path = user_data;
326 struct connman_device *device;
330 device = g_hash_table_lookup(devices, path);
331 if (device == NULL) {
332 DBG("device already removed");
336 if (dbus_error_is_set(error) == TRUE) {
337 connman_warn("Bluetooth device %s not enabled %s",
338 path, error->message);
342 DBG("device %p %s", device, path);
344 connman_device_set_powered(device, TRUE);
346 g_hash_table_iter_init(&iter, networks);
347 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
348 struct bluetooth_pan *pan = value;
350 if (g_strcmp0(proxy_get_string(pan->btdevice_proxy, "Adapter"),
353 DBG("enable network %p", pan->network);
362 static int bluetooth_device_enable(struct connman_device *device)
364 GDBusProxy *proxy = connman_device_get_data(device);
365 connman_bool_t device_powered = TRUE;
371 path = g_dbus_proxy_get_path(proxy);
373 if (proxy_get_bool(proxy, "Powered") == TRUE) {
374 DBG("already enabled %p %s", device, path);
378 DBG("device %p %s", device, path);
380 g_dbus_proxy_set_property_basic(proxy, "Powered",
381 DBUS_TYPE_BOOLEAN, &device_powered,
382 device_enable_cb, g_strdup(path), NULL);
387 static void device_disable_cb(const DBusError *error, void *user_data)
389 char *path = user_data;
390 struct connman_device *device;
394 device = g_hash_table_lookup(devices, path);
395 if (device == NULL) {
396 DBG("device already removed");
400 if (dbus_error_is_set(error) == TRUE) {
401 connman_warn("Bluetooth device %s not disabled: %s",
402 path, error->message);
406 DBG("device %p %s", device, path);
407 connman_device_set_powered(device, FALSE);
409 g_hash_table_iter_init(&iter, networks);
410 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
411 struct bluetooth_pan *pan = value;
413 if (connman_network_get_device(pan->network) == device) {
414 DBG("disable network %p", pan->network);
415 connman_device_remove_network(device, pan->network);
423 static int bluetooth_device_disable(struct connman_device *device)
425 GDBusProxy *proxy = connman_device_get_data(device);
426 connman_bool_t device_powered = FALSE;
432 path = g_dbus_proxy_get_path(proxy);
434 if (proxy_get_bool(proxy, "Powered") == FALSE) {
435 DBG("already disabled %p %s", device, path);
439 DBG("device %p %s", device, path);
441 g_dbus_proxy_set_property_basic(proxy, "Powered",
442 DBUS_TYPE_BOOLEAN, &device_powered,
443 device_disable_cb, g_strdup(path), NULL);
448 static void adapter_property_change(GDBusProxy *proxy, const char *name,
449 DBusMessageIter *iter, void *user_data)
451 struct connman_device *device;
453 connman_bool_t adapter_powered, device_powered;
455 if (strcmp(name, "Powered") != 0)
458 path = g_dbus_proxy_get_path(proxy);
459 device = g_hash_table_lookup(devices, path);
461 adapter_powered = proxy_get_bool(proxy, "Powered");
462 device_powered = connman_device_get_powered(device);
464 DBG("device %p %s device powered %d adapter powered %d", device, path,
465 device_powered, adapter_powered);
467 if (device_powered != adapter_powered) {
468 DBG("powering adapter");
469 if (device_powered == TRUE)
470 bluetooth_device_enable(device);
472 bluetooth_device_disable(device);
476 static void device_free(gpointer data)
478 struct connman_device *device = data;
479 GDBusProxy *proxy = connman_device_get_data(device);
481 connman_device_set_data(device, NULL);
483 g_dbus_proxy_unref(proxy);
485 connman_device_unregister(device);
486 connman_device_unref(device);
489 static void device_create(GDBusProxy *proxy)
491 struct connman_device *device = NULL;
492 const char *path = g_dbus_proxy_get_path(proxy);
494 char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
495 connman_bool_t powered;
497 address = proxy_get_string(proxy, "Address");
501 address2ident(address, ident);
503 device = connman_device_create("bluetooth",
504 CONNMAN_DEVICE_TYPE_BLUETOOTH);
508 connman_device_set_data(device, g_dbus_proxy_ref(proxy));
509 connman_device_set_ident(device, ident);
511 g_hash_table_replace(devices, g_strdup(path), device);
513 DBG("device %p %s device powered %d adapter powered %d", device,
514 path, connman_device_get_powered(device),
515 proxy_get_bool(proxy, "Powered"));
517 if (connman_device_register(device) < 0) {
518 g_hash_table_remove(devices, device);
522 g_dbus_proxy_set_property_watch(proxy, adapter_property_change, NULL);
524 powered = proxy_get_bool(proxy, "Powered");
525 connman_device_set_powered(device, powered);
528 static void object_added(GDBusProxy *proxy, void *user_data)
530 const char *interface;
532 interface = g_dbus_proxy_get_interface(proxy);
534 if (strcmp(interface, "org.bluez.Adapter1") == 0) {
535 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
536 device_create(proxy);
540 if (strcmp(interface, "org.bluez.Network1") == 0) {
541 DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
547 static void object_removed(GDBusProxy *proxy, void *user_data)
549 const char *interface, *path;
551 interface = g_dbus_proxy_get_interface(proxy);
553 if (strcmp(interface, "org.bluez.Adapter1") == 0) {
554 path = g_dbus_proxy_get_path(proxy);
555 DBG("%s %s", interface, path);
557 g_hash_table_remove(devices, path);
560 if (strcmp(interface, "org.bluez.Network1") == 0) {
561 path = g_dbus_proxy_get_path(proxy);
562 DBG("%s %s", interface, path);
564 g_hash_table_remove(networks, path);
569 static int bluetooth_device_probe(struct connman_device *device)
574 g_hash_table_iter_init(&iter, devices);
576 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
577 struct connman_device *known = value;
586 static void bluetooth_device_remove(struct connman_device *device)
591 static struct connman_device_driver device_driver = {
593 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
594 .probe = bluetooth_device_probe,
595 .remove = bluetooth_device_remove,
596 .enable = bluetooth_device_enable,
597 .disable = bluetooth_device_disable,
600 static int bluetooth_tech_probe(struct connman_technology *technology)
605 static void bluetooth_tech_remove(struct connman_technology *technology)
610 static struct connman_technology_driver tech_driver = {
612 .type = CONNMAN_SERVICE_TYPE_BLUETOOTH,
613 .probe = bluetooth_tech_probe,
614 .remove = bluetooth_tech_remove,
617 static int bluetooth_init(void)
619 connection = connman_dbus_get_connection();
620 if (connection == NULL)
623 if (connman_technology_driver_register(&tech_driver) < 0) {
624 connman_warn("Failed to initialize technology for Bluez 5");
628 devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
631 if (connman_device_driver_register(&device_driver) < 0) {
632 connman_warn("Failed to initialize device driver for "
634 connman_technology_driver_unregister(&tech_driver);
638 if (connman_network_driver_register(&network_driver) < 0) {
639 connman_technology_driver_unregister(&tech_driver);
640 connman_device_driver_unregister(&device_driver);
644 networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
647 client = g_dbus_client_new(connection, BLUEZ_SERVICE, BLUEZ_PATH);
648 if (client == NULL) {
649 connman_warn("Failed to initialize D-Bus client for "
654 g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
660 if (networks != NULL)
661 g_hash_table_destroy(networks);
664 g_hash_table_destroy(devices);
667 g_dbus_client_unref(client);
669 if (connection != NULL)
670 dbus_connection_unref(connection);
675 static void bluetooth_exit(void)
677 connman_network_driver_unregister(&network_driver);
678 g_hash_table_destroy(networks);
680 connman_device_driver_unregister(&device_driver);
681 g_hash_table_destroy(devices);
683 connman_technology_driver_unregister(&tech_driver);
684 dbus_connection_unref(connection);
687 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
688 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)