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 #include <connman/plugin.h>
32 #include <connman/device.h>
33 #include <connman/dbus.h>
34 #include <connman/log.h>
36 #define BLUEZ_SERVICE "org.bluez"
37 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
38 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
39 #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
41 #define LIST_ADAPTERS "ListAdapters"
42 #define ADAPTER_ADDED "AdapterAdded"
43 #define ADAPTER_REMOVED "AdapterRemoved"
45 #define PROPERTY_CHANGED "PropertyChanged"
46 #define GET_PROPERTIES "GetProperties"
47 #define SET_PROPERTY "SetProperty"
51 typedef void (* properties_callback_t) (DBusConnection *connection,
56 struct properties_data {
57 DBusConnection *connection;
59 properties_callback_t callback;
63 static void get_properties_reply(DBusPendingCall *call, void *user_data)
65 struct properties_data *data = user_data;
69 reply = dbus_pending_call_steal_reply(call);
73 path = dbus_message_get_path(data->message);
75 data->callback(data->connection, path, reply, data->user_data);
77 dbus_message_unref(reply);
80 dbus_message_unref(data->message);
84 static void get_properties(DBusConnection *connection,
85 const char *path, const char *interface,
86 properties_callback_t callback, void *user_data)
88 struct properties_data *data;
90 DBusPendingCall *call;
92 DBG("path %s interface %s", path, interface);
94 data = g_try_new0(struct properties_data, 1);
98 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
99 interface, GET_PROPERTIES);
100 if (message == NULL) {
105 if (dbus_connection_send_with_reply(connection, message,
106 &call, TIMEOUT) == FALSE) {
107 connman_error("Failed to get properties for %s", interface);
108 dbus_message_unref(message);
113 data->connection = connection;
114 data->message = message;
115 data->callback = callback;
116 data->user_data = user_data;
118 dbus_pending_call_set_notify(call, get_properties_reply, data, NULL);
121 struct adapter_data {
122 DBusConnection *connection;
125 static int bluetooth_probe(struct connman_device *adapter)
127 struct adapter_data *data;
129 DBG("adapter %p", adapter);
131 data = g_try_new0(struct adapter_data, 1);
135 data->connection = connman_dbus_get_connection();
136 if (data->connection == NULL) {
141 connman_device_set_data(adapter, data);
146 static void bluetooth_remove(struct connman_device *adapter)
148 struct adapter_data *data = connman_device_get_data(adapter);
150 DBG("adapter %p", adapter);
152 connman_device_set_data(adapter, NULL);
154 dbus_connection_unref(data->connection);
159 static void powered_reply(DBusPendingCall *call, void *user_data)
165 reply = dbus_pending_call_steal_reply(call);
167 dbus_message_unref(reply);
170 static int change_powered(DBusConnection *connection, const char *path,
173 DBusMessage *message;
174 DBusMessageIter iter;
175 DBusPendingCall *call;
179 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
180 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
184 dbus_message_iter_init_append(message, &iter);
185 connman_dbus_property_append_variant(&iter, "Powered",
186 DBUS_TYPE_BOOLEAN, &powered);
188 if (dbus_connection_send_with_reply(connection, message,
189 &call, TIMEOUT) == FALSE) {
190 connman_error("Failed to change Powered property");
191 dbus_message_unref(message);
195 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
197 dbus_message_unref(message);
202 static int bluetooth_enable(struct connman_device *adapter)
204 struct adapter_data *data = connman_device_get_data(adapter);
205 const char *path = connman_device_get_path(adapter);
207 DBG("adapter %p", adapter);
209 return change_powered(data->connection, path, TRUE);
212 static int bluetooth_disable(struct connman_device *adapter)
214 struct adapter_data *data = connman_device_get_data(adapter);
215 const char *path = connman_device_get_path(adapter);
217 DBG("adapter %p", adapter);
219 return change_powered(data->connection, path, FALSE);
222 static int bluetooth_scan(struct connman_device *adapter)
224 DBG("adapter %p", adapter);
229 static struct connman_device_driver bluetooth_driver = {
231 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
232 .probe = bluetooth_probe,
233 .remove = bluetooth_remove,
234 .enable = bluetooth_enable,
235 .disable = bluetooth_disable,
236 .scan = bluetooth_scan,
239 static GSList *adapter_list = NULL;
241 static void free_adapters(void)
247 for (list = adapter_list; list; list = list->next) {
248 struct connman_device *adapter = list->data;
250 connman_device_unregister(adapter);
251 connman_device_unref(adapter);
254 g_slist_free(adapter_list);
258 static struct connman_device *find_adapter(const char *path)
262 DBG("path %s", path);
264 for (list = adapter_list; list; list = list->next) {
265 struct connman_device *adapter = list->data;
266 const char *adapter_path = connman_device_get_path(adapter);
268 if (adapter_path == NULL)
271 if (g_str_equal(adapter_path, path) == TRUE)
278 static void device_properties(DBusConnection *connection, const char *path,
279 DBusMessage *message, void *user_data)
281 struct connman_device *device = user_data;
282 const char *node = g_basename(path);
283 struct connman_network *network;
285 DBG("path %s", path);
287 network = connman_device_get_network(device, node);
291 network = connman_network_create(node, CONNMAN_NETWORK_TYPE_WIFI);
295 connman_device_add_network(device, network);
298 static void check_devices(struct connman_device *adapter,
299 DBusConnection *connection, DBusMessageIter *array)
301 DBusMessageIter value;
303 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
306 dbus_message_iter_recurse(array, &value);
308 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
311 dbus_message_iter_get_basic(&value, &path);
313 get_properties(connection, path, BLUEZ_DEVICE_INTERFACE,
314 device_properties, adapter);
316 dbus_message_iter_next(&value);
320 static void property_changed(DBusConnection *connection, DBusMessage *message)
322 const char *path = dbus_message_get_path(message);
323 struct connman_device *adapter;
324 DBusMessageIter iter, value;
327 DBG("path %s", path);
329 adapter = find_adapter(path);
333 if (dbus_message_iter_init(message, &iter) == FALSE)
336 dbus_message_iter_get_basic(&iter, &key);
338 dbus_message_iter_next(&iter);
339 dbus_message_iter_recurse(&iter, &value);
341 if (g_str_equal(key, "Powered") == TRUE) {
344 dbus_message_iter_get_basic(&value, &val);
345 connman_device_set_powered(adapter, val);
346 } else if (g_str_equal(key, "Discovering") == TRUE) {
349 dbus_message_iter_get_basic(&value, &val);
350 connman_device_set_scanning(adapter, val);
354 static void parse_adapter_properties(struct connman_device *adapter,
355 DBusConnection *connection,
358 DBusMessageIter array, dict;
360 if (dbus_message_iter_init(reply, &array) == FALSE)
363 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
366 dbus_message_iter_recurse(&array, &dict);
368 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
369 DBusMessageIter entry, value;
372 dbus_message_iter_recurse(&dict, &entry);
373 dbus_message_iter_get_basic(&entry, &key);
375 dbus_message_iter_next(&entry);
376 dbus_message_iter_recurse(&entry, &value);
378 if (g_str_equal(key, "Powered") == TRUE) {
381 dbus_message_iter_get_basic(&value, &val);
382 connman_device_set_powered(adapter, val);
383 } else if (g_str_equal(key, "Discovering") == TRUE) {
386 dbus_message_iter_get_basic(&value, &val);
387 connman_device_set_scanning(adapter, val);
388 } else if (g_str_equal(key, "Devices") == TRUE) {
389 check_devices(adapter, connection, &value);
392 dbus_message_iter_next(&dict);
396 static void adapter_properties(DBusConnection *connection, const char *path,
397 DBusMessage *message, void *user_data)
399 const char *node = g_basename(path);
400 struct connman_device *adapter;
402 DBG("path %s", path);
404 adapter = find_adapter(path);
408 adapter = connman_device_create(node, CONNMAN_DEVICE_TYPE_BLUETOOTH);
412 connman_device_set_path(adapter, path);
414 if (g_str_has_prefix(node, "hci") == TRUE) {
417 index = atoi(node + 3);
419 connman_device_set_index(adapter, index);
422 connman_device_set_interface(adapter, node);
424 connman_device_set_mode(adapter, CONNMAN_DEVICE_MODE_MULTIPLE_NETWORKS);
426 if (connman_device_register(adapter) < 0) {
427 connman_device_unref(adapter);
431 adapter_list = g_slist_append(adapter_list, adapter);
434 parse_adapter_properties(adapter, connection, message);
437 static void add_adapter(DBusConnection *connection, const char *path)
439 DBG("path %s", path);
441 get_properties(connection, path, BLUEZ_ADAPTER_INTERFACE,
442 adapter_properties, NULL);
445 static void remove_adapter(DBusConnection *connection, const char *path)
447 struct connman_device *adapter;
449 DBG("path %s", path);
451 adapter = find_adapter(path);
455 adapter_list = g_slist_remove(adapter_list, adapter);
457 connman_device_unregister(adapter);
458 connman_device_unref(adapter);
461 static void list_adapters_reply(DBusPendingCall *call, void *user_data)
463 DBusConnection *connection = user_data;
471 reply = dbus_pending_call_steal_reply(call);
473 dbus_error_init(&error);
475 if (dbus_message_get_args(reply, &error,
476 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
477 &adapters, &num_adapters,
478 DBUS_TYPE_INVALID) == FALSE) {
479 if (dbus_error_is_set(&error) == TRUE) {
480 connman_error("%s", error.message);
481 dbus_error_free(&error);
483 connman_error("Wrong arguments for adapter list");
487 for (i = 0; i < num_adapters; i++)
488 get_properties(connection, adapters[i],
489 BLUEZ_ADAPTER_INTERFACE,
490 adapter_properties, NULL);
492 g_strfreev(adapters);
495 dbus_message_unref(reply);
498 static void bluetooth_connect(DBusConnection *connection, void *user_data)
500 DBusMessage *message;
501 DBusPendingCall *call;
503 DBG("connection %p", connection);
505 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
506 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
510 if (dbus_connection_send_with_reply(connection, message,
511 &call, TIMEOUT) == FALSE) {
512 connman_error("Failed to get Bluetooth adapters");
513 dbus_message_unref(message);
517 dbus_pending_call_set_notify(call, list_adapters_reply,
520 dbus_message_unref(message);
523 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
525 DBG("connection %p", connection);
530 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
531 DBusMessage *message, void *user_data)
533 if (dbus_message_has_interface(message,
534 BLUEZ_MANAGER_INTERFACE) == FALSE &&
535 dbus_message_has_interface(message,
536 BLUEZ_ADAPTER_INTERFACE) == FALSE)
537 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
539 DBG("connection %p", connection);
541 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
542 PROPERTY_CHANGED) == TRUE) {
543 property_changed(connection, message);
544 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
545 ADAPTER_ADDED) == TRUE) {
547 dbus_message_get_args(message, NULL,
548 DBUS_TYPE_OBJECT_PATH, &path,
550 add_adapter(connection, path);
551 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
552 ADAPTER_REMOVED) == TRUE) {
554 dbus_message_get_args(message, NULL,
555 DBUS_TYPE_OBJECT_PATH, &path,
557 remove_adapter(connection, path);
560 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
563 static DBusConnection *connection;
566 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
567 ",interface=" BLUEZ_MANAGER_INTERFACE;
568 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
569 ",interface=" BLUEZ_MANAGER_INTERFACE;
571 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
572 ",interface=" BLUEZ_ADAPTER_INTERFACE;
574 static int bluetooth_init(void)
578 connection = connman_dbus_get_connection();
579 if (connection == NULL)
582 if (dbus_connection_add_filter(connection, bluetooth_signal,
583 NULL, NULL) == FALSE)
586 err = connman_device_driver_register(&bluetooth_driver);
590 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
591 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
593 connman_device_driver_unregister(&bluetooth_driver);
598 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
599 bluetooth_connect(connection, NULL);
601 dbus_bus_add_match(connection, added_rule, NULL);
602 dbus_bus_add_match(connection, removed_rule, NULL);
603 dbus_bus_add_match(connection, adapter_rule, NULL);
604 dbus_connection_flush(connection);
609 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
612 dbus_connection_unref(connection);
617 static void bluetooth_exit(void)
619 dbus_bus_remove_match(connection, adapter_rule, NULL);
620 dbus_bus_remove_match(connection, removed_rule, NULL);
621 dbus_bus_remove_match(connection, added_rule, NULL);
622 dbus_connection_flush(connection);
624 g_dbus_remove_watch(connection, watch);
628 connman_device_driver_unregister(&bluetooth_driver);
630 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
632 dbus_connection_unref(connection);
635 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
636 bluetooth_init, bluetooth_exit)