1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2007 Nokia Corporation 6 * Copyright (C) 2004-2009 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 #include <bluetooth/hci.h> 38 #include <bluetooth/hci_lib.h> 39 40 #include <glib.h> 41 42 #include <dbus/dbus.h> 43 44 #include <gdbus.h> 45 46 #include "hcid.h" 47 #include "dbus-common.h" 48 #include "logging.h" 49 #include "adapter.h" 50 #include "error.h" 51 #include "manager.h" 52 53 static char base_path[50] = "/org/bluez"; 54 55 static DBusConnection *connection = NULL; 56 static int default_adapter_id = -1; 57 static GSList *adapters = NULL; 58 59 const char *manager_get_base_path(void) 60 { 61 return base_path; 62 } 63 64 void manager_update_svc(const bdaddr_t *bdaddr, uint8_t svc) 65 { 66 GSList *l; 67 bdaddr_t src; 68 69 for (l = adapters; l != NULL; l = l->next) { 70 struct btd_adapter *adapter = l->data; 71 72 adapter_get_address(adapter, &src); 73 74 if (bacmp(bdaddr, BDADDR_ANY) != 0 && bacmp(bdaddr, &src) != 0) 75 continue; 76 77 adapter_update(adapter, svc); 78 } 79 } 80 81 int manager_get_adapter_class(uint16_t dev_id, uint8_t *cls) 82 { 83 struct btd_adapter *adapter; 84 85 adapter = manager_find_adapter_by_id(dev_id); 86 if (!adapter) 87 return -EINVAL; 88 89 return adapter_get_class(adapter, cls); 90 } 91 92 static inline DBusMessage *invalid_args(DBusMessage *msg) 93 { 94 return g_dbus_create_error(msg, 95 ERROR_INTERFACE ".InvalidArguments", 96 "Invalid arguments in method call"); 97 } 98 99 static inline DBusMessage *no_such_adapter(DBusMessage *msg) 100 { 101 return g_dbus_create_error(msg, 102 ERROR_INTERFACE ".NoSuchAdapter", 103 "No such adapter"); 104 } 105 106 static DBusMessage *default_adapter(DBusConnection *conn, 107 DBusMessage *msg, void *data) 108 { 109 DBusMessage *reply; 110 struct btd_adapter *adapter; 111 const gchar *path; 112 113 adapter = manager_find_adapter_by_id(default_adapter_id); 114 if (!adapter) 115 return no_such_adapter(msg); 116 117 reply = dbus_message_new_method_return(msg); 118 if (!reply) 119 return NULL; 120 121 path = adapter_get_path(adapter); 122 123 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 124 DBUS_TYPE_INVALID); 125 126 return reply; 127 } 128 129 static DBusMessage *find_adapter(DBusConnection *conn, 130 DBusMessage *msg, void *data) 131 { 132 DBusMessage *reply; 133 struct btd_adapter *adapter; 134 const char *pattern; 135 int dev_id; 136 const gchar *path; 137 138 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern, 139 DBUS_TYPE_INVALID)) 140 return NULL; 141 142 /* hci_devid() would make sense to use here, except it 143 is restricted to devices which are up */ 144 if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) { 145 path = adapter_any_get_path(); 146 if (path != NULL) 147 goto done; 148 return no_such_adapter(msg); 149 } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) { 150 dev_id = atoi(pattern + 3); 151 adapter = manager_find_adapter_by_id(dev_id); 152 } else 153 adapter = manager_find_adapter_by_address(pattern); 154 155 if (!adapter) 156 return no_such_adapter(msg); 157 158 path = adapter_get_path(adapter); 159 160 done: 161 reply = dbus_message_new_method_return(msg); 162 if (!reply) 163 return NULL; 164 165 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 166 DBUS_TYPE_INVALID); 167 168 return reply; 169 } 170 171 static DBusMessage *list_adapters(DBusConnection *conn, 172 DBusMessage *msg, void *data) 173 { 174 DBusMessageIter iter; 175 DBusMessageIter array_iter; 176 DBusMessage *reply; 177 GSList *l; 178 179 reply = dbus_message_new_method_return(msg); 180 if (!reply) 181 return NULL; 182 183 dbus_message_iter_init_append(reply, &iter); 184 185 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 186 DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); 187 188 for (l = adapters; l; l = l->next) { 189 struct btd_adapter *adapter = l->data; 190 const gchar *path = adapter_get_path(adapter); 191 192 dbus_message_iter_append_basic(&array_iter, 193 DBUS_TYPE_OBJECT_PATH, &path); 194 } 195 196 dbus_message_iter_close_container(&iter, &array_iter); 197 198 return reply; 199 } 200 201 static DBusMessage *get_properties(DBusConnection *conn, 202 DBusMessage *msg, void *data) 203 { 204 DBusMessage *reply; 205 DBusMessageIter iter; 206 DBusMessageIter dict; 207 GSList *list; 208 char **array; 209 int i; 210 211 reply = dbus_message_new_method_return(msg); 212 if (!reply) 213 return NULL; 214 215 dbus_message_iter_init_append(reply, &iter); 216 217 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 218 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 219 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 220 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 221 222 array = g_new0(char *, g_slist_length(adapters) + 1); 223 for (i = 0, list = adapters; list; list = list->next, i++) { 224 struct btd_adapter *adapter = list->data; 225 226 if (!adapter_is_ready(adapter)) 227 continue; 228 229 array[i] = (char *) adapter_get_path(adapter); 230 } 231 dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i); 232 g_free(array); 233 234 dbus_message_iter_close_container(&iter, &dict); 235 236 return reply; 237 } 238 239 static GDBusMethodTable manager_methods[] = { 240 { "GetProperties", "", "a{sv}",get_properties }, 241 { "DefaultAdapter", "", "o", default_adapter }, 242 { "FindAdapter", "s", "o", find_adapter }, 243 { "ListAdapters", "", "ao", list_adapters }, 244 { } 245 }; 246 247 static GDBusSignalTable manager_signals[] = { 248 { "PropertyChanged", "sv" }, 249 { "AdapterAdded", "o" }, 250 { "AdapterRemoved", "o" }, 251 { "DefaultAdapterChanged", "o" }, 252 { } 253 }; 254 255 dbus_bool_t manager_init(DBusConnection *conn, const char *path) 256 { 257 connection = conn; 258 259 snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid()); 260 261 return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE, 262 manager_methods, manager_signals, 263 NULL, NULL, NULL); 264 } 265 266 static void manager_update_adapters(void) 267 { 268 GSList *list; 269 char **array; 270 int i; 271 272 array = g_new0(char *, g_slist_length(adapters) + 1); 273 for (i = 0, list = adapters; list; list = list->next, i++) { 274 struct btd_adapter *adapter = list->data; 275 276 if (!adapter_is_ready(adapter)) 277 continue; 278 279 array[i] = (char *) adapter_get_path(adapter); 280 } 281 282 emit_array_property_changed(connection, "/", 283 MANAGER_INTERFACE, "Adapters", 284 DBUS_TYPE_OBJECT_PATH, &array); 285 286 g_free(array); 287 } 288 289 static void manager_remove_adapter(struct btd_adapter *adapter) 290 { 291 uint16_t dev_id = adapter_get_dev_id(adapter); 292 const gchar *path = adapter_get_path(adapter); 293 294 adapters = g_slist_remove(adapters, adapter); 295 296 manager_update_adapters(); 297 298 if (default_adapter_id == dev_id || default_adapter_id < 0) { 299 int new_default = hci_get_route(NULL); 300 301 manager_set_default_adapter(new_default); 302 } 303 304 g_dbus_emit_signal(connection, "/", 305 MANAGER_INTERFACE, "AdapterRemoved", 306 DBUS_TYPE_OBJECT_PATH, &path, 307 DBUS_TYPE_INVALID); 308 309 adapter_remove(adapter); 310 311 if (adapters == NULL) 312 btd_start_exit_timer(); 313 } 314 315 void manager_cleanup(DBusConnection *conn, const char *path) 316 { 317 g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL); 318 g_slist_free(adapters); 319 320 g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE); 321 } 322 323 static gint adapter_id_cmp(gconstpointer a, gconstpointer b) 324 { 325 struct btd_adapter *adapter = (struct btd_adapter *) a; 326 uint16_t id = GPOINTER_TO_UINT(b); 327 uint16_t dev_id = adapter_get_dev_id(adapter); 328 329 return dev_id == id ? 0 : -1; 330 } 331 332 static gint adapter_path_cmp(gconstpointer a, gconstpointer b) 333 { 334 struct btd_adapter *adapter = (struct btd_adapter *) a; 335 const char *path = b; 336 const gchar *adapter_path = adapter_get_path(adapter); 337 338 return strcmp(adapter_path, path); 339 } 340 341 static gint adapter_cmp(gconstpointer a, gconstpointer b) 342 { 343 struct btd_adapter *adapter = (struct btd_adapter *) a; 344 const bdaddr_t *bdaddr = b; 345 bdaddr_t src; 346 347 adapter_get_address(adapter, &src); 348 349 return bacmp(&src, bdaddr); 350 } 351 352 static gint adapter_address_cmp(gconstpointer a, gconstpointer b) 353 { 354 struct btd_adapter *adapter = (struct btd_adapter *) a; 355 const char *address = b; 356 bdaddr_t bdaddr; 357 char addr[18]; 358 359 adapter_get_address(adapter, &bdaddr); 360 ba2str(&bdaddr, addr); 361 362 return strcmp(addr, address); 363 } 364 365 struct btd_adapter *manager_find_adapter(const bdaddr_t *sba) 366 { 367 GSList *match; 368 369 match = g_slist_find_custom(adapters, sba, adapter_cmp); 370 if (!match) 371 return NULL; 372 373 return match->data; 374 } 375 376 struct btd_adapter *manager_find_adapter_by_address(const char *address) 377 { 378 GSList *match; 379 380 match = g_slist_find_custom(adapters, address, adapter_address_cmp); 381 if (!match) 382 return NULL; 383 384 return match->data; 385 } 386 387 struct btd_adapter *manager_find_adapter_by_path(const char *path) 388 { 389 GSList *match; 390 391 match = g_slist_find_custom(adapters, path, adapter_path_cmp); 392 if (!match) 393 return NULL; 394 395 return match->data; 396 } 397 398 struct btd_adapter *manager_find_adapter_by_id(int id) 399 { 400 GSList *match; 401 402 match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), adapter_id_cmp); 403 if (!match) 404 return NULL; 405 406 return match->data; 407 } 408 409 GSList *manager_get_adapters(void) 410 { 411 return adapters; 412 } 413 414 void manager_add_adapter(const char *path) 415 { 416 g_dbus_emit_signal(connection, "/", 417 MANAGER_INTERFACE, "AdapterAdded", 418 DBUS_TYPE_OBJECT_PATH, &path, 419 DBUS_TYPE_INVALID); 420 421 manager_update_adapters(); 422 423 btd_stop_exit_timer(); 424 } 425 426 int manager_register_adapter(int id, gboolean devup) 427 { 428 struct btd_adapter *adapter; 429 430 adapter = manager_find_adapter_by_id(id); 431 if (adapter) { 432 error("Unable to register adapter: hci%d already exist", id); 433 return -1; 434 } 435 436 adapter = adapter_create(connection, id, devup); 437 if (!adapter) 438 return -1; 439 440 adapters = g_slist_append(adapters, adapter); 441 442 return 0; 443 } 444 445 int manager_unregister_adapter(int id) 446 { 447 struct btd_adapter *adapter; 448 const gchar *path; 449 450 adapter = manager_find_adapter_by_id(id); 451 if (!adapter) 452 return -1; 453 454 path = adapter_get_path(adapter); 455 456 info("Unregister path: %s", path); 457 458 manager_remove_adapter(adapter); 459 460 return 0; 461 } 462 463 int manager_start_adapter(int id) 464 { 465 struct btd_adapter* adapter; 466 int ret; 467 468 adapter = manager_find_adapter_by_id(id); 469 if (!adapter) { 470 error("Getting device data failed: hci%d", id); 471 return -EINVAL; 472 } 473 474 ret = adapter_start(adapter); 475 if (ret < 0) 476 return ret; 477 478 if (default_adapter_id < 0) 479 manager_set_default_adapter(id); 480 481 return ret; 482 } 483 484 int manager_stop_adapter(int id) 485 { 486 struct btd_adapter *adapter; 487 488 adapter = manager_find_adapter_by_id(id); 489 if (!adapter) { 490 error("Getting device data failed: hci%d", id); 491 return -EINVAL; 492 } 493 494 return adapter_stop(adapter); 495 } 496 497 int manager_get_default_adapter() 498 { 499 return default_adapter_id; 500 } 501 502 void manager_set_default_adapter(int id) 503 { 504 struct btd_adapter *adapter; 505 const gchar *path; 506 507 default_adapter_id = id; 508 509 adapter = manager_find_adapter_by_id(id); 510 if (!adapter) 511 return; 512 513 path = adapter_get_path(adapter); 514 515 g_dbus_emit_signal(connection, "/", 516 MANAGER_INTERFACE, 517 "DefaultAdapterChanged", 518 DBUS_TYPE_OBJECT_PATH, &path, 519 DBUS_TYPE_INVALID); 520 } 521 522 void btd_manager_set_offline(gboolean offline) 523 { 524 GSList *l; 525 526 for (l = adapters; l != NULL; l = g_slist_next(l)) { 527 struct btd_adapter *adapter = l->data; 528 529 if (offline) 530 btd_adapter_switch_offline(adapter); 531 else 532 btd_adapter_restore_powered(adapter); 533 } 534 } 535