1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 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. 13 * 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. 18 * 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 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <errno.h> 32 #include <unistd.h> 33 #include <sys/ioctl.h> 34 #include <sys/socket.h> 35 36 #include <bluetooth/bluetooth.h> 37 38 #include <glib.h> 39 40 #include <dbus/dbus.h> 41 42 #include <gdbus.h> 43 44 #include "hcid.h" 45 #include "dbus-common.h" 46 #include "log.h" 47 #include "adapter.h" 48 #include "error.h" 49 #include "manager.h" 50 51 static char base_path[50] = "/org/bluez"; 52 53 static DBusConnection *connection = NULL; 54 static int default_adapter_id = -1; 55 static GSList *adapters = NULL; 56 57 const char *manager_get_base_path(void) 58 { 59 return base_path; 60 } 61 62 static DBusMessage *default_adapter(DBusConnection *conn, 63 DBusMessage *msg, void *data) 64 { 65 DBusMessage *reply; 66 struct btd_adapter *adapter; 67 const gchar *path; 68 69 adapter = manager_find_adapter_by_id(default_adapter_id); 70 if (!adapter) 71 return btd_error_no_such_adapter(msg); 72 73 reply = dbus_message_new_method_return(msg); 74 if (!reply) 75 return NULL; 76 77 path = adapter_get_path(adapter); 78 79 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 80 DBUS_TYPE_INVALID); 81 82 return reply; 83 } 84 85 static DBusMessage *find_adapter(DBusConnection *conn, 86 DBusMessage *msg, void *data) 87 { 88 DBusMessage *reply; 89 struct btd_adapter *adapter; 90 const char *pattern; 91 int dev_id; 92 const gchar *path; 93 94 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern, 95 DBUS_TYPE_INVALID)) 96 return NULL; 97 98 /* hci_devid() would make sense to use here, except it is 99 * restricted to devices which are up */ 100 if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) { 101 path = adapter_any_get_path(); 102 if (path != NULL) 103 goto done; 104 return btd_error_no_such_adapter(msg); 105 } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) { 106 dev_id = atoi(pattern + 3); 107 adapter = manager_find_adapter_by_id(dev_id); 108 } else { 109 bdaddr_t bdaddr; 110 str2ba(pattern, &bdaddr); 111 adapter = manager_find_adapter(&bdaddr); 112 } 113 114 if (!adapter) 115 return btd_error_no_such_adapter(msg); 116 117 path = adapter_get_path(adapter); 118 119 done: 120 reply = dbus_message_new_method_return(msg); 121 if (!reply) 122 return NULL; 123 124 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 125 DBUS_TYPE_INVALID); 126 127 return reply; 128 } 129 130 static DBusMessage *list_adapters(DBusConnection *conn, 131 DBusMessage *msg, void *data) 132 { 133 DBusMessageIter iter; 134 DBusMessageIter array_iter; 135 DBusMessage *reply; 136 GSList *l; 137 138 reply = dbus_message_new_method_return(msg); 139 if (!reply) 140 return NULL; 141 142 dbus_message_iter_init_append(reply, &iter); 143 144 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 145 DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); 146 147 for (l = adapters; l; l = l->next) { 148 struct btd_adapter *adapter = l->data; 149 const gchar *path = adapter_get_path(adapter); 150 151 dbus_message_iter_append_basic(&array_iter, 152 DBUS_TYPE_OBJECT_PATH, &path); 153 } 154 155 dbus_message_iter_close_container(&iter, &array_iter); 156 157 return reply; 158 } 159 160 static DBusMessage *get_properties(DBusConnection *conn, 161 DBusMessage *msg, void *data) 162 { 163 DBusMessage *reply; 164 DBusMessageIter iter; 165 DBusMessageIter dict; 166 GSList *list; 167 char **array; 168 int i; 169 170 reply = dbus_message_new_method_return(msg); 171 if (!reply) 172 return NULL; 173 174 dbus_message_iter_init_append(reply, &iter); 175 176 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 177 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 178 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 179 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 180 181 array = g_new0(char *, g_slist_length(adapters) + 1); 182 for (i = 0, list = adapters; list; list = list->next) { 183 struct btd_adapter *adapter = list->data; 184 185 array[i] = (char *) adapter_get_path(adapter); 186 i++; 187 } 188 dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i); 189 g_free(array); 190 191 dbus_message_iter_close_container(&iter, &dict); 192 193 return reply; 194 } 195 196 static GDBusMethodTable manager_methods[] = { 197 { "GetProperties", "", "a{sv}",get_properties }, 198 { "DefaultAdapter", "", "o", default_adapter }, 199 { "FindAdapter", "s", "o", find_adapter }, 200 { "ListAdapters", "", "ao", list_adapters, 201 G_DBUS_METHOD_FLAG_DEPRECATED}, 202 { } 203 }; 204 205 static GDBusSignalTable manager_signals[] = { 206 { "PropertyChanged", "sv" }, 207 { "AdapterAdded", "o" }, 208 { "AdapterRemoved", "o" }, 209 { "DefaultAdapterChanged", "o" }, 210 { } 211 }; 212 213 dbus_bool_t manager_init(DBusConnection *conn, const char *path) 214 { 215 connection = conn; 216 217 snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid()); 218 219 return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE, 220 manager_methods, manager_signals, 221 NULL, NULL, NULL); 222 } 223 224 static void manager_update_adapters(void) 225 { 226 GSList *list; 227 char **array; 228 int i; 229 230 array = g_new0(char *, g_slist_length(adapters) + 1); 231 for (i = 0, list = adapters; list; list = list->next) { 232 struct btd_adapter *adapter = list->data; 233 234 array[i] = (char *) adapter_get_path(adapter); 235 i++; 236 } 237 238 emit_array_property_changed(connection, "/", 239 MANAGER_INTERFACE, "Adapters", 240 DBUS_TYPE_OBJECT_PATH, &array, i); 241 242 g_free(array); 243 } 244 245 static void manager_set_default_adapter(int id) 246 { 247 struct btd_adapter *adapter; 248 const gchar *path; 249 250 default_adapter_id = id; 251 252 adapter = manager_find_adapter_by_id(id); 253 if (!adapter) 254 return; 255 256 path = adapter_get_path(adapter); 257 258 g_dbus_emit_signal(connection, "/", 259 MANAGER_INTERFACE, 260 "DefaultAdapterChanged", 261 DBUS_TYPE_OBJECT_PATH, &path, 262 DBUS_TYPE_INVALID); 263 } 264 265 static void manager_remove_adapter(struct btd_adapter *adapter) 266 { 267 uint16_t dev_id = adapter_get_dev_id(adapter); 268 const gchar *path = adapter_get_path(adapter); 269 270 adapters = g_slist_remove(adapters, adapter); 271 272 manager_update_adapters(); 273 274 if (default_adapter_id == dev_id || default_adapter_id < 0) { 275 int new_default = hci_get_route(NULL); 276 277 manager_set_default_adapter(new_default); 278 } 279 280 g_dbus_emit_signal(connection, "/", 281 MANAGER_INTERFACE, "AdapterRemoved", 282 DBUS_TYPE_OBJECT_PATH, &path, 283 DBUS_TYPE_INVALID); 284 285 adapter_remove(adapter); 286 287 if (adapters == NULL) 288 btd_start_exit_timer(); 289 } 290 291 void manager_cleanup(DBusConnection *conn, const char *path) 292 { 293 g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL); 294 g_slist_free(adapters); 295 296 g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE); 297 } 298 299 static gint adapter_id_cmp(gconstpointer a, gconstpointer b) 300 { 301 struct btd_adapter *adapter = (struct btd_adapter *) a; 302 uint16_t id = GPOINTER_TO_UINT(b); 303 uint16_t dev_id = adapter_get_dev_id(adapter); 304 305 return dev_id == id ? 0 : -1; 306 } 307 308 static gint adapter_cmp(gconstpointer a, gconstpointer b) 309 { 310 struct btd_adapter *adapter = (struct btd_adapter *) a; 311 const bdaddr_t *bdaddr = b; 312 bdaddr_t src; 313 314 adapter_get_address(adapter, &src); 315 316 return bacmp(&src, bdaddr); 317 } 318 319 struct btd_adapter *manager_find_adapter(const bdaddr_t *sba) 320 { 321 GSList *match; 322 323 match = g_slist_find_custom(adapters, sba, adapter_cmp); 324 if (!match) 325 return NULL; 326 327 return match->data; 328 } 329 330 struct btd_adapter *manager_find_adapter_by_id(int id) 331 { 332 GSList *match; 333 334 match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), 335 adapter_id_cmp); 336 if (!match) 337 return NULL; 338 339 return match->data; 340 } 341 342 void manager_foreach_adapter(adapter_cb func, gpointer user_data) 343 { 344 g_slist_foreach(adapters, (GFunc) func, user_data); 345 } 346 347 GSList *manager_get_adapters(void) 348 { 349 return adapters; 350 } 351 352 void manager_add_adapter(const char *path) 353 { 354 g_dbus_emit_signal(connection, "/", 355 MANAGER_INTERFACE, "AdapterAdded", 356 DBUS_TYPE_OBJECT_PATH, &path, 357 DBUS_TYPE_INVALID); 358 359 manager_update_adapters(); 360 361 btd_stop_exit_timer(); 362 } 363 364 struct btd_adapter *btd_manager_register_adapter(int id) 365 { 366 struct btd_adapter *adapter; 367 const char *path; 368 369 adapter = manager_find_adapter_by_id(id); 370 if (adapter) { 371 error("Unable to register adapter: hci%d already exist", id); 372 return NULL; 373 } 374 375 adapter = adapter_create(connection, id); 376 if (!adapter) 377 return NULL; 378 379 adapters = g_slist_append(adapters, adapter); 380 381 if (!adapter_init(adapter)) { 382 btd_adapter_unref(adapter); 383 return NULL; 384 } 385 386 path = adapter_get_path(adapter); 387 g_dbus_emit_signal(connection, "/", 388 MANAGER_INTERFACE, "AdapterAdded", 389 DBUS_TYPE_OBJECT_PATH, &path, 390 DBUS_TYPE_INVALID); 391 392 manager_update_adapters(); 393 394 btd_stop_exit_timer(); 395 396 if (default_adapter_id < 0) 397 manager_set_default_adapter(id); 398 399 DBG("Adapter %s registered", path); 400 401 return btd_adapter_ref(adapter); 402 } 403 404 int btd_manager_unregister_adapter(int id) 405 { 406 struct btd_adapter *adapter; 407 const gchar *path; 408 409 adapter = manager_find_adapter_by_id(id); 410 if (!adapter) 411 return -1; 412 413 path = adapter_get_path(adapter); 414 415 info("Unregister path: %s", path); 416 417 manager_remove_adapter(adapter); 418 419 return 0; 420 } 421 422 void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version) 423 { 424 GSList *l; 425 426 for (l = adapters; l != NULL; l = g_slist_next(l)) { 427 struct btd_adapter *adapter = l->data; 428 429 btd_adapter_set_did(adapter, vendor, product, version); 430 } 431 } 432