3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2006-2010 Nokia Corporation
6
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33
#include <sys/ioctl.h>
34
#include <sys/socket.h>
36
#include <bluetooth/bluetooth.h>
37
#include <bluetooth/sdp.h>
38
#include <bluetooth/sdp_lib.h>
42
#include <dbus/dbus.h>
46
#include "glib-helper.h"
48
#include "dbus-common.h"
54
static char base_path[50] = "/org/bluez";
56
static DBusConnection *connection = NULL;
57
static int default_adapter_id = -1;
58
static GSList *adapters = NULL;
60
const char *manager_get_base_path(void)
65
static DBusMessage *default_adapter(DBusConnection *conn,
66
DBusMessage *msg, void *data)
69
struct btd_adapter *adapter;
72
adapter = manager_find_adapter_by_id(default_adapter_id);
74
return btd_error_no_such_adapter(msg);
76
reply = dbus_message_new_method_return(msg);
80
path = adapter_get_path(adapter);
82
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
88
static DBusMessage *find_adapter(DBusConnection *conn,
89
DBusMessage *msg, void *data)
92
struct btd_adapter *adapter;
97
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
101
/* hci_devid() would make sense to use here, except it is
102
* restricted to devices which are up */
103
if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
104
path = adapter_any_get_path();
107
return btd_error_no_such_adapter(msg);
108
} else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) {
109
dev_id = atoi(pattern + 3);
110
adapter = manager_find_adapter_by_id(dev_id);
113
str2ba(pattern, &bdaddr);
114
adapter = manager_find_adapter(&bdaddr);
118
return btd_error_no_such_adapter(msg);
120
path = adapter_get_path(adapter);
123
reply = dbus_message_new_method_return(msg);
127
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
133
static DBusMessage *list_adapters(DBusConnection *conn,
134
DBusMessage *msg, void *data)
136
DBusMessageIter iter;
137
DBusMessageIter array_iter;
141
reply = dbus_message_new_method_return(msg);
145
dbus_message_iter_init_append(reply, &iter);
147
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
148
DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
150
for (l = adapters; l; l = l->next) {
151
struct btd_adapter *adapter = l->data;
152
const gchar *path = adapter_get_path(adapter);
154
dbus_message_iter_append_basic(&array_iter,
155
DBUS_TYPE_OBJECT_PATH, &path);
158
dbus_message_iter_close_container(&iter, &array_iter);
163
static DBusMessage *get_properties(DBusConnection *conn,
164
DBusMessage *msg, void *data)
167
DBusMessageIter iter;
168
DBusMessageIter dict;
173
reply = dbus_message_new_method_return(msg);
177
dbus_message_iter_init_append(reply, &iter);
179
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
180
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
181
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
182
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
184
array = g_new0(char *, g_slist_length(adapters) + 1);
185
for (i = 0, list = adapters; list; list = list->next) {
186
struct btd_adapter *adapter = list->data;
188
array[i] = (char *) adapter_get_path(adapter);
191
dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i);
194
dbus_message_iter_close_container(&iter, &dict);
199
static const GDBusMethodTable manager_methods[] = {
200
{ GDBUS_METHOD("GetProperties",
201
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
203
{ GDBUS_METHOD("DefaultAdapter",
204
NULL, GDBUS_ARGS({ "adapter", "o" }),
206
{ GDBUS_METHOD("FindAdapter",
207
GDBUS_ARGS({ "pattern", "s" }),
208
GDBUS_ARGS({ "adapter", "o" }),
210
{ GDBUS_ASYNC_METHOD("ListAdapters",
211
NULL, GDBUS_ARGS({ "adapters", "ao" }),
216
static const GDBusSignalTable manager_signals[] = {
217
{ GDBUS_SIGNAL("PropertyChanged",
218
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
219
{ GDBUS_SIGNAL("AdapterAdded",
220
GDBUS_ARGS({ "adapter", "o" })) },
221
{ GDBUS_SIGNAL("AdapterRemoved",
222
GDBUS_ARGS({ "adapter", "o" })) },
223
{ GDBUS_SIGNAL("DefaultAdapterChanged",
224
GDBUS_ARGS({ "adapter", "o" })) },
228
dbus_bool_t manager_init(DBusConnection *conn, const char *path)
232
snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
234
return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
235
manager_methods, manager_signals,
239
static void manager_update_adapters(void)
245
array = g_new0(char *, g_slist_length(adapters) + 1);
246
for (i = 0, list = adapters; list; list = list->next) {
247
struct btd_adapter *adapter = list->data;
249
array[i] = (char *) adapter_get_path(adapter);
253
emit_array_property_changed(connection, "/",
254
MANAGER_INTERFACE, "Adapters",
255
DBUS_TYPE_OBJECT_PATH, &array, i);
260
static void manager_set_default_adapter(int id)
262
struct btd_adapter *adapter;
265
default_adapter_id = id;
267
adapter = manager_find_adapter_by_id(id);
271
path = adapter_get_path(adapter);
273
g_dbus_emit_signal(connection, "/",
275
"DefaultAdapterChanged",
276
DBUS_TYPE_OBJECT_PATH, &path,
280
struct btd_adapter *manager_get_default_adapter(void)
282
return manager_find_adapter_by_id(default_adapter_id);
285
static void manager_remove_adapter(struct btd_adapter *adapter)
287
uint16_t dev_id = adapter_get_dev_id(adapter);
288
const gchar *path = adapter_get_path(adapter);
290
adapters = g_slist_remove(adapters, adapter);
292
manager_update_adapters();
294
if (default_adapter_id == dev_id || default_adapter_id < 0) {
295
int new_default = hci_get_route(NULL);
297
manager_set_default_adapter(new_default);
300
g_dbus_emit_signal(connection, "/",
301
MANAGER_INTERFACE, "AdapterRemoved",
302
DBUS_TYPE_OBJECT_PATH, &path,
305
adapter_remove(adapter);
306
btd_adapter_unref(adapter);
308
if (adapters == NULL)
309
btd_start_exit_timer();
312
void manager_cleanup(DBusConnection *conn, const char *path)
315
struct btd_adapter *adapter = adapters->data;
317
adapters = g_slist_remove(adapters, adapter);
318
adapter_remove(adapter);
319
btd_adapter_unref(adapter);
322
btd_start_exit_timer();
324
g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
327
static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
329
struct btd_adapter *adapter = (struct btd_adapter *) a;
330
uint16_t id = GPOINTER_TO_UINT(b);
331
uint16_t dev_id = adapter_get_dev_id(adapter);
333
return dev_id == id ? 0 : -1;
336
static gint adapter_cmp(gconstpointer a, gconstpointer b)
338
struct btd_adapter *adapter = (struct btd_adapter *) a;
339
const bdaddr_t *bdaddr = b;
342
adapter_get_address(adapter, &src);
344
return bacmp(&src, bdaddr);
347
struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
351
match = g_slist_find_custom(adapters, sba, adapter_cmp);
358
struct btd_adapter *manager_find_adapter_by_id(int id)
362
match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
370
void manager_foreach_adapter(adapter_cb func, gpointer user_data)
372
g_slist_foreach(adapters, (GFunc) func, user_data);
375
GSList *manager_get_adapters(void)
380
void manager_add_adapter(const char *path)
382
g_dbus_emit_signal(connection, "/",
383
MANAGER_INTERFACE, "AdapterAdded",
384
DBUS_TYPE_OBJECT_PATH, &path,
387
manager_update_adapters();
389
btd_stop_exit_timer();
392
struct btd_adapter *btd_manager_register_adapter(int id, gboolean up)
394
struct btd_adapter *adapter;
397
adapter = manager_find_adapter_by_id(id);
399
error("Unable to register adapter: hci%d already exist", id);
403
adapter = adapter_create(connection, id);
407
adapters = g_slist_append(adapters, adapter);
409
if (!adapter_init(adapter, up)) {
410
adapters = g_slist_remove(adapters, adapter);
411
btd_adapter_unref(adapter);
415
path = adapter_get_path(adapter);
416
g_dbus_emit_signal(connection, "/",
417
MANAGER_INTERFACE, "AdapterAdded",
418
DBUS_TYPE_OBJECT_PATH, &path,
421
manager_update_adapters();
423
btd_stop_exit_timer();
425
if (default_adapter_id < 0)
426
manager_set_default_adapter(id);
428
if (main_opts.did_source)
429
btd_adapter_set_did(adapter, main_opts.did_vendor,
430
main_opts.did_product,
431
main_opts.did_version,
432
main_opts.did_source);
434
DBG("Adapter %s registered", path);
436
return btd_adapter_ref(adapter);
439
int btd_manager_unregister_adapter(int id)
441
struct btd_adapter *adapter;
444
adapter = manager_find_adapter_by_id(id);
448
path = adapter_get_path(adapter);
450
info("Unregister path: %s", path);
452
manager_remove_adapter(adapter);