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