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
30 #include <connman/plugin.h>
31 #include <connman/driver.h>
32 #include <connman/dbus.h>
33 #include <connman/log.h>
35 #define BLUEZ_SERVICE "org.bluez"
36 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
37 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
39 #define LIST_ADAPTERS "ListAdapters"
40 #define ADAPTER_ADDED "AdapterAdded"
41 #define ADAPTER_REMOVED "AdapterRemoved"
43 #define PROPERTY_CHANGED "PropertyChanged"
44 #define GET_PROPERTIES "GetProperties"
45 #define SET_PROPERTY "SetProperty"
50 DBusConnection *connection;
53 static int bluetooth_probe(struct connman_element *adapter)
55 struct adapter_data *data;
57 DBG("adapter %p name %s", adapter, adapter->name);
59 data = g_try_new0(struct adapter_data, 1);
63 data->connection = connman_dbus_get_connection();
64 if (data->connection == NULL) {
69 connman_element_set_data(adapter, data);
74 static void bluetooth_remove(struct connman_element *adapter)
76 struct adapter_data *data = connman_element_get_data(adapter);
78 DBG("adapter %p name %s", adapter, adapter->name);
80 connman_element_set_data(adapter, NULL);
82 dbus_connection_unref(data->connection);
87 static void powered_reply(DBusPendingCall *call, void *user_data)
93 reply = dbus_pending_call_steal_reply(call);
95 dbus_message_unref(reply);
98 static int change_powered(DBusConnection *connection, const char *path,
101 DBusMessage *message;
102 DBusMessageIter iter;
103 DBusPendingCall *call;
107 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
108 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
112 dbus_message_iter_init_append(message, &iter);
113 connman_dbus_property_append_variant(&iter, "Powered",
114 DBUS_TYPE_BOOLEAN, &powered);
116 if (dbus_connection_send_with_reply(connection, message,
117 &call, TIMEOUT) == FALSE) {
118 connman_error("Failed to change Powered property");
119 dbus_message_unref(message);
123 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
125 dbus_message_unref(message);
130 static int bluetooth_enable(struct connman_element *adapter)
132 struct adapter_data *data = connman_element_get_data(adapter);
134 DBG("adapter %p name %s", adapter, adapter->name);
136 return change_powered(data->connection, adapter->devpath, TRUE);
139 static int bluetooth_disable(struct connman_element *adapter)
141 struct adapter_data *data = connman_element_get_data(adapter);
143 DBG("adapter %p name %s", adapter, adapter->name);
145 return change_powered(data->connection, adapter->devpath, FALSE);
148 static struct connman_driver bluetooth_driver = {
150 .type = CONNMAN_ELEMENT_TYPE_DEVICE,
151 .subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH,
152 .probe = bluetooth_probe,
153 .remove = bluetooth_remove,
154 .enable = bluetooth_enable,
155 .disable = bluetooth_disable,
158 static GSList *device_list = NULL;
160 static struct connman_element *find_adapter(const char *path)
164 DBG("path %s", path);
166 for (list = device_list; list; list = list->next) {
167 struct connman_element *device = list->data;
169 if (g_str_equal(device->devpath, path) == TRUE)
176 static void check_devices(struct connman_element *adapter,
177 DBusMessageIter *array)
179 DBusMessageIter value;
181 DBG("adapter %p name %s", adapter, adapter->name);
183 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
186 dbus_message_iter_recurse(array, &value);
188 while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
191 dbus_message_iter_get_basic(&value, &path);
193 DBG("device %s", path);
195 dbus_message_iter_next(&value);
199 static void property_changed(DBusConnection *connection, DBusMessage *message)
201 const char *path = dbus_message_get_path(message);
202 struct connman_element *device;
203 DBusMessageIter iter, value;
206 DBG("path %s", path);
208 device = find_adapter(path);
212 if (dbus_message_iter_init(message, &iter) == FALSE)
215 dbus_message_iter_get_basic(&iter, &key);
217 dbus_message_iter_next(&iter);
218 dbus_message_iter_recurse(&iter, &value);
220 if (g_str_equal(key, "Powered") == TRUE) {
223 dbus_message_iter_get_basic(&value, &val);
224 connman_element_set_enabled(device, val);
225 } else if (g_str_equal(key, "Discovering") == TRUE) {
228 dbus_message_iter_get_basic(&value, &val);
229 connman_element_set_scanning(device, val);
233 static void properties_reply(DBusPendingCall *call, void *user_data)
235 DBusMessage *message = user_data;
236 const char *path = dbus_message_get_path(message);
237 struct connman_element *device;
238 DBusMessageIter array, dict;
241 DBG("path %s", path);
243 device = find_adapter(path);
245 dbus_message_unref(message);
247 reply = dbus_pending_call_steal_reply(call);
252 if (dbus_message_iter_init(reply, &array) == FALSE)
255 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
258 dbus_message_iter_recurse(&array, &dict);
259 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
260 DBusMessageIter entry, value;
263 dbus_message_iter_recurse(&dict, &entry);
264 dbus_message_iter_get_basic(&entry, &key);
266 dbus_message_iter_next(&entry);
267 dbus_message_iter_recurse(&entry, &value);
269 if (g_str_equal(key, "Powered") == TRUE) {
272 dbus_message_iter_get_basic(&value, &val);
273 connman_element_set_enabled(device, val);
274 } else if (g_str_equal(key, "Discovering") == TRUE) {
277 dbus_message_iter_get_basic(&value, &val);
278 connman_element_set_scanning(device, val);
279 } else if (g_str_equal(key, "Devices") == TRUE) {
280 check_devices(device, &value);
283 dbus_message_iter_next(&dict);
287 dbus_message_unref(reply);
290 static void add_adapter(DBusConnection *connection, const char *path)
292 struct connman_element *device;
293 DBusMessage *message;
294 DBusPendingCall *call;
296 DBG("path %s", path);
298 device = find_adapter(path);
302 device = connman_element_create(NULL);
303 device->type = CONNMAN_ELEMENT_TYPE_DEVICE;
304 device->subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
305 device->policy = CONNMAN_ELEMENT_POLICY_IGNORE;
307 device->name = g_path_get_basename(path);
308 device->devpath = g_strdup(path);
310 if (connman_element_register(device, NULL) < 0) {
311 connman_element_unref(device);
315 device_list = g_slist_append(device_list, device);
317 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
318 BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
322 if (dbus_connection_send_with_reply(connection, message,
323 &call, TIMEOUT) == FALSE) {
324 connman_error("Failed to get adapter properties");
325 dbus_message_unref(message);
329 dbus_pending_call_set_notify(call, properties_reply, message, NULL);
332 static void remove_adapter(DBusConnection *connection, const char *path)
334 struct connman_element *device;
336 DBG("path %s", path);
338 device = find_adapter(path);
342 device_list = g_slist_remove(device_list, device);
344 connman_element_unregister(device);
345 connman_element_unref(device);
348 static void adapters_reply(DBusPendingCall *call, void *user_data)
350 DBusConnection *connection = user_data;
358 reply = dbus_pending_call_steal_reply(call);
360 dbus_error_init(&error);
362 if (dbus_message_get_args(reply, &error,
363 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
364 &adapters, &num_adapters,
365 DBUS_TYPE_INVALID) == FALSE) {
366 if (dbus_error_is_set(&error) == TRUE) {
367 connman_error("%s", error.message);
368 dbus_error_free(&error);
370 connman_error("Wrong arguments for adapter list");
374 for (i = 0; i < num_adapters; i++)
375 add_adapter(connection, adapters[i]);
377 g_strfreev(adapters);
380 dbus_message_unref(reply);
383 static void bluetooth_connect(DBusConnection *connection, void *user_data)
385 DBusMessage *message;
386 DBusPendingCall *call;
388 DBG("connection %p", connection);
390 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
391 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
395 if (dbus_connection_send_with_reply(connection, message,
396 &call, TIMEOUT) == FALSE) {
397 connman_error("Failed to get Bluetooth adapters");
398 dbus_message_unref(message);
402 dbus_pending_call_set_notify(call, adapters_reply, connection, NULL);
404 dbus_message_unref(message);
407 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
411 DBG("connection %p", connection);
413 for (list = device_list; list; list = list->next) {
414 struct connman_element *device = list->data;
416 connman_element_unregister(device);
417 connman_element_unref(device);
420 g_slist_free(device_list);
424 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
425 DBusMessage *message, void *user_data)
427 DBG("connection %p", connection);
429 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
430 PROPERTY_CHANGED) == TRUE) {
431 property_changed(connection, message);
432 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
433 ADAPTER_ADDED) == TRUE) {
435 dbus_message_get_args(message, NULL,
436 DBUS_TYPE_OBJECT_PATH, &path,
438 add_adapter(connection, path);
439 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
440 ADAPTER_REMOVED) == TRUE) {
442 dbus_message_get_args(message, NULL,
443 DBUS_TYPE_OBJECT_PATH, &path,
445 remove_adapter(connection, path);
448 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
451 static DBusConnection *connection;
454 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
455 ",interface=" BLUEZ_MANAGER_INTERFACE;
456 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
457 ",interface=" BLUEZ_MANAGER_INTERFACE;
459 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
460 ",interface=" BLUEZ_ADAPTER_INTERFACE;
462 static int bluetooth_init(void)
466 connection = connman_dbus_get_connection();
467 if (connection == NULL)
470 if (dbus_connection_add_filter(connection, bluetooth_signal,
471 NULL, NULL) == FALSE)
474 err = connman_driver_register(&bluetooth_driver);
478 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
479 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
481 connman_driver_unregister(&bluetooth_driver);
486 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
487 bluetooth_connect(connection, NULL);
489 dbus_bus_add_match(connection, added_rule, NULL);
490 dbus_bus_add_match(connection, removed_rule, NULL);
491 dbus_bus_add_match(connection, adapter_rule, NULL);
492 dbus_connection_flush(connection);
497 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
500 dbus_connection_unref(connection);
505 static void bluetooth_exit(void)
507 dbus_bus_remove_match(connection, adapter_rule, NULL);
508 dbus_bus_remove_match(connection, removed_rule, NULL);
509 dbus_bus_remove_match(connection, added_rule, NULL);
510 dbus_connection_flush(connection);
512 g_dbus_remove_watch(connection, watch);
514 bluetooth_disconnect(connection, NULL);
516 connman_driver_unregister(&bluetooth_driver);
518 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
520 dbus_connection_unref(connection);
523 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
524 bluetooth_init, bluetooth_exit)