• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@qualcomm.com>
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@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 
load_config(const char * file)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 
parse_config(GKeyFile * config)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  */
expand_name(char * dst,int size,char * str,int dev_id)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 
init_defaults(void)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 
sig_term(int sig)329 static void sig_term(int sig)
330 {
331 	g_main_loop_quit(event_loop);
332 }
333 
sig_debug(int sig)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 
exit_timeout(gpointer data)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 
btd_start_exit_timer(void)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 
btd_stop_exit_timer(void)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 
parse_debug(const char * key,const char * value,gpointer user_data,GError ** error)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 
main(int argc,char * argv[])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