5 * Copyright (C) 2007-2010 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
30 #include <netinet/ether.h>
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/device.h>
37 #include <connman/inet.h>
38 #include <connman/dbus.h>
39 #include <connman/log.h>
41 #define BLUEZ_SERVICE "org.bluez"
42 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
43 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
44 #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
45 #define BLUEZ_NETWORK_INTERFACE BLUEZ_SERVICE ".Network"
47 #define LIST_ADAPTERS "ListAdapters"
48 #define ADAPTER_ADDED "AdapterAdded"
49 #define ADAPTER_REMOVED "AdapterRemoved"
51 #define PROPERTY_CHANGED "PropertyChanged"
52 #define GET_PROPERTIES "GetProperties"
53 #define SET_PROPERTY "SetProperty"
55 #define CONNECT "Connect"
56 #define DISCONNECT "Disconnect"
58 #define UUID_NAP "00001116-0000-1000-8000-00805f9b34fb"
62 static DBusConnection *connection;
64 static GHashTable *bluetooth_devices = NULL;
66 static int pan_probe(struct connman_network *network)
68 DBG("network %p", network);
73 static void pan_remove(struct connman_network *network)
75 DBG("network %p", network);
78 static void connect_reply(DBusPendingCall *call, void *user_data)
80 struct connman_network *network = user_data;
83 const char *interface = NULL;
86 DBG("network %p", network);
88 reply = dbus_pending_call_steal_reply(call);
90 dbus_error_init(&error);
92 if (dbus_message_get_args(reply, &error,
93 DBUS_TYPE_STRING, &interface,
94 DBUS_TYPE_INVALID) == FALSE) {
95 if (dbus_error_is_set(&error) == TRUE) {
96 connman_error("%s", error.message);
97 dbus_error_free(&error);
99 connman_error("Wrong arguments for connect");
103 if (interface == NULL)
106 DBG("interface %s", interface);
108 index = connman_inet_ifindex(interface);
110 connman_network_set_index(network, index);
112 connman_network_set_method(network, CONNMAN_IPCONFIG_METHOD_DHCP);
114 connman_network_set_connected(network, TRUE);
117 dbus_message_unref(reply);
119 dbus_pending_call_unref(call);
122 static int pan_connect(struct connman_network *network)
124 const char *path = connman_network_get_string(network, "Path");
125 const char *uuid = "nap";
126 DBusMessage *message;
127 DBusPendingCall *call;
129 DBG("network %p", network);
134 if (connman_network_get_index(network) >= 0)
137 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
138 BLUEZ_NETWORK_INTERFACE, CONNECT);
142 dbus_message_set_auto_start(message, FALSE);
144 dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
147 if (dbus_connection_send_with_reply(connection, message,
148 &call, TIMEOUT * 10) == FALSE) {
149 connman_error("Failed to connect service");
150 dbus_message_unref(message);
155 connman_error("D-Bus connection not available");
156 dbus_message_unref(message);
160 dbus_pending_call_set_notify(call, connect_reply, network, NULL);
162 dbus_message_unref(message);
167 static void disconnect_reply(DBusPendingCall *call, void *user_data)
169 struct connman_network *network = user_data;
173 DBG("network %p", network);
175 reply = dbus_pending_call_steal_reply(call);
177 dbus_error_init(&error);
179 if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
180 if (dbus_error_is_set(&error) == TRUE) {
181 connman_error("%s", error.message);
182 dbus_error_free(&error);
184 connman_error("Wrong arguments for disconnect");
188 connman_network_set_connected(network, FALSE);
189 connman_network_set_index(network, -1);
192 dbus_message_unref(reply);
194 dbus_pending_call_unref(call);
197 static int pan_disconnect(struct connman_network *network)
199 const char *path = connman_network_get_string(network, "Path");
200 DBusMessage *message;
201 DBusPendingCall *call;
203 DBG("network %p", network);
208 if (connman_network_get_index(network) < 0)
211 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
212 BLUEZ_NETWORK_INTERFACE, DISCONNECT);
216 dbus_message_set_auto_start(message, FALSE);
218 dbus_message_append_args(message, DBUS_TYPE_INVALID);
220 if (dbus_connection_send_with_reply(connection, message,
221 &call, TIMEOUT) == FALSE) {
222 connman_error("Failed to disconnect service");
223 dbus_message_unref(message);
228 connman_error("D-Bus connection not available");
229 dbus_message_unref(message);
233 dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
235 dbus_message_unref(message);
240 static struct connman_network_driver pan_driver = {
241 .name = "bluetooth-pan",
242 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
244 .remove = pan_remove,
245 .connect = pan_connect,
246 .disconnect = pan_disconnect,
249 static void extract_properties(DBusMessage *reply, const char **parent,
250 const char **address,
253 dbus_bool_t *powered,
254 dbus_bool_t *scanning,
255 DBusMessageIter *uuids,
256 DBusMessageIter *networks)
258 DBusMessageIter array, dict;
260 if (dbus_message_iter_init(reply, &array) == FALSE)
263 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
266 dbus_message_iter_recurse(&array, &dict);
268 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
269 DBusMessageIter entry, value;
272 dbus_message_iter_recurse(&dict, &entry);
273 dbus_message_iter_get_basic(&entry, &key);
275 dbus_message_iter_next(&entry);
276 dbus_message_iter_recurse(&entry, &value);
278 if (g_str_equal(key, "Adapter") == TRUE) {
280 dbus_message_iter_get_basic(&value, parent);
281 } else if (g_str_equal(key, "Address") == TRUE) {
283 dbus_message_iter_get_basic(&value, address);
284 } else if (g_str_equal(key, "Name") == TRUE) {
286 dbus_message_iter_get_basic(&value, name);
287 } else if (g_str_equal(key, "Alias") == TRUE) {
289 dbus_message_iter_get_basic(&value, alias);
290 } else if (g_str_equal(key, "Powered") == TRUE) {
292 dbus_message_iter_get_basic(&value, powered);
293 } else if (g_str_equal(key, "Discovering") == TRUE) {
294 if (scanning != NULL)
295 dbus_message_iter_get_basic(&value, scanning);
296 } else if (g_str_equal(key, "Devices") == TRUE) {
297 if (networks != NULL)
298 memcpy(networks, &value, sizeof(value));
299 } else if (g_str_equal(key, "UUIDs") == TRUE) {
301 memcpy(uuids, &value, sizeof(value));
304 dbus_message_iter_next(&dict);
308 static dbus_bool_t has_pan(DBusMessageIter *array)
310 DBusMessageIter value;
312 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
315 dbus_message_iter_recurse(array, &value);
317 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
320 dbus_message_iter_get_basic(&value, &uuid);
322 if (g_strcmp0(uuid, UUID_NAP) == 0)
325 dbus_message_iter_next(&value);
331 static void network_properties_reply(DBusPendingCall *call, void *user_data)
333 char *path = user_data;
334 struct connman_device *device;
335 struct connman_network *network;
337 DBusMessageIter uuids;
338 const char *parent = NULL, *address = NULL, *name = NULL;
339 struct ether_addr addr;
342 reply = dbus_pending_call_steal_reply(call);
344 extract_properties(reply, &parent, &address, NULL, &name,
345 NULL, NULL, &uuids, NULL);
350 device = g_hash_table_lookup(bluetooth_devices, parent);
357 ether_aton_r(address, &addr);
359 snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
360 addr.ether_addr_octet[0],
361 addr.ether_addr_octet[1],
362 addr.ether_addr_octet[2],
363 addr.ether_addr_octet[3],
364 addr.ether_addr_octet[4],
365 addr.ether_addr_octet[5]);
367 if (has_pan(&uuids) == FALSE)
370 network = connman_device_get_network(device, ident);
374 network = connman_network_create(ident,
375 CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
379 connman_network_set_string(network, "Path", path);
381 connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
383 connman_network_set_name(network, name);
385 connman_device_add_network(device, network);
387 connman_network_set_group(network, ident);
390 dbus_message_unref(reply);
392 dbus_pending_call_unref(call);
395 static void add_network(struct connman_device *device, const char *path)
397 DBusMessage *message;
398 DBusPendingCall *call;
400 DBG("path %s", path);
402 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
403 BLUEZ_DEVICE_INTERFACE, GET_PROPERTIES);
407 dbus_message_set_auto_start(message, FALSE);
409 if (dbus_connection_send_with_reply(connection, message,
410 &call, TIMEOUT) == FALSE) {
411 connman_error("Failed to get network properties for %s", path);
416 connman_error("D-Bus connection not available");
420 dbus_pending_call_set_notify(call, network_properties_reply,
421 g_strdup(path), g_free);
424 dbus_message_unref(message);
427 static void check_networks(struct connman_device *device,
428 DBusMessageIter *array)
430 DBusMessageIter value;
432 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
435 dbus_message_iter_recurse(array, &value);
437 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
440 dbus_message_iter_get_basic(&value, &path);
442 add_network(device, path);
444 dbus_message_iter_next(&value);
448 static gboolean adapter_changed(DBusConnection *connection,
449 DBusMessage *message, void *user_data)
451 const char *path = dbus_message_get_path(message);
452 struct connman_device *device;
453 DBusMessageIter iter, value;
456 DBG("path %s", path);
458 device = g_hash_table_lookup(bluetooth_devices, path);
462 if (dbus_message_iter_init(message, &iter) == FALSE)
465 dbus_message_iter_get_basic(&iter, &key);
467 dbus_message_iter_next(&iter);
468 dbus_message_iter_recurse(&iter, &value);
470 if (g_str_equal(key, "Powered") == TRUE) {
473 dbus_message_iter_get_basic(&value, &val);
474 connman_device_set_powered(device, val);
475 } else if (g_str_equal(key, "Discovering") == TRUE) {
478 dbus_message_iter_get_basic(&value, &val);
479 connman_device_set_scanning(device, val);
480 } else if (g_str_equal(key, "Devices") == TRUE) {
481 check_networks(device, &value);
487 static void adapter_properties_reply(DBusPendingCall *call, void *user_data)
489 char *path = user_data;
490 struct connman_device *device;
492 DBusMessageIter networks;
493 const char *address = NULL, *name = NULL;
494 dbus_bool_t powered = FALSE, scanning = FALSE;
495 struct ether_addr addr;
498 DBG("path %s", path);
500 reply = dbus_pending_call_steal_reply(call);
505 extract_properties(reply, NULL, &address, &name, NULL,
506 &powered, &scanning, NULL, &networks);
511 device = g_hash_table_lookup(bluetooth_devices, path);
515 ether_aton_r(address, &addr);
517 snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
518 addr.ether_addr_octet[0],
519 addr.ether_addr_octet[1],
520 addr.ether_addr_octet[2],
521 addr.ether_addr_octet[3],
522 addr.ether_addr_octet[4],
523 addr.ether_addr_octet[5]);
525 device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
529 connman_device_set_ident(device, ident);
531 connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
533 connman_device_set_string(device, "Path", path);
535 if (connman_device_register(device) < 0) {
536 connman_device_unref(device);
540 g_hash_table_insert(bluetooth_devices, g_strdup(path), device);
543 connman_device_set_string(device, "Address", address);
544 connman_device_set_string(device, "Name", name);
545 connman_device_set_string(device, "Path", path);
547 connman_device_set_powered(device, powered);
548 connman_device_set_scanning(device, scanning);
551 check_networks(device, &networks);
554 dbus_message_unref(reply);
556 dbus_pending_call_unref(call);
559 static void add_adapter(DBusConnection *connection, const char *path)
561 DBusMessage *message;
562 DBusPendingCall *call;
564 DBG("path %s", path);
566 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
567 BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
571 dbus_message_set_auto_start(message, FALSE);
573 if (dbus_connection_send_with_reply(connection, message,
574 &call, TIMEOUT) == FALSE) {
575 connman_error("Failed to get adapter properties for %s", path);
580 connman_error("D-Bus connection not available");
584 dbus_pending_call_set_notify(call, adapter_properties_reply,
585 g_strdup(path), g_free);
588 dbus_message_unref(message);
591 static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
596 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
598 add_adapter(connection, path);
602 static void remove_adapter(DBusConnection *connection, const char *path)
604 DBG("path %s", path);
606 g_hash_table_remove(bluetooth_devices, path);
609 static gboolean adapter_removed(DBusConnection *connection, DBusMessage *message,
614 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
616 remove_adapter(connection, path);
620 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
629 reply = dbus_pending_call_steal_reply(call);
631 dbus_error_init(&error);
633 if (dbus_message_get_args(reply, &error,
634 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
635 &adapters, &num_adapters,
636 DBUS_TYPE_INVALID) == FALSE) {
637 if (dbus_error_is_set(&error) == TRUE) {
638 connman_error("%s", error.message);
639 dbus_error_free(&error);
641 connman_error("Wrong arguments for adapter list");
645 for (i = 0; i < num_adapters; i++)
646 add_adapter(connection, adapters[i]);
648 g_strfreev(adapters);
651 dbus_message_unref(reply);
653 dbus_pending_call_unref(call);
656 static void unregister_device(gpointer data)
658 struct connman_device *device = data;
662 connman_device_unregister(device);
663 connman_device_unref(device);
666 static void bluetooth_connect(DBusConnection *connection, void *user_data)
668 DBusMessage *message;
669 DBusPendingCall *call;
671 DBG("connection %p", connection);
673 bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
674 g_free, unregister_device);
676 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
677 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
681 dbus_message_set_auto_start(message, FALSE);
683 if (dbus_connection_send_with_reply(connection, message,
684 &call, TIMEOUT) == FALSE) {
685 connman_error("Failed to get Bluetooth adapters");
690 connman_error("D-Bus connection not available");
694 dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL);
697 dbus_message_unref(message);
700 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
702 DBG("connection %p", connection);
704 if (bluetooth_devices == NULL)
707 g_hash_table_destroy(bluetooth_devices);
708 bluetooth_devices = NULL;
711 static int bluetooth_probe(struct connman_device *device)
713 DBG("device %p", device);
718 static void bluetooth_remove(struct connman_device *device)
720 DBG("device %p", device);
723 static void powered_reply(DBusPendingCall *call, void *user_data)
729 reply = dbus_pending_call_steal_reply(call);
731 dbus_message_unref(reply);
733 dbus_pending_call_unref(call);
735 add_adapter(connection, user_data);
738 static int change_powered(DBusConnection *connection, const char *path,
741 DBusMessage *message;
742 DBusMessageIter iter;
743 DBusPendingCall *call;
750 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
751 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
755 dbus_message_set_auto_start(message, FALSE);
757 dbus_message_iter_init_append(message, &iter);
758 connman_dbus_property_append_basic(&iter, "Powered",
759 DBUS_TYPE_BOOLEAN, &powered);
761 if (dbus_connection_send_with_reply(connection, message,
762 &call, TIMEOUT) == FALSE) {
763 connman_error("Failed to change Powered property");
764 dbus_message_unref(message);
769 connman_error("D-Bus connection not available");
770 dbus_message_unref(message);
774 dbus_pending_call_set_notify(call, powered_reply,
775 g_strdup(path), g_free);
777 dbus_message_unref(message);
782 static int bluetooth_enable(struct connman_device *device)
784 const char *path = connman_device_get_string(device, "Path");
786 DBG("device %p", device);
788 return change_powered(connection, path, TRUE);
791 static int bluetooth_disable(struct connman_device *device)
793 const char *path = connman_device_get_string(device, "Path");
795 DBG("device %p", device);
797 return change_powered(connection, path, FALSE);
800 static struct connman_device_driver bluetooth_driver = {
802 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
803 .probe = bluetooth_probe,
804 .remove = bluetooth_remove,
805 .enable = bluetooth_enable,
806 .disable = bluetooth_disable,
810 static guint added_watch;
811 static guint removed_watch;
812 static guint adapter_watch;
814 static int bluetooth_init(void)
818 connection = connman_dbus_get_connection();
819 if (connection == NULL)
822 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
823 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
825 added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
826 BLUEZ_MANAGER_INTERFACE,
827 ADAPTER_ADDED, adapter_added,
830 removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
831 BLUEZ_MANAGER_INTERFACE,
832 ADAPTER_REMOVED, adapter_removed,
835 adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
836 BLUEZ_MANAGER_INTERFACE,
837 PROPERTY_CHANGED, adapter_changed,
840 if (watch == 0 || added_watch == 0 || removed_watch == 0
841 || adapter_watch == 0) {
846 err = connman_network_driver_register(&pan_driver);
850 err = connman_device_driver_register(&bluetooth_driver);
852 connman_network_driver_unregister(&pan_driver);
859 g_dbus_remove_watch(connection, watch);
860 g_dbus_remove_watch(connection, added_watch);
861 g_dbus_remove_watch(connection, removed_watch);
862 g_dbus_remove_watch(connection, adapter_watch);
864 dbus_connection_unref(connection);
869 static void bluetooth_exit(void)
871 g_dbus_remove_watch(connection, watch);
872 g_dbus_remove_watch(connection, added_watch);
873 g_dbus_remove_watch(connection, removed_watch);
874 g_dbus_remove_watch(connection, adapter_watch);
876 bluetooth_disconnect(connection, NULL);
878 connman_device_driver_unregister(&bluetooth_driver);
879 connman_network_driver_unregister(&pan_driver);
881 dbus_connection_unref(connection);
884 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
885 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)