1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2000-2001 Qualcomm Incorporated 6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk (at) qualcomm.com> 7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel (at) holtmann.org> 8 * 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include <config.h> 28 #endif 29 30 #include <errno.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 39 #include <bluetooth/bluetooth.h> 40 #include <bluetooth/uuid.h> 41 42 #include <glib.h> 43 44 #include <dbus/dbus.h> 45 46 #include <gdbus.h> 47 48 #include "log.h" 49 50 #include "hcid.h" 51 #include "sdpd.h" 52 #include "attrib-server.h" 53 #include "adapter.h" 54 #include "dbus-common.h" 55 #include "agent.h" 56 #include "manager.h" 57 58 #ifdef HAVE_CAPNG 59 #include <cap-ng.h> 60 #endif 61 62 #define BLUEZ_NAME "org.bluez" 63 64 #define LAST_ADAPTER_EXIT_TIMEOUT 30 65 66 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */ 67 68 struct main_opts main_opts; 69 70 static GKeyFile *load_config(const char *file) 71 { 72 GError *err = NULL; 73 GKeyFile *keyfile; 74 75 keyfile = g_key_file_new(); 76 77 g_key_file_set_list_separator(keyfile, ','); 78 79 if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { 80 error("Parsing %s failed: %s", file, err->message); 81 g_error_free(err); 82 g_key_file_free(keyfile); 83 return NULL; 84 } 85 86 return keyfile; 87 } 88 89 static void parse_config(GKeyFile *config) 90 { 91 GError *err = NULL; 92 char *str; 93 int val; 94 gboolean boolean; 95 96 if (!config) 97 return; 98 99 DBG("parsing main.conf"); 100 101 val = g_key_file_get_integer(config, "General", 102 "DiscoverableTimeout", &err); 103 if (err) { 104 DBG("%s", err->message); 105 g_clear_error(&err); 106 } else { 107 DBG("discovto=%d", val); 108 main_opts.discovto = val; 109 main_opts.flags |= 1 << HCID_SET_DISCOVTO; 110 } 111 112 val = g_key_file_get_integer(config, "General", 113 "PairableTimeout", &err); 114 if (err) { 115 DBG("%s", err->message); 116 g_clear_error(&err); 117 } else { 118 DBG("pairto=%d", val); 119 main_opts.pairto = val; 120 } 121 122 val = g_key_file_get_integer(config, "General", "PageTimeout", &err); 123 if (err) { 124 DBG("%s", err->message); 125 g_clear_error(&err); 126 } else { 127 DBG("pageto=%d", val); 128 main_opts.pageto = val; 129 main_opts.flags |= 1 << HCID_SET_PAGETO; 130 } 131 132 str = g_key_file_get_string(config, "General", "Name", &err); 133 if (err) { 134 DBG("%s", err->message); 135 g_clear_error(&err); 136 } else { 137 DBG("name=%s", str); 138 g_free(main_opts.name); 139 main_opts.name = g_strdup(str); 140 main_opts.flags |= 1 << HCID_SET_NAME; 141 g_free(str); 142 } 143 144 str = g_key_file_get_string(config, "General", "Class", &err); 145 if (err) { 146 DBG("%s", err->message); 147 g_clear_error(&err); 148 } else { 149 DBG("class=%s", str); 150 main_opts.class = strtol(str, NULL, 16); 151 main_opts.flags |= 1 << HCID_SET_CLASS; 152 g_free(str); 153 } 154 155 val = g_key_file_get_integer(config, "General", 156 "DiscoverSchedulerInterval", &err); 157 if (err) { 158 DBG("%s", err->message); 159 g_clear_error(&err); 160 } else { 161 DBG("discov_interval=%d", val); 162 main_opts.discov_interval = val; 163 } 164 165 boolean = g_key_file_get_boolean(config, "General", 166 "InitiallyPowered", &err); 167 if (err) { 168 DBG("%s", err->message); 169 g_clear_error(&err); 170 } else if (boolean == FALSE) 171 main_opts.mode = MODE_OFF; 172 173 boolean = g_key_file_get_boolean(config, "General", 174 "RememberPowered", &err); 175 if (err) { 176 DBG("%s", err->message); 177 g_clear_error(&err); 178 } else 179 main_opts.remember_powered = boolean; 180 181 str = g_key_file_get_string(config, "General", "DeviceID", &err); 182 if (err) { 183 DBG("%s", err->message); 184 g_clear_error(&err); 185 } else { 186 DBG("deviceid=%s", str); 187 strncpy(main_opts.deviceid, str, 188 sizeof(main_opts.deviceid) - 1); 189 g_free(str); 190 } 191 192 boolean = g_key_file_get_boolean(config, "General", 193 "ReverseServiceDiscovery", &err); 194 if (err) { 195 DBG("%s", err->message); 196 g_clear_error(&err); 197 } else 198 main_opts.reverse_sdp = boolean; 199 200 boolean = g_key_file_get_boolean(config, "General", 201 "NameResolving", &err); 202 if (err) 203 g_clear_error(&err); 204 else 205 main_opts.name_resolv = boolean; 206 207 boolean = g_key_file_get_boolean(config, "General", 208 "DebugKeys", &err); 209 if (err) 210 g_clear_error(&err); 211 else 212 main_opts.debug_keys = boolean; 213 214 boolean = g_key_file_get_boolean(config, "General", 215 "AttributeServer", &err); 216 if (err) 217 g_clear_error(&err); 218 else 219 main_opts.attrib_server = boolean; 220 221 boolean = g_key_file_get_boolean(config, "General", 222 "EnableLE", &err); 223 if (err) 224 g_clear_error(&err); 225 else 226 main_opts.le = boolean; 227 228 main_opts.link_mode = HCI_LM_ACCEPT; 229 230 main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | 231 HCI_LP_HOLD | HCI_LP_PARK; 232 233 str = g_key_file_get_string(config, "General", 234 "DefaultLinkPolicy", &err); 235 if (err) 236 g_clear_error(&err); 237 else { 238 DBG("default_link_policy=%s", str); 239 main_opts.link_policy &= strtol(str, NULL, 16); 240 } 241 } 242 243 static void init_defaults(void) 244 { 245 /* Default HCId settings */ 246 memset(&main_opts, 0, sizeof(main_opts)); 247 main_opts.mode = MODE_CONNECTABLE; 248 main_opts.name = g_strdup("BlueZ"); 249 main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT; 250 main_opts.remember_powered = TRUE; 251 main_opts.reverse_sdp = TRUE; 252 main_opts.name_resolv = TRUE; 253 main_opts.link_mode = HCI_LM_ACCEPT; 254 main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | 255 HCI_LP_HOLD | HCI_LP_PARK; 256 257 if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0) 258 strcpy(main_opts.host_name, "noname"); 259 } 260 261 static GMainLoop *event_loop; 262 263 static void sig_term(int sig) 264 { 265 g_main_loop_quit(event_loop); 266 } 267 268 static void sig_debug(int sig) 269 { 270 __btd_toggle_debug(); 271 } 272 273 static gchar *option_debug = NULL; 274 static gchar *option_plugin = NULL; 275 static gchar *option_noplugin = NULL; 276 static gboolean option_detach = TRUE; 277 static gboolean option_version = FALSE; 278 static gboolean option_udev = FALSE; 279 280 static guint last_adapter_timeout = 0; 281 282 static gboolean exit_timeout(gpointer data) 283 { 284 g_main_loop_quit(event_loop); 285 last_adapter_timeout = 0; 286 return FALSE; 287 } 288 289 void btd_start_exit_timer(void) 290 { 291 if (option_udev == FALSE) 292 return; 293 294 if (last_adapter_timeout > 0) 295 g_source_remove(last_adapter_timeout); 296 297 last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT, 298 exit_timeout, NULL); 299 } 300 301 void btd_stop_exit_timer(void) 302 { 303 if (last_adapter_timeout == 0) 304 return; 305 306 g_source_remove(last_adapter_timeout); 307 last_adapter_timeout = 0; 308 } 309 310 static void disconnect_dbus(void) 311 { 312 DBusConnection *conn = get_dbus_connection(); 313 314 if (!conn || !dbus_connection_get_is_connected(conn)) 315 return; 316 317 manager_cleanup(conn, "/"); 318 319 set_dbus_connection(NULL); 320 321 dbus_connection_unref(conn); 322 } 323 324 static int connect_dbus(void) 325 { 326 DBusConnection *conn; 327 DBusError err; 328 329 dbus_error_init(&err); 330 331 conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err); 332 if (!conn) { 333 if (dbus_error_is_set(&err)) { 334 dbus_error_free(&err); 335 return -EIO; 336 } 337 return -EALREADY; 338 } 339 340 if (!manager_init(conn, "/")) 341 return -EIO; 342 343 set_dbus_connection(conn); 344 345 return 0; 346 } 347 348 static gboolean parse_debug(const char *key, const char *value, 349 gpointer user_data, GError **error) 350 { 351 if (value) 352 option_debug = g_strdup(value); 353 else 354 option_debug = g_strdup("*"); 355 356 return TRUE; 357 } 358 359 static GOptionEntry options[] = { 360 { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, 361 G_OPTION_ARG_CALLBACK, parse_debug, 362 "Specify debug options to enable", "DEBUG" }, 363 { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin, 364 "Specify plugins to load", "NAME,..," }, 365 { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin, 366 "Specify plugins not to load", "NAME,..." }, 367 { "nodetach", 'n', G_OPTION_FLAG_REVERSE, 368 G_OPTION_ARG_NONE, &option_detach, 369 "Don't run as daemon in background" }, 370 { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, 371 "Show version information and exit" }, 372 { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev, 373 "Run from udev mode of operation" }, 374 { NULL }, 375 }; 376 377 int main(int argc, char *argv[]) 378 { 379 GOptionContext *context; 380 GError *err = NULL; 381 struct sigaction sa; 382 uint16_t mtu = 0; 383 GKeyFile *config; 384 385 #ifdef ANDROID_SET_AID_AND_CAP 386 /* Unfortunately Android's init.rc does not yet support applying 387 * capabilities. So we must do it in-process. */ 388 void *android_set_aid_and_cap(void); 389 android_set_aid_and_cap(); 390 #endif 391 392 init_defaults(); 393 394 #ifdef HAVE_CAPNG 395 /* Drop capabilities */ 396 capng_clear(CAPNG_SELECT_BOTH); 397 capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, 398 CAP_NET_BIND_SERVICE, CAP_NET_ADMIN, 399 CAP_NET_RAW, CAP_IPC_LOCK, -1); 400 capng_apply(CAPNG_SELECT_BOTH); 401 #endif 402 403 context = g_option_context_new(NULL); 404 g_option_context_add_main_entries(context, options, NULL); 405 406 if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) { 407 if (err != NULL) { 408 g_printerr("%s\n", err->message); 409 g_error_free(err); 410 } else 411 g_printerr("An unknown error occurred\n"); 412 exit(1); 413 } 414 415 g_option_context_free(context); 416 417 if (option_version == TRUE) { 418 printf("%s\n", VERSION); 419 exit(0); 420 } 421 422 if (option_udev == TRUE) { 423 int err; 424 425 option_detach = TRUE; 426 err = connect_dbus(); 427 if (err < 0) { 428 if (err == -EALREADY) 429 exit(0); 430 exit(1); 431 } 432 } 433 434 if (option_detach == TRUE && option_udev == FALSE) { 435 if (daemon(0, 0)) { 436 perror("Can't start daemon"); 437 exit(1); 438 } 439 } 440 441 umask(0077); 442 443 __btd_log_init(option_debug, option_detach); 444 445 memset(&sa, 0, sizeof(sa)); 446 sa.sa_flags = SA_NOCLDSTOP; 447 sa.sa_handler = sig_term; 448 sigaction(SIGTERM, &sa, NULL); 449 sigaction(SIGINT, &sa, NULL); 450 451 sa.sa_handler = sig_debug; 452 sigaction(SIGUSR2, &sa, NULL); 453 454 sa.sa_handler = SIG_IGN; 455 sigaction(SIGPIPE, &sa, NULL); 456 457 config = load_config(CONFIGDIR "/main.conf"); 458 459 parse_config(config); 460 461 agent_init(); 462 463 if (option_udev == FALSE) { 464 if (connect_dbus() < 0) { 465 error("Unable to get on D-Bus"); 466 exit(1); 467 } 468 } else { 469 if (daemon(0, 0)) { 470 perror("Can't start daemon"); 471 exit(1); 472 } 473 } 474 475 start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT); 476 477 if (main_opts.attrib_server) { 478 if (attrib_server_init() < 0) 479 error("Can't initialize attribute server"); 480 } 481 482 /* Loading plugins has to be done after D-Bus has been setup since 483 * the plugins might wanna expose some paths on the bus. However the 484 * best order of how to init various subsystems of the Bluetooth 485 * daemon needs to be re-worked. */ 486 plugin_init(config, option_plugin, option_noplugin); 487 488 event_loop = g_main_loop_new(NULL, FALSE); 489 490 if (adapter_ops_setup() < 0) { 491 error("adapter_ops_setup failed"); 492 exit(1); 493 } 494 495 rfkill_init(); 496 497 DBG("Entering main loop"); 498 499 g_main_loop_run(event_loop); 500 501 disconnect_dbus(); 502 503 rfkill_exit(); 504 505 plugin_cleanup(); 506 507 if (main_opts.attrib_server) 508 attrib_server_exit(); 509 510 stop_sdp_server(); 511 512 agent_exit(); 513 514 g_main_loop_unref(event_loop); 515 516 if (config) 517 g_key_file_free(config); 518 519 info("Exit"); 520 521 __btd_log_cleanup(); 522 523 return 0; 524 } 525