| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdbool.h>
- #include <signal.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <sys/signalfd.h>
- #if defined(ANDROID)
- #include <sys/prctl.h>
- #include <sys/capability.h>
- #endif
- #include <glib.h>
- #include "lib/bluetooth.h"
- #include "lib/sdp.h"
- #include "src/log.h"
- #include "src/sdpd.h"
- #include "src/shared/util.h"
- #include "ipc-common.h"
- #include "ipc.h"
- #include "bluetooth.h"
- #include "socket.h"
- #include "hidhost.h"
- #include "hal-msg.h"
- #include "a2dp.h"
- #include "pan.h"
- #include "avrcp.h"
- #include "handsfree.h"
- #include "gatt.h"
- #include "health.h"
- #include "handsfree-client.h"
- #include "map-client.h"
- #include "utils.h"
- #define DEFAULT_VENDOR "BlueZ"
- #define DEFAULT_MODEL "BlueZ for Android"
- #define DEFAULT_NAME "BlueZ for Android"
- #define STARTUP_GRACE_SECONDS 5
- #define SHUTDOWN_GRACE_SECONDS 5
- static char *config_vendor = NULL;
- static char *config_model = NULL;
- static char *config_name = NULL;
- static char *config_serial = NULL;
- static char *config_fw_rev = NULL;
- static char *config_hw_rev = NULL;
- static uint64_t config_system_id = 0;
- static uint16_t config_pnp_source = 0x0002; /* USB */
- static uint16_t config_pnp_vendor = 0x1d6b; /* Linux Foundation */
- static uint16_t config_pnp_product = 0x0247; /* BlueZ for Android */
- static uint16_t config_pnp_version = 0x0000;
- static guint quit_timeout = 0;
- static bdaddr_t adapter_bdaddr;
- static GMainLoop *event_loop;
- static struct ipc *hal_ipc = NULL;
- static bool services[HAL_SERVICE_ID_MAX + 1] = { false };
- const char *bt_config_get_vendor(void)
- {
- if (config_vendor)
- return config_vendor;
- return DEFAULT_VENDOR;
- }
- const char *bt_config_get_name(void)
- {
- if (config_name)
- return config_name;
- return DEFAULT_NAME;
- }
- const char *bt_config_get_model(void)
- {
- if (config_model)
- return config_model;
- return DEFAULT_MODEL;
- }
- const char *bt_config_get_serial(void)
- {
- return config_serial;
- }
- const char *bt_config_get_fw_rev(void)
- {
- return config_fw_rev;
- }
- const char *bt_config_get_hw_rev(void)
- {
- return config_hw_rev;
- }
- uint64_t bt_config_get_system_id(void)
- {
- return config_system_id;
- }
- uint16_t bt_config_get_pnp_source(void)
- {
- return config_pnp_source;
- }
- uint16_t bt_config_get_pnp_vendor(void)
- {
- return config_pnp_vendor;
- }
- uint16_t bt_config_get_pnp_product(void)
- {
- return config_pnp_product;
- }
- uint16_t bt_config_get_pnp_version(void)
- {
- return config_pnp_version;
- }
- static void service_register(const void *buf, uint16_t len)
- {
- const struct hal_cmd_register_module *m = buf;
- uint8_t status;
- if (m->service_id > HAL_SERVICE_ID_MAX || services[m->service_id]) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- switch (m->service_id) {
- case HAL_SERVICE_ID_BLUETOOTH:
- if (!bt_bluetooth_register(hal_ipc, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_SOCKET:
- bt_socket_register(hal_ipc, &adapter_bdaddr, m->mode);
- break;
- case HAL_SERVICE_ID_HIDHOST:
- if (!bt_hid_register(hal_ipc, &adapter_bdaddr, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_A2DP:
- if (!bt_a2dp_register(hal_ipc, &adapter_bdaddr, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_PAN:
- if (!bt_pan_register(hal_ipc, &adapter_bdaddr, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_AVRCP:
- if (!bt_avrcp_register(hal_ipc, &adapter_bdaddr, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_HANDSFREE:
- if (!bt_handsfree_register(hal_ipc, &adapter_bdaddr, m->mode,
- m->max_clients)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_GATT:
- if (!bt_gatt_register(hal_ipc, &adapter_bdaddr)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_HEALTH:
- if (!bt_health_register(hal_ipc, &adapter_bdaddr, m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_HANDSFREE_CLIENT:
- if (!bt_hf_client_register(hal_ipc, &adapter_bdaddr)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- case HAL_SERVICE_ID_MAP_CLIENT:
- if (!bt_map_client_register(hal_ipc, &adapter_bdaddr,
- m->mode)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- break;
- default:
- DBG("service %u not supported", m->service_id);
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- services[m->service_id] = true;
- status = HAL_STATUS_SUCCESS;
- info("Service ID=%u registered", m->service_id);
- failed:
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
- status);
- }
- static bool unregister_service(uint8_t id)
- {
- if (id > HAL_SERVICE_ID_MAX || !services[id])
- return false;
- switch (id) {
- case HAL_SERVICE_ID_BLUETOOTH:
- bt_bluetooth_unregister();
- break;
- case HAL_SERVICE_ID_SOCKET:
- bt_socket_unregister();
- break;
- case HAL_SERVICE_ID_HIDHOST:
- bt_hid_unregister();
- break;
- case HAL_SERVICE_ID_A2DP:
- bt_a2dp_unregister();
- break;
- case HAL_SERVICE_ID_PAN:
- bt_pan_unregister();
- break;
- case HAL_SERVICE_ID_AVRCP:
- bt_avrcp_unregister();
- break;
- case HAL_SERVICE_ID_HANDSFREE:
- bt_handsfree_unregister();
- break;
- case HAL_SERVICE_ID_GATT:
- bt_gatt_unregister();
- break;
- case HAL_SERVICE_ID_HEALTH:
- bt_health_unregister();
- break;
- case HAL_SERVICE_ID_HANDSFREE_CLIENT:
- bt_hf_client_unregister();
- break;
- case HAL_SERVICE_ID_MAP_CLIENT:
- bt_map_client_unregister();
- break;
- default:
- DBG("service %u not supported", id);
- return false;
- }
- services[id] = false;
- return true;
- }
- static void service_unregister(const void *buf, uint16_t len)
- {
- const struct hal_cmd_unregister_module *m = buf;
- uint8_t status;
- if (!unregister_service(m->service_id)) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
- status = HAL_STATUS_SUCCESS;
- info("Service ID=%u unregistered", m->service_id);
- failed:
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
- status);
- }
- static char *get_prop(char *prop, uint16_t len, const uint8_t *val)
- {
- /* TODO should fail if set more than once ? */
- free(prop);
- prop = malloc0(len);
- if (!prop)
- return NULL;
- memcpy(prop, val, len);
- prop[len - 1] = '\0';
- return prop;
- }
- static void parse_pnp_id(uint16_t len, const uint8_t *val)
- {
- int result;
- uint16_t vendor, product, version , source;
- char *pnp;
- /* version is optional */
- version = config_pnp_version;
- pnp = get_prop(NULL, len, val);
- if (!pnp)
- return;
- DBG("pnp_id %s", pnp);
- result = sscanf(pnp, "bluetooth:%4hx:%4hx:%4hx",
- &vendor, &product, &version);
- if (result != EOF && result >= 2) {
- source = 0x0001;
- goto done;
- }
- result = sscanf(pnp, "usb:%4hx:%4hx:%4hx", &vendor, &product, &version);
- if (result != EOF && result >= 2) {
- source = 0x0002;
- goto done;
- }
- free(pnp);
- return;
- done:
- free(pnp);
- config_pnp_source = source;
- config_pnp_vendor = vendor;
- config_pnp_product = product;
- config_pnp_version = version;
- }
- static void parse_system_id(uint16_t len, const uint8_t *val)
- {
- uint64_t res;
- char *id;
- id = get_prop(NULL, len, val);
- if (!id)
- return;
- res = strtoull(id, NULL, 16);
- if (res == ULLONG_MAX && errno == ERANGE)
- goto done;
- config_system_id = res;
- done:
- free(id);
- }
- static void configuration(const void *buf, uint16_t len)
- {
- const struct hal_cmd_configuration *cmd = buf;
- const struct hal_config_prop *prop;
- unsigned int i;
- buf += sizeof(*cmd);
- len -= sizeof(*cmd);
- for (i = 0; i < cmd->num; i++) {
- prop = buf;
- if (len < sizeof(*prop) || len < sizeof(*prop) + prop->len) {
- error("Invalid configuration command, terminating");
- raise(SIGTERM);
- return;
- }
- switch (prop->type) {
- case HAL_CONFIG_VENDOR:
- config_vendor = get_prop(config_vendor, prop->len,
- prop->val);
- DBG("vendor %s", config_vendor);
- break;
- case HAL_CONFIG_NAME:
- config_name = get_prop(config_name, prop->len,
- prop->val);
- DBG("name %s", config_name);
- break;
- case HAL_CONFIG_MODEL:
- config_model = get_prop(config_model, prop->len,
- prop->val);
- DBG("model %s", config_model);
- break;
- case HAL_CONFIG_SERIAL_NUMBER:
- config_serial = get_prop(config_serial, prop->len,
- prop->val);
- DBG("serial %s", config_serial);
- break;
- case HAL_CONFIG_SYSTEM_ID:
- parse_system_id(prop->len, prop->val);
- break;
- case HAL_CONFIG_PNP_ID:
- parse_pnp_id(prop->len, prop->val);
- break;
- case HAL_CONFIG_FW_REV:
- config_fw_rev = get_prop(config_fw_rev, prop->len,
- prop->val);
- DBG("fw_rev %s", config_fw_rev);
- break;
- case HAL_CONFIG_HW_REV:
- config_hw_rev = get_prop(config_hw_rev, prop->len,
- prop->val);
- DBG("hw_rev %s", config_hw_rev);
- break;
- default:
- error("Invalid configuration option (%u), terminating",
- prop->type);
- raise(SIGTERM);
- return;
- }
- buf += sizeof(*prop) + prop->len;
- len -= sizeof(*prop) + prop->len;
- }
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_CONFIGURATION,
- HAL_STATUS_SUCCESS);
- }
- static const struct ipc_handler cmd_handlers[] = {
- /* HAL_OP_REGISTER_MODULE */
- { service_register, false, sizeof(struct hal_cmd_register_module) },
- /* HAL_OP_UNREGISTER_MODULE */
- { service_unregister, false, sizeof(struct hal_cmd_unregister_module) },
- /* HAL_OP_CONFIGURATION */
- { configuration, true, sizeof(struct hal_cmd_configuration) },
- };
- static void bluetooth_stopped(void)
- {
- g_main_loop_quit(event_loop);
- }
- static gboolean quit_eventloop(gpointer user_data)
- {
- g_main_loop_quit(event_loop);
- quit_timeout = 0;
- return FALSE;
- }
- static void stop_bluetooth(void)
- {
- static bool __stop = false;
- if (__stop)
- return;
- __stop = true;
- if (!bt_bluetooth_stop(bluetooth_stopped)) {
- g_main_loop_quit(event_loop);
- return;
- }
- quit_timeout = g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
- quit_eventloop, NULL);
- }
- static void ipc_disconnected(void *data)
- {
- stop_bluetooth();
- }
- static void adapter_ready(int err, const bdaddr_t *addr)
- {
- if (err < 0) {
- error("Adapter initialization failed: %s", strerror(-err));
- exit(EXIT_FAILURE);
- }
- bacpy(&adapter_bdaddr, addr);
- if (quit_timeout > 0) {
- g_source_remove(quit_timeout);
- quit_timeout = 0;
- }
- info("Adapter initialized");
- hal_ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX, true,
- ipc_disconnected, NULL);
- if (!hal_ipc) {
- error("Failed to initialize IPC");
- exit(EXIT_FAILURE);
- }
- ipc_register(hal_ipc, HAL_SERVICE_ID_CORE, cmd_handlers,
- G_N_ELEMENTS(cmd_handlers));
- }
- static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
- gpointer user_data)
- {
- static bool __terminated = false;
- struct signalfd_siginfo si;
- ssize_t result;
- int fd;
- if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
- return FALSE;
- fd = g_io_channel_unix_get_fd(channel);
- result = read(fd, &si, sizeof(si));
- if (result != sizeof(si))
- return FALSE;
- switch (si.ssi_signo) {
- case SIGINT:
- case SIGTERM:
- if (!__terminated) {
- info("Terminating");
- stop_bluetooth();
- }
- __terminated = true;
- break;
- }
- return TRUE;
- }
- static guint setup_signalfd(void)
- {
- GIOChannel *channel;
- guint source;
- sigset_t mask;
- int fd;
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
- if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
- perror("Failed to set signal mask");
- return 0;
- }
- fd = signalfd(-1, &mask, 0);
- if (fd < 0) {
- perror("Failed to create signal descriptor");
- return 0;
- }
- channel = g_io_channel_unix_new(fd);
- g_io_channel_set_close_on_unref(channel, TRUE);
- g_io_channel_set_encoding(channel, NULL, NULL);
- g_io_channel_set_buffered(channel, FALSE);
- source = g_io_add_watch(channel,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- signal_handler, NULL);
- g_io_channel_unref(channel);
- return source;
- }
- static gboolean option_version = FALSE;
- static gint option_index = -1;
- static gboolean option_dbg = FALSE;
- static gboolean option_mgmt_dbg = FALSE;
- static GOptionEntry options[] = {
- { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
- "Show version information and exit", NULL },
- { "index", 'i', 0, G_OPTION_ARG_INT, &option_index,
- "Use specified controller", "INDEX"},
- { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_dbg,
- "Enable debug logs", NULL},
- { "mgmt-debug", 0, 0, G_OPTION_ARG_NONE, &option_mgmt_dbg,
- "Enable mgmt debug logs", NULL},
- { NULL }
- };
- static void cleanup_services(void)
- {
- int i;
- DBG("");
- for (i = HAL_SERVICE_ID_MAX; i > HAL_SERVICE_ID_CORE; i--)
- unregister_service(i);
- }
- static bool set_capabilities(void)
- {
- #if defined(ANDROID)
- struct __user_cap_header_struct header;
- struct __user_cap_data_struct cap;
- header.version = _LINUX_CAPABILITY_VERSION;
- header.pid = 0;
- /*
- * CAP_NET_ADMIN: Allow use of MGMT interface
- * CAP_NET_BIND_SERVICE: Allow use of privileged PSM
- * CAP_NET_RAW: Allow use of bnep ioctl calls
- */
- cap.effective = cap.permitted =
- CAP_TO_MASK(CAP_NET_RAW) |
- CAP_TO_MASK(CAP_NET_ADMIN) |
- CAP_TO_MASK(CAP_NET_BIND_SERVICE);
- cap.inheritable = 0;
- /* don't clear capabilities when dropping root */
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- error("%s: prctl(): %s", __func__, strerror(errno));
- return false;
- }
- /* Android bluetooth user UID=1002 */
- if (setuid(1002) < 0) {
- error("%s: setuid(): %s", __func__, strerror(errno));
- return false;
- }
- /* TODO: Move to cap_set_proc once bionic support it */
- if (capset(&header, &cap) < 0) {
- error("%s: capset(): %s", __func__, strerror(errno));
- return false;
- }
- /* TODO: Move to cap_get_proc once bionic support it */
- if (capget(&header, &cap) < 0) {
- error("%s: capget(): %s", __func__, strerror(errno));
- return false;
- }
- DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective,
- cap.permitted, cap.inheritable);
- #endif
- return true;
- }
- static void set_version(void)
- {
- uint8_t major, minor;
- if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
- return;
- config_pnp_version = major << 8 | minor;
- }
- int main(int argc, char *argv[])
- {
- GOptionContext *context;
- GError *err = NULL;
- guint signal;
- set_version();
- context = g_option_context_new(NULL);
- g_option_context_add_main_entries(context, options, NULL);
- if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
- if (err != NULL) {
- g_printerr("%s\n", err->message);
- g_error_free(err);
- } else
- g_printerr("An unknown error occurred\n");
- exit(EXIT_FAILURE);
- }
- g_option_context_free(context);
- if (option_version == TRUE) {
- printf("%s\n", VERSION);
- exit(EXIT_SUCCESS);
- }
- signal = setup_signalfd();
- if (!signal)
- return EXIT_FAILURE;
- if (option_dbg || option_mgmt_dbg)
- __btd_log_init("*", 0);
- else
- __btd_log_init(NULL, 0);
- if (!set_capabilities()) {
- __btd_log_cleanup();
- g_source_remove(signal);
- return EXIT_FAILURE;
- }
- quit_timeout = g_timeout_add_seconds(STARTUP_GRACE_SECONDS,
- quit_eventloop, NULL);
- if (quit_timeout == 0) {
- error("Failed to init startup timeout");
- __btd_log_cleanup();
- g_source_remove(signal);
- return EXIT_FAILURE;
- }
- if (!bt_bluetooth_start(option_index, option_mgmt_dbg, adapter_ready)) {
- __btd_log_cleanup();
- g_source_remove(quit_timeout);
- g_source_remove(signal);
- return EXIT_FAILURE;
- }
- /* Use params: mtu = 0, flags = 0 */
- start_sdp_server(0, 0);
- DBG("Entering main loop");
- event_loop = g_main_loop_new(NULL, FALSE);
- g_main_loop_run(event_loop);
- g_source_remove(signal);
- if (quit_timeout > 0)
- g_source_remove(quit_timeout);
- cleanup_services();
- stop_sdp_server();
- bt_bluetooth_cleanup();
- g_main_loop_unref(event_loop);
- /* If no adapter was initialized, hal_ipc is NULL */
- if (hal_ipc) {
- ipc_unregister(hal_ipc, HAL_SERVICE_ID_CORE);
- ipc_cleanup(hal_ipc);
- }
- info("Exit");
- __btd_log_cleanup();
- free(config_vendor);
- free(config_model);
- free(config_name);
- free(config_serial);
- free(config_fw_rev);
- free(config_hw_rev);
- return EXIT_SUCCESS;
- }
|