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