5 * Copyright (C) 2007-2008 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/dbus.h>
35 #include <connman/log.h>
37 #define BLUEZ_SERVICE "org.bluez"
38 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
39 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
40 #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
42 #define LIST_ADAPTERS "ListAdapters"
43 #define ADAPTER_ADDED "AdapterAdded"
44 #define ADAPTER_REMOVED "AdapterRemoved"
46 #define PROPERTY_CHANGED "PropertyChanged"
47 #define GET_PROPERTIES "GetProperties"
48 #define SET_PROPERTY "SetProperty"
52 typedef void (* properties_callback_t) (DBusConnection *connection,
57 struct properties_data {
58 DBusConnection *connection;
60 properties_callback_t callback;
64 static void get_properties_reply(DBusPendingCall *call, void *user_data)
66 struct properties_data *data = user_data;
70 reply = dbus_pending_call_steal_reply(call);
74 path = dbus_message_get_path(data->message);
76 data->callback(data->connection, path, reply, data->user_data);
78 dbus_message_unref(reply);
81 dbus_message_unref(data->message);
85 static void get_properties(DBusConnection *connection,
86 const char *path, const char *interface,
87 properties_callback_t callback, void *user_data)
89 struct properties_data *data;
91 DBusPendingCall *call;
93 DBG("path %s interface %s", path, interface);
95 data = g_try_new0(struct properties_data, 1);
99 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
100 interface, GET_PROPERTIES);
101 if (message == NULL) {
106 if (dbus_connection_send_with_reply(connection, message,
107 &call, TIMEOUT) == FALSE) {
108 connman_error("Failed to get properties for %s", interface);
109 dbus_message_unref(message);
114 data->connection = connection;
115 data->message = message;
116 data->callback = callback;
117 data->user_data = user_data;
119 dbus_pending_call_set_notify(call, get_properties_reply, data, NULL);
122 struct adapter_data {
123 DBusConnection *connection;
126 static int bluetooth_probe(struct connman_device *adapter)
128 struct adapter_data *data;
130 DBG("adapter %p", adapter);
132 data = g_try_new0(struct adapter_data, 1);
136 data->connection = connman_dbus_get_connection();
137 if (data->connection == NULL) {
142 connman_device_set_data(adapter, data);
147 static void bluetooth_remove(struct connman_device *adapter)
149 struct adapter_data *data = connman_device_get_data(adapter);
151 DBG("adapter %p", adapter);
153 connman_device_set_data(adapter, NULL);
155 dbus_connection_unref(data->connection);
160 static void powered_reply(DBusPendingCall *call, void *user_data)
166 reply = dbus_pending_call_steal_reply(call);
168 dbus_message_unref(reply);
171 static int change_powered(DBusConnection *connection, const char *path,
174 DBusMessage *message;
175 DBusMessageIter iter;
176 DBusPendingCall *call;
180 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
181 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
185 dbus_message_iter_init_append(message, &iter);
186 connman_dbus_property_append_variant(&iter, "Powered",
187 DBUS_TYPE_BOOLEAN, &powered);
189 if (dbus_connection_send_with_reply(connection, message,
190 &call, TIMEOUT) == FALSE) {
191 connman_error("Failed to change Powered property");
192 dbus_message_unref(message);
196 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
198 dbus_message_unref(message);
203 static int bluetooth_enable(struct connman_device *adapter)
205 struct adapter_data *data = connman_device_get_data(adapter);
206 const char *path = connman_device_get_path(adapter);
208 DBG("adapter %p", adapter);
210 return change_powered(data->connection, path, TRUE);
213 static int bluetooth_disable(struct connman_device *adapter)
215 struct adapter_data *data = connman_device_get_data(adapter);
216 const char *path = connman_device_get_path(adapter);
218 DBG("adapter %p", adapter);
220 return change_powered(data->connection, path, FALSE);
223 static int bluetooth_scan(struct connman_device *adapter)
225 DBG("adapter %p", adapter);
230 static struct connman_device_driver bluetooth_driver = {
232 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
233 .probe = bluetooth_probe,
234 .remove = bluetooth_remove,
235 .enable = bluetooth_enable,
236 .disable = bluetooth_disable,
237 .scan = bluetooth_scan,
240 static GSList *adapter_list = NULL;
242 static void free_adapters(void)
248 for (list = adapter_list; list; list = list->next) {
249 struct connman_device *adapter = list->data;
251 connman_device_unregister(adapter);
252 connman_device_unref(adapter);
255 g_slist_free(adapter_list);
259 static struct connman_device *find_adapter(const char *path)
263 DBG("path %s", path);
265 for (list = adapter_list; list; list = list->next) {
266 struct connman_device *adapter = list->data;
267 const char *adapter_path = connman_device_get_path(adapter);
269 if (adapter_path == NULL)
272 if (g_str_equal(adapter_path, path) == TRUE)
279 static void device_properties(DBusConnection *connection, const char *path,
280 DBusMessage *message, void *user_data)
282 struct connman_device *device = user_data;
283 const char *node = g_basename(path);
284 struct connman_network *network;
286 DBG("path %s", path);
288 network = connman_device_get_network(device, node);
292 network = connman_network_create(node, CONNMAN_NETWORK_TYPE_WIFI);
296 connman_device_add_network(device, network);
299 static void check_devices(struct connman_device *adapter,
300 DBusConnection *connection, DBusMessageIter *array)
302 DBusMessageIter value;
304 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
307 dbus_message_iter_recurse(array, &value);
309 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
312 dbus_message_iter_get_basic(&value, &path);
314 get_properties(connection, path, BLUEZ_DEVICE_INTERFACE,
315 device_properties, adapter);
317 dbus_message_iter_next(&value);
321 static void property_changed(DBusConnection *connection, DBusMessage *message)
323 const char *path = dbus_message_get_path(message);
324 struct connman_device *adapter;
325 DBusMessageIter iter, value;
328 DBG("path %s", path);
330 adapter = find_adapter(path);
334 if (dbus_message_iter_init(message, &iter) == FALSE)
337 dbus_message_iter_get_basic(&iter, &key);
339 dbus_message_iter_next(&iter);
340 dbus_message_iter_recurse(&iter, &value);
342 if (g_str_equal(key, "Powered") == TRUE) {
345 dbus_message_iter_get_basic(&value, &val);
346 connman_device_set_powered(adapter, val);
347 } else if (g_str_equal(key, "Discovering") == TRUE) {
350 dbus_message_iter_get_basic(&value, &val);
351 connman_device_set_scanning(adapter, val);
355 static void parse_adapter_properties(struct connman_device *adapter,
356 DBusConnection *connection,
359 DBusMessageIter array, dict;
361 if (dbus_message_iter_init(reply, &array) == FALSE)
364 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
367 dbus_message_iter_recurse(&array, &dict);
369 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
370 DBusMessageIter entry, value;
373 dbus_message_iter_recurse(&dict, &entry);
374 dbus_message_iter_get_basic(&entry, &key);
376 dbus_message_iter_next(&entry);
377 dbus_message_iter_recurse(&entry, &value);
379 if (g_str_equal(key, "Powered") == TRUE) {
382 dbus_message_iter_get_basic(&value, &val);
383 connman_device_set_powered(adapter, val);
384 } else if (g_str_equal(key, "Discovering") == TRUE) {
387 dbus_message_iter_get_basic(&value, &val);
388 connman_device_set_scanning(adapter, val);
389 } else if (g_str_equal(key, "Devices") == TRUE) {
390 check_devices(adapter, connection, &value);
393 dbus_message_iter_next(&dict);
397 static void adapter_properties(DBusConnection *connection, const char *path,
398 DBusMessage *message, void *user_data)
400 const char *node = g_basename(path);
401 struct connman_device *adapter;
403 DBG("path %s", path);
405 adapter = find_adapter(path);
409 adapter = connman_device_create(node, CONNMAN_DEVICE_TYPE_BLUETOOTH);
413 connman_device_set_path(adapter, path);
415 if (node != NULL && g_str_has_prefix(node, "hci") == TRUE) {
418 index = atoi(node + 3);
420 connman_device_set_index(adapter, index);
423 connman_device_set_interface(adapter, node);
425 connman_device_set_policy(adapter, CONNMAN_DEVICE_POLICY_MANUAL);
426 connman_device_set_mode(adapter, CONNMAN_DEVICE_MODE_MULTIPLE_NETWORKS);
428 if (connman_device_register(adapter) < 0) {
429 connman_device_unref(adapter);
433 adapter_list = g_slist_append(adapter_list, adapter);
436 parse_adapter_properties(adapter, connection, message);
439 static void add_adapter(DBusConnection *connection, const char *path)
441 DBG("path %s", path);
443 get_properties(connection, path, BLUEZ_ADAPTER_INTERFACE,
444 adapter_properties, NULL);
447 static void remove_adapter(DBusConnection *connection, const char *path)
449 struct connman_device *adapter;
451 DBG("path %s", path);
453 adapter = find_adapter(path);
457 adapter_list = g_slist_remove(adapter_list, adapter);
459 connman_device_unregister(adapter);
460 connman_device_unref(adapter);
463 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
465 DBusConnection *connection = user_data;
473 reply = dbus_pending_call_steal_reply(call);
475 dbus_error_init(&error);
477 if (dbus_message_get_args(reply, &error,
478 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
479 &adapters, &num_adapters,
480 DBUS_TYPE_INVALID) == FALSE) {
481 if (dbus_error_is_set(&error) == TRUE) {
482 connman_error("%s", error.message);
483 dbus_error_free(&error);
485 connman_error("Wrong arguments for adapter list");
489 for (i = 0; i < num_adapters; i++)
490 get_properties(connection, adapters[i],
491 BLUEZ_ADAPTER_INTERFACE,
492 adapter_properties, NULL);
494 g_strfreev(adapters);
497 dbus_message_unref(reply);
500 static void bluetooth_connect(DBusConnection *connection, void *user_data)
502 DBusMessage *message;
503 DBusPendingCall *call;
505 DBG("connection %p", connection);
507 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
508 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
512 if (dbus_connection_send_with_reply(connection, message,
513 &call, TIMEOUT) == FALSE) {
514 connman_error("Failed to get Bluetooth adapters");
515 dbus_message_unref(message);
519 dbus_pending_call_set_notify(call, list_adapters_reply,
522 dbus_message_unref(message);
525 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
527 DBG("connection %p", connection);
532 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
533 DBusMessage *message, void *user_data)
535 if (dbus_message_has_interface(message,
536 BLUEZ_MANAGER_INTERFACE) == FALSE &&
537 dbus_message_has_interface(message,
538 BLUEZ_ADAPTER_INTERFACE) == FALSE)
539 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
541 DBG("connection %p", connection);
543 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
544 PROPERTY_CHANGED) == TRUE) {
545 property_changed(connection, message);
546 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
547 ADAPTER_ADDED) == TRUE) {
549 dbus_message_get_args(message, NULL,
550 DBUS_TYPE_OBJECT_PATH, &path,
552 add_adapter(connection, path);
553 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
554 ADAPTER_REMOVED) == TRUE) {
556 dbus_message_get_args(message, NULL,
557 DBUS_TYPE_OBJECT_PATH, &path,
559 remove_adapter(connection, path);
562 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
565 static DBusConnection *connection;
568 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
569 ",interface=" BLUEZ_MANAGER_INTERFACE;
570 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
571 ",interface=" BLUEZ_MANAGER_INTERFACE;
573 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
574 ",interface=" BLUEZ_ADAPTER_INTERFACE;
576 static int bluetooth_init(void)
580 connection = connman_dbus_get_connection();
581 if (connection == NULL)
584 if (dbus_connection_add_filter(connection, bluetooth_signal,
585 NULL, NULL) == FALSE)
588 err = connman_device_driver_register(&bluetooth_driver);
592 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
593 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
595 connman_device_driver_unregister(&bluetooth_driver);
600 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
601 bluetooth_connect(connection, NULL);
603 dbus_bus_add_match(connection, added_rule, NULL);
604 dbus_bus_add_match(connection, removed_rule, NULL);
605 dbus_bus_add_match(connection, adapter_rule, NULL);
606 dbus_connection_flush(connection);
611 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
614 dbus_connection_unref(connection);
619 static void bluetooth_exit(void)
621 dbus_bus_remove_match(connection, adapter_rule, NULL);
622 dbus_bus_remove_match(connection, removed_rule, NULL);
623 dbus_bus_remove_match(connection, added_rule, NULL);
624 dbus_connection_flush(connection);
626 g_dbus_remove_watch(connection, watch);
630 connman_device_driver_unregister(&bluetooth_driver);
632 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
634 dbus_connection_unref(connection);
637 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
638 bluetooth_init, bluetooth_exit)