Home | History | Annotate | Download | only in src
      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/stat.h>
     37 #include <sys/ioctl.h>
     38 #include <sys/socket.h>
     39 #include <sys/types.h>
     40 
     41 #include <bluetooth/bluetooth.h>
     42 #include <bluetooth/hci.h>
     43 #include <bluetooth/hci_lib.h>
     44 
     45 #include <glib.h>
     46 
     47 #ifdef ANDROID_EXPAND_NAME
     48 #include <cutils/properties.h>
     49 #endif
     50 
     51 #include <dbus/dbus.h>
     52 
     53 #include "log.h"
     54 
     55 #include "hcid.h"
     56 #include "sdpd.h"
     57 #include "adapter.h"
     58 #include "dbus-hci.h"
     59 #include "dbus-common.h"
     60 #include "agent.h"
     61 #include "manager.h"
     62 
     63 #ifdef HAVE_CAPNG
     64 #include <cap-ng.h>
     65 #endif
     66 
     67 #define LAST_ADAPTER_EXIT_TIMEOUT 30
     68 
     69 struct main_opts main_opts;
     70 
     71 static GKeyFile *load_config(const char *file)
     72 {
     73 	GError *err = NULL;
     74 	GKeyFile *keyfile;
     75 
     76 	keyfile = g_key_file_new();
     77 
     78 	g_key_file_set_list_separator(keyfile, ',');
     79 
     80 	if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
     81 		error("Parsing %s failed: %s", file, err->message);
     82 		g_error_free(err);
     83 		g_key_file_free(keyfile);
     84 		return NULL;
     85 	}
     86 
     87 	return keyfile;
     88 }
     89 
     90 static void parse_config(GKeyFile *config)
     91 {
     92 	GError *err = NULL;
     93 	char *str;
     94 	int val;
     95 	gboolean boolean;
     96 
     97 	if (!config)
     98 		return;
     99 
    100 	DBG("parsing main.conf");
    101 
    102 	val = g_key_file_get_integer(config, "General",
    103 						"DiscoverableTimeout", &err);
    104 	if (err) {
    105 		DBG("%s", err->message);
    106 		g_clear_error(&err);
    107 	} else {
    108 		DBG("discovto=%d", val);
    109 		main_opts.discovto = val;
    110 		main_opts.flags |= 1 << HCID_SET_DISCOVTO;
    111 	}
    112 
    113 	val = g_key_file_get_integer(config, "General",
    114 						"PairableTimeout", &err);
    115 	if (err) {
    116 		DBG("%s", err->message);
    117 		g_clear_error(&err);
    118 	} else {
    119 		DBG("pairto=%d", val);
    120 		main_opts.pairto = val;
    121 	}
    122 
    123 	val = g_key_file_get_integer(config, "General", "PageTimeout", &err);
    124 	if (err) {
    125 		DBG("%s", err->message);
    126 		g_clear_error(&err);
    127 	} else {
    128 		DBG("pageto=%d", val);
    129 		main_opts.pageto = val;
    130 		main_opts.flags |= 1 << HCID_SET_PAGETO;
    131 	}
    132 
    133 	str = g_key_file_get_string(config, "General", "Name", &err);
    134 	if (err) {
    135 		DBG("%s", err->message);
    136 		g_clear_error(&err);
    137 	} else {
    138 		DBG("name=%s", str);
    139 		g_free(main_opts.name);
    140 		main_opts.name = g_strdup(str);
    141 		main_opts.flags |= 1 << HCID_SET_NAME;
    142 		g_free(str);
    143 	}
    144 
    145 	str = g_key_file_get_string(config, "General", "Class", &err);
    146 	if (err) {
    147 		DBG("%s", err->message);
    148 		g_clear_error(&err);
    149 	} else {
    150 		DBG("class=%s", str);
    151 		main_opts.class = strtol(str, NULL, 16);
    152 		main_opts.flags |= 1 << HCID_SET_CLASS;
    153 		g_free(str);
    154 	}
    155 
    156 	val = g_key_file_get_integer(config, "General",
    157 					"DiscoverSchedulerInterval", &err);
    158 	if (err) {
    159 		DBG("%s", err->message);
    160 		g_clear_error(&err);
    161 	} else {
    162 		DBG("discov_interval=%d", val);
    163 		main_opts.discov_interval = val;
    164 	}
    165 
    166 	boolean = g_key_file_get_boolean(config, "General",
    167 						"InitiallyPowered", &err);
    168 	if (err) {
    169 		DBG("%s", err->message);
    170 		g_clear_error(&err);
    171 	} else if (boolean == FALSE)
    172 		main_opts.mode = MODE_OFF;
    173 
    174 	boolean = g_key_file_get_boolean(config, "General",
    175 						"RememberPowered", &err);
    176 	if (err) {
    177 		DBG("%s", err->message);
    178 		g_clear_error(&err);
    179 	} else
    180 		main_opts.remember_powered = boolean;
    181 
    182 	str = g_key_file_get_string(config, "General", "DeviceID", &err);
    183 	if (err) {
    184 		DBG("%s", err->message);
    185 		g_clear_error(&err);
    186 	} else {
    187 		DBG("deviceid=%s", str);
    188 		strncpy(main_opts.deviceid, str,
    189 					sizeof(main_opts.deviceid) - 1);
    190 		g_free(str);
    191 	}
    192 
    193 	boolean = g_key_file_get_boolean(config, "General",
    194 						"ReverseServiceDiscovery", &err);
    195 	if (err) {
    196 		DBG("%s", err->message);
    197 		g_clear_error(&err);
    198 	} else
    199 		main_opts.reverse_sdp = boolean;
    200 
    201 	boolean = g_key_file_get_boolean(config, "General",
    202 						"NameResolving", &err);
    203 	if (err)
    204 		g_clear_error(&err);
    205 	else
    206 		main_opts.name_resolv = boolean;
    207 
    208 	boolean = g_key_file_get_boolean(config, "General",
    209 						"DebugKeys", &err);
    210 	if (err)
    211 		g_clear_error(&err);
    212 	else
    213 		main_opts.debug_keys = boolean;
    214 
    215 	main_opts.link_mode = HCI_LM_ACCEPT;
    216 
    217 	main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
    218 						HCI_LP_HOLD | HCI_LP_PARK;
    219 	str = g_key_file_get_string(config, "General",
    220 						"DefaultLinkPolicy", &err);
    221 	if (err)
    222 		g_clear_error(&err);
    223 	else {
    224 		DBG("default_link_policy=%s", str);
    225 		main_opts.link_policy &= strtol(str, NULL, 16);
    226 	}
    227 }
    228 
    229 /*
    230  * Device name expansion
    231  *   %d - device id
    232  */
    233 char *expand_name(char *dst, int size, char *str, int dev_id)
    234 {
    235 	register int sp, np, olen;
    236 	char *opt, buf[10];
    237 
    238 #ifdef ANDROID_EXPAND_NAME
    239 	char value[PROPERTY_VALUE_MAX];
    240 #endif
    241 
    242 	if (!str || !dst)
    243 		return NULL;
    244 
    245 	sp = np = 0;
    246 	while (np < size - 1 && str[sp]) {
    247 		switch (str[sp]) {
    248 		case '%':
    249 			opt = NULL;
    250 
    251 			switch (str[sp+1]) {
    252 			case 'd':
    253 				sprintf(buf, "%d", dev_id);
    254 				opt = buf;
    255 				break;
    256 
    257 			case 'h':
    258 				opt = main_opts.host_name;
    259 				break;
    260 
    261 #ifdef ANDROID_EXPAND_NAME
    262 			case 'b':
    263 				property_get("ro.product.brand", value, "");
    264 				opt = value;
    265 			break;
    266 
    267 			case 'm':
    268 				property_get("ro.product.model", value, "");
    269 				opt = value;
    270 			break;
    271 
    272 			case 'n':
    273 				property_get("ro.product.name", value, "");
    274 				opt = value;
    275 			break;
    276 #endif
    277 
    278 			case '%':
    279 				dst[np++] = str[sp++];
    280 				/* fall through */
    281 			default:
    282 				sp++;
    283 				continue;
    284 			}
    285 
    286 			if (opt) {
    287 				/* substitute */
    288 				olen = strlen(opt);
    289 				if (np + olen < size - 1)
    290 					memcpy(dst + np, opt, olen);
    291 				np += olen;
    292 			}
    293 			sp += 2;
    294 			continue;
    295 
    296 		case '\\':
    297 			sp++;
    298 			/* fall through */
    299 		default:
    300 			dst[np++] = str[sp++];
    301 			break;
    302 		}
    303 	}
    304 	dst[np] = '\0';
    305 	return dst;
    306 }
    307 
    308 static void init_defaults(void)
    309 {
    310 	/* Default HCId settings */
    311 	memset(&main_opts, 0, sizeof(main_opts));
    312 	main_opts.scan	= SCAN_PAGE;
    313 	main_opts.mode	= MODE_CONNECTABLE;
    314 	main_opts.name	= g_strdup("BlueZ");
    315 	main_opts.discovto	= HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
    316 	main_opts.remember_powered = TRUE;
    317 	main_opts.reverse_sdp = TRUE;
    318 	main_opts.name_resolv = TRUE;
    319 	main_opts.link_mode = HCI_LM_ACCEPT;
    320 	main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
    321 						HCI_LP_HOLD | HCI_LP_PARK;
    322 
    323 	if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0)
    324 		strcpy(main_opts.host_name, "noname");
    325 }
    326 
    327 static GMainLoop *event_loop;
    328 
    329 static void sig_term(int sig)
    330 {
    331 	g_main_loop_quit(event_loop);
    332 }
    333 
    334 static void sig_debug(int sig)
    335 {
    336 	__btd_toggle_debug();
    337 }
    338 
    339 static gchar *option_debug = NULL;
    340 static gboolean option_detach = TRUE;
    341 static gboolean option_version = FALSE;
    342 static gboolean option_udev = FALSE;
    343 
    344 static guint last_adapter_timeout = 0;
    345 
    346 static gboolean exit_timeout(gpointer data)
    347 {
    348 	g_main_loop_quit(event_loop);
    349 	last_adapter_timeout = 0;
    350 	return FALSE;
    351 }
    352 
    353 void btd_start_exit_timer(void)
    354 {
    355 	if (option_udev == FALSE)
    356 		return;
    357 
    358 	if (last_adapter_timeout > 0)
    359 		g_source_remove(last_adapter_timeout);
    360 
    361 	last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT,
    362 						exit_timeout, NULL);
    363 }
    364 
    365 void btd_stop_exit_timer(void)
    366 {
    367 	if (last_adapter_timeout == 0)
    368 		return;
    369 
    370 	g_source_remove(last_adapter_timeout);
    371 	last_adapter_timeout = 0;
    372 }
    373 
    374 static gboolean parse_debug(const char *key, const char *value,
    375 				gpointer user_data, GError **error)
    376 {
    377 	if (value)
    378 		option_debug = g_strdup(value);
    379 	else
    380 		option_debug = g_strdup("*");
    381 
    382 	return TRUE;
    383 }
    384 
    385 static GOptionEntry options[] = {
    386 	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
    387 				G_OPTION_ARG_CALLBACK, parse_debug,
    388 				"Specify debug options to enable", "DEBUG" },
    389 	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
    390 				G_OPTION_ARG_NONE, &option_detach,
    391 				"Don't run as daemon in background" },
    392 	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
    393 				"Show version information and exit" },
    394 	{ "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev,
    395 				"Run from udev mode of operation" },
    396 	{ NULL },
    397 };
    398 
    399 int main(int argc, char *argv[])
    400 {
    401 	GOptionContext *context;
    402 	GError *err = NULL;
    403 	struct sigaction sa;
    404 	uint16_t mtu = 0;
    405 	GKeyFile *config;
    406 
    407 #ifdef ANDROID_SET_AID_AND_CAP
    408 	/* Unfortunately Android's init.rc does not yet support applying
    409 	 * capabilities. So we must do it in-process. */
    410 	void *android_set_aid_and_cap(void);
    411 	android_set_aid_and_cap();
    412 #endif
    413 
    414 	init_defaults();
    415 
    416 #ifdef HAVE_CAPNG
    417 	/* Drop capabilities */
    418 	capng_clear(CAPNG_SELECT_BOTH);
    419 	capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
    420 					CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
    421 						CAP_NET_RAW, CAP_IPC_LOCK, -1);
    422 	capng_apply(CAPNG_SELECT_BOTH);
    423 #endif
    424 
    425 	context = g_option_context_new(NULL);
    426 	g_option_context_add_main_entries(context, options, NULL);
    427 
    428 	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
    429 		if (err != NULL) {
    430 			g_printerr("%s\n", err->message);
    431 			g_error_free(err);
    432 		} else
    433 			g_printerr("An unknown error occurred\n");
    434 		exit(1);
    435 	}
    436 
    437 	g_option_context_free(context);
    438 
    439 	if (option_version == TRUE) {
    440 		printf("%s\n", VERSION);
    441 		exit(0);
    442 	}
    443 
    444 	if (option_udev == TRUE) {
    445 		int err;
    446 
    447 		option_detach = TRUE;
    448 		err = hcid_dbus_init();
    449 		if (err < 0) {
    450 			if (err == -EALREADY)
    451 				exit(0);
    452 			exit(1);
    453 		}
    454 	}
    455 
    456 	if (option_detach == TRUE && option_udev == FALSE) {
    457 		if (daemon(0, 0)) {
    458 			perror("Can't start daemon");
    459 			exit(1);
    460 		}
    461 	}
    462 
    463 	umask(0077);
    464 
    465 	__btd_log_init(option_debug, option_detach);
    466 
    467 	memset(&sa, 0, sizeof(sa));
    468 	sa.sa_flags = SA_NOCLDSTOP;
    469 	sa.sa_handler = sig_term;
    470 	sigaction(SIGTERM, &sa, NULL);
    471 	sigaction(SIGINT,  &sa, NULL);
    472 
    473 	sa.sa_handler = sig_debug;
    474 	sigaction(SIGUSR2, &sa, NULL);
    475 
    476 	sa.sa_handler = SIG_IGN;
    477 	sigaction(SIGPIPE, &sa, NULL);
    478 
    479 	config = load_config(CONFIGDIR "/main.conf");
    480 
    481 	parse_config(config);
    482 
    483 	agent_init();
    484 
    485 	if (option_udev == FALSE) {
    486 		if (hcid_dbus_init() < 0) {
    487 			error("Unable to get on D-Bus");
    488 			exit(1);
    489 		}
    490 	} else {
    491 		if (daemon(0, 0)) {
    492 			perror("Can't start daemon");
    493 			exit(1);
    494 		}
    495 	}
    496 
    497 	start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);
    498 
    499 	/* Loading plugins has to be done after D-Bus has been setup since
    500 	 * the plugins might wanna expose some paths on the bus. However the
    501 	 * best order of how to init various subsystems of the Bluetooth
    502 	 * daemon needs to be re-worked. */
    503 	plugin_init(config);
    504 
    505 	event_loop = g_main_loop_new(NULL, FALSE);
    506 
    507 	if (adapter_ops_setup() < 0) {
    508 		error("adapter_ops_setup failed");
    509 		exit(1);
    510 	}
    511 
    512 	rfkill_init();
    513 
    514 	DBG("Entering main loop");
    515 
    516 	g_main_loop_run(event_loop);
    517 
    518 	hcid_dbus_unregister();
    519 
    520 	hcid_dbus_exit();
    521 
    522 	rfkill_exit();
    523 
    524 	plugin_cleanup();
    525 
    526 	stop_sdp_server();
    527 
    528 	agent_exit();
    529 
    530 	g_main_loop_unref(event_loop);
    531 
    532 	if (config)
    533 		g_key_file_free(config);
    534 
    535 	info("Exit");
    536 
    537 	__btd_log_cleanup();
    538 
    539 	return 0;
    540 }
    541