5 * Copyright (C) 2007-2009 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
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/device.h>
34 #include <connman/inet.h>
35 #include <connman/dbus.h>
36 #include <connman/log.h>
38 #define BLUEZ_SERVICE "org.bluez"
39 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
40 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
41 #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
42 #define BLUEZ_NETWORK_INTERFACE BLUEZ_SERVICE ".Network"
44 #define LIST_ADAPTERS "ListAdapters"
45 #define ADAPTER_ADDED "AdapterAdded"
46 #define ADAPTER_REMOVED "AdapterRemoved"
48 #define PROPERTY_CHANGED "PropertyChanged"
49 #define GET_PROPERTIES "GetProperties"
50 #define SET_PROPERTY "SetProperty"
52 #define CONNECT "Connect"
53 #define DISCONNECT "Disconnect"
57 typedef void (* properties_callback_t) (DBusConnection *connection,
62 struct properties_data {
63 DBusConnection *connection;
65 properties_callback_t callback;
69 static void get_properties_reply(DBusPendingCall *call, void *user_data)
71 struct properties_data *data = user_data;
75 reply = dbus_pending_call_steal_reply(call);
79 path = dbus_message_get_path(data->message);
81 data->callback(data->connection, path, reply, data->user_data);
83 dbus_message_unref(reply);
86 dbus_message_unref(data->message);
90 static void get_properties(DBusConnection *connection,
91 const char *path, const char *interface,
92 properties_callback_t callback, void *user_data)
94 struct properties_data *data;
96 DBusPendingCall *call;
98 DBG("path %s interface %s", path, interface);
100 data = g_try_new0(struct properties_data, 1);
104 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
105 interface, GET_PROPERTIES);
106 if (message == NULL) {
111 if (dbus_connection_send_with_reply(connection, message,
112 &call, TIMEOUT) == FALSE) {
113 connman_error("Failed to get properties for %s", interface);
114 dbus_message_unref(message);
120 connman_error("D-Bus connection not available");
121 dbus_message_unref(message);
126 data->connection = connection;
127 data->message = message;
128 data->callback = callback;
129 data->user_data = user_data;
131 dbus_pending_call_set_notify(call, get_properties_reply, data, NULL);
134 struct adapter_data {
135 DBusConnection *connection;
138 struct network_data {
139 DBusConnection *connection;
143 static int pan_probe(struct connman_network *network)
145 struct connman_device *device = connman_network_get_device(network);
146 struct adapter_data *adapter;
147 struct network_data *data;
149 DBG("network %p", network);
154 adapter = connman_device_get_data(device);
158 data = g_try_new0(struct network_data, 1);
162 data->connection = adapter->connection;
164 connman_network_set_data(network, data);
169 static void pan_remove(struct connman_network *network)
171 struct network_data *data = connman_network_get_data(network);
173 DBG("network %p", network);
175 connman_network_set_data(network, NULL);
180 static void connect_reply(DBusPendingCall *call, void *user_data)
182 struct connman_network *network = user_data;
183 struct network_data *data = connman_network_get_data(network);
186 const char *interface = NULL;
189 DBG("network %p", network);
191 reply = dbus_pending_call_steal_reply(call);
195 dbus_error_init(&error);
197 if (dbus_message_get_args(reply, &error,
198 DBUS_TYPE_STRING, &interface,
199 DBUS_TYPE_INVALID) == FALSE) {
200 if (dbus_error_is_set(&error) == TRUE) {
201 connman_error("%s", error.message);
202 dbus_error_free(&error);
204 connman_error("Wrong arguments for connect");
208 if (interface == NULL)
211 DBG("interface %s", interface);
213 data->interface = g_strdup(interface);
215 index = connman_inet_ifindex(interface);
217 connman_network_set_index(network, index);
218 connman_network_set_connected(network, TRUE);
221 dbus_message_unref(reply);
224 static int pan_connect(struct connman_network *network)
226 struct network_data *data = connman_network_get_data(network);
227 const char *path = connman_network_get_string(network, "Node");
228 const char *uuid = "nap";
229 DBusMessage *message;
230 DBusPendingCall *call;
232 DBG("network %p", network);
234 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
235 BLUEZ_NETWORK_INTERFACE, CONNECT);
239 dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
242 if (dbus_connection_send_with_reply(data->connection, message,
243 &call, TIMEOUT * 10) == FALSE) {
244 connman_error("Failed to connect service");
245 dbus_message_unref(message);
250 connman_error("D-Bus connection not available");
251 dbus_message_unref(message);
255 dbus_pending_call_set_notify(call, connect_reply, network, NULL);
257 dbus_message_unref(message);
262 static void disconnect_reply(DBusPendingCall *call, void *user_data)
264 struct connman_network *network = user_data;
265 struct network_data *data = connman_network_get_data(network);
269 DBG("network %p", network);
271 reply = dbus_pending_call_steal_reply(call);
275 dbus_error_init(&error);
277 if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
278 if (dbus_error_is_set(&error) == TRUE) {
279 connman_error("%s", error.message);
280 dbus_error_free(&error);
282 connman_error("Wrong arguments for disconnect");
286 g_free(data->interface);
287 data->interface = NULL;
289 connman_network_set_connected(network, FALSE);
290 connman_network_set_index(network, -1);
293 dbus_message_unref(reply);
296 static int pan_disconnect(struct connman_network *network)
298 struct network_data *data = connman_network_get_data(network);
299 const char *path = connman_network_get_string(network, "Node");
300 DBusMessage *message;
301 DBusPendingCall *call;
303 DBG("network %p", network);
305 if (data->interface == NULL)
308 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
309 BLUEZ_NETWORK_INTERFACE, DISCONNECT);
313 dbus_message_append_args(message, DBUS_TYPE_INVALID);
315 if (dbus_connection_send_with_reply(data->connection, message,
316 &call, TIMEOUT) == FALSE) {
317 connman_error("Failed to disconnect service");
318 dbus_message_unref(message);
323 connman_error("D-Bus connection not available");
324 dbus_message_unref(message);
328 dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
330 dbus_message_unref(message);
335 static struct connman_network_driver pan_driver = {
336 .name = "bluetooth-pan",
337 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
339 .remove = pan_remove,
340 .connect = pan_connect,
341 .disconnect = pan_disconnect,
344 static int bluetooth_probe(struct connman_device *adapter)
346 struct adapter_data *data;
348 DBG("adapter %p", adapter);
350 data = g_try_new0(struct adapter_data, 1);
354 data->connection = connman_dbus_get_connection();
355 if (data->connection == NULL) {
360 connman_device_set_data(adapter, data);
365 static void bluetooth_remove(struct connman_device *adapter)
367 struct adapter_data *data = connman_device_get_data(adapter);
369 DBG("adapter %p", adapter);
371 connman_device_set_data(adapter, NULL);
373 dbus_connection_unref(data->connection);
378 static void powered_reply(DBusPendingCall *call, void *user_data)
384 reply = dbus_pending_call_steal_reply(call);
386 dbus_message_unref(reply);
389 static int change_powered(DBusConnection *connection, const char *path,
392 DBusMessage *message;
393 DBusMessageIter iter;
394 DBusPendingCall *call;
398 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
399 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
403 dbus_message_iter_init_append(message, &iter);
404 connman_dbus_property_append_variant(&iter, "Powered",
405 DBUS_TYPE_BOOLEAN, &powered);
407 if (dbus_connection_send_with_reply(connection, message,
408 &call, TIMEOUT) == FALSE) {
409 connman_error("Failed to change Powered property");
410 dbus_message_unref(message);
415 connman_error("D-Bus connection not available");
416 dbus_message_unref(message);
420 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
422 dbus_message_unref(message);
427 static int bluetooth_enable(struct connman_device *adapter)
429 struct adapter_data *data = connman_device_get_data(adapter);
430 const char *path = connman_device_get_string(adapter, "Node");
432 DBG("adapter %p", adapter);
434 return change_powered(data->connection, path, TRUE);
437 static int bluetooth_disable(struct connman_device *adapter)
439 struct adapter_data *data = connman_device_get_data(adapter);
440 const char *path = connman_device_get_string(adapter, "Node");
442 DBG("adapter %p", adapter);
444 return change_powered(data->connection, path, FALSE);
447 static int bluetooth_scan(struct connman_device *adapter)
449 DBG("adapter %p", adapter);
454 static struct connman_device_driver bluetooth_driver = {
456 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
457 .probe = bluetooth_probe,
458 .remove = bluetooth_remove,
459 .enable = bluetooth_enable,
460 .disable = bluetooth_disable,
461 .scan = bluetooth_scan,
464 static GSList *adapter_list = NULL;
466 static void free_adapters(void)
472 for (list = adapter_list; list; list = list->next) {
473 struct connman_device *adapter = list->data;
475 connman_device_unregister(adapter);
476 connman_device_unref(adapter);
479 g_slist_free(adapter_list);
483 static struct connman_device *find_adapter(const char *path)
487 DBG("path %s", path);
489 for (list = adapter_list; list; list = list->next) {
490 struct connman_device *adapter = list->data;
491 const char *adapter_path = connman_device_get_string(adapter,
494 if (adapter_path == NULL)
497 if (g_str_equal(adapter_path, path) == TRUE)
504 static void device_properties(DBusConnection *connection, const char *path,
505 DBusMessage *message, void *user_data)
507 struct connman_device *device = user_data;
508 const char *node = g_basename(path);
509 struct connman_network *network;
511 DBG("path %s", path);
513 network = connman_device_get_network(device, node);
517 network = connman_network_create(node,
518 CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
522 connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
524 connman_network_set_string(network, "Node", path);
526 connman_device_add_network(device, network);
529 static void check_devices(struct connman_device *adapter,
530 DBusConnection *connection, DBusMessageIter *array)
532 DBusMessageIter value;
534 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
537 dbus_message_iter_recurse(array, &value);
539 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
542 dbus_message_iter_get_basic(&value, &path);
544 get_properties(connection, path, BLUEZ_DEVICE_INTERFACE,
545 device_properties, adapter);
547 dbus_message_iter_next(&value);
551 static void property_changed(DBusConnection *connection, DBusMessage *message)
553 const char *path = dbus_message_get_path(message);
554 struct connman_device *adapter;
555 DBusMessageIter iter, value;
558 DBG("path %s", path);
560 adapter = find_adapter(path);
564 if (dbus_message_iter_init(message, &iter) == FALSE)
567 dbus_message_iter_get_basic(&iter, &key);
569 dbus_message_iter_next(&iter);
570 dbus_message_iter_recurse(&iter, &value);
572 if (g_str_equal(key, "Powered") == TRUE) {
575 dbus_message_iter_get_basic(&value, &val);
576 connman_device_set_powered(adapter, val);
577 } else if (g_str_equal(key, "Discovering") == TRUE) {
580 dbus_message_iter_get_basic(&value, &val);
581 connman_device_set_scanning(adapter, val);
585 static void parse_adapter_properties(struct connman_device *adapter,
586 DBusConnection *connection,
589 DBusMessageIter array, dict;
591 if (dbus_message_iter_init(reply, &array) == FALSE)
594 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
597 dbus_message_iter_recurse(&array, &dict);
599 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
600 DBusMessageIter entry, value;
603 dbus_message_iter_recurse(&dict, &entry);
604 dbus_message_iter_get_basic(&entry, &key);
606 dbus_message_iter_next(&entry);
607 dbus_message_iter_recurse(&entry, &value);
609 if (g_str_equal(key, "Powered") == TRUE) {
612 dbus_message_iter_get_basic(&value, &val);
613 connman_device_set_powered(adapter, val);
614 } else if (g_str_equal(key, "Discovering") == TRUE) {
617 dbus_message_iter_get_basic(&value, &val);
618 connman_device_set_scanning(adapter, val);
619 } else if (g_str_equal(key, "Devices") == TRUE) {
620 check_devices(adapter, connection, &value);
623 dbus_message_iter_next(&dict);
627 static void adapter_properties(DBusConnection *connection, const char *path,
628 DBusMessage *message, void *user_data)
630 const char *node = g_basename(path);
631 struct connman_device *adapter;
633 DBG("path %s", path);
635 adapter = find_adapter(path);
639 adapter = connman_device_create(node, CONNMAN_DEVICE_TYPE_BLUETOOTH);
643 connman_device_set_string(adapter, "Node", path);
645 if (node != NULL && g_str_has_prefix(node, "hci") == TRUE) {
648 index = atoi(node + 3);
650 connman_device_set_index(adapter, index);
653 connman_device_set_interface(adapter, node, NULL);
655 connman_device_set_mode(adapter, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
657 if (connman_device_register(adapter) < 0) {
658 connman_device_unref(adapter);
662 adapter_list = g_slist_append(adapter_list, adapter);
665 parse_adapter_properties(adapter, connection, message);
668 static void add_adapter(DBusConnection *connection, const char *path)
670 DBG("path %s", path);
672 get_properties(connection, path, BLUEZ_ADAPTER_INTERFACE,
673 adapter_properties, NULL);
676 static void remove_adapter(DBusConnection *connection, const char *path)
678 struct connman_device *adapter;
680 DBG("path %s", path);
682 adapter = find_adapter(path);
686 adapter_list = g_slist_remove(adapter_list, adapter);
688 connman_device_unregister(adapter);
689 connman_device_unref(adapter);
692 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
694 DBusConnection *connection = user_data;
702 reply = dbus_pending_call_steal_reply(call);
704 dbus_error_init(&error);
706 if (dbus_message_get_args(reply, &error,
707 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
708 &adapters, &num_adapters,
709 DBUS_TYPE_INVALID) == FALSE) {
710 if (dbus_error_is_set(&error) == TRUE) {
711 connman_error("%s", error.message);
712 dbus_error_free(&error);
714 connman_error("Wrong arguments for adapter list");
718 for (i = 0; i < num_adapters; i++)
719 get_properties(connection, adapters[i],
720 BLUEZ_ADAPTER_INTERFACE,
721 adapter_properties, NULL);
723 g_strfreev(adapters);
726 dbus_message_unref(reply);
729 static void bluetooth_connect(DBusConnection *connection, void *user_data)
731 DBusMessage *message;
732 DBusPendingCall *call;
734 DBG("connection %p", connection);
736 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
737 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
741 if (dbus_connection_send_with_reply(connection, message,
742 &call, TIMEOUT) == FALSE) {
743 connman_error("Failed to get Bluetooth adapters");
748 connman_error("D-Bus connection not available");
752 dbus_pending_call_set_notify(call, list_adapters_reply,
756 dbus_message_unref(message);
759 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
761 DBG("connection %p", connection);
766 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
767 DBusMessage *message, void *user_data)
769 if (dbus_message_has_interface(message,
770 BLUEZ_MANAGER_INTERFACE) == FALSE &&
771 dbus_message_has_interface(message,
772 BLUEZ_ADAPTER_INTERFACE) == FALSE)
773 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
775 DBG("connection %p", connection);
777 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
778 PROPERTY_CHANGED) == TRUE) {
779 property_changed(connection, message);
780 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
781 ADAPTER_ADDED) == TRUE) {
783 dbus_message_get_args(message, NULL,
784 DBUS_TYPE_OBJECT_PATH, &path,
786 add_adapter(connection, path);
787 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
788 ADAPTER_REMOVED) == TRUE) {
790 dbus_message_get_args(message, NULL,
791 DBUS_TYPE_OBJECT_PATH, &path,
793 remove_adapter(connection, path);
796 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
799 static DBusConnection *connection;
802 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
803 ",interface=" BLUEZ_MANAGER_INTERFACE;
804 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
805 ",interface=" BLUEZ_MANAGER_INTERFACE;
807 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
808 ",interface=" BLUEZ_ADAPTER_INTERFACE;
810 static int bluetooth_init(void)
814 connection = connman_dbus_get_connection();
815 if (connection == NULL)
818 if (dbus_connection_add_filter(connection, bluetooth_signal,
819 NULL, NULL) == FALSE)
822 err = connman_network_driver_register(&pan_driver);
826 err = connman_device_driver_register(&bluetooth_driver);
828 connman_network_driver_unregister(&pan_driver);
832 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
833 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
835 connman_device_driver_unregister(&bluetooth_driver);
836 connman_network_driver_unregister(&pan_driver);
841 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
842 bluetooth_connect(connection, NULL);
844 dbus_bus_add_match(connection, added_rule, NULL);
845 dbus_bus_add_match(connection, removed_rule, NULL);
846 dbus_bus_add_match(connection, adapter_rule, NULL);
847 dbus_connection_flush(connection);
852 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
855 dbus_connection_unref(connection);
860 static void bluetooth_exit(void)
862 dbus_bus_remove_match(connection, adapter_rule, NULL);
863 dbus_bus_remove_match(connection, removed_rule, NULL);
864 dbus_bus_remove_match(connection, added_rule, NULL);
865 dbus_connection_flush(connection);
867 g_dbus_remove_watch(connection, watch);
871 connman_device_driver_unregister(&bluetooth_driver);
872 connman_network_driver_unregister(&pan_driver);
874 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
876 dbus_connection_unref(connection);
879 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
880 CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)