mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-03 17:14:21 +08:00
d0cd4f3fd6
After starting up, daemon is responsible for connecting to HAL library. If this doesn't happen before timeout occured init will fail.
472 lines
8.9 KiB
C
472 lines
8.9 KiB
C
/*
|
|
* Copyright (C) 2013 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdbool.h>
|
|
#include <errno.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <poll.h>
|
|
|
|
#include <hardware/bluetooth.h>
|
|
#include <hardware/bt_sock.h>
|
|
#include <hardware/bt_hh.h>
|
|
#include <hardware/bt_pan.h>
|
|
|
|
#include <cutils/properties.h>
|
|
|
|
#define LOG_TAG "BlueZ"
|
|
#include <cutils/log.h>
|
|
|
|
#include "hal.h"
|
|
#include "hal-msg.h"
|
|
|
|
#define SERVICE_NAME "bluetoothd"
|
|
#define CONNECT_TIMEOUT (5 * 1000)
|
|
|
|
bt_callbacks_t *bt_hal_cbacks = NULL;
|
|
|
|
static int cmd_sk = -1;
|
|
static int notif_sk = -1;
|
|
|
|
static bool interface_ready(void)
|
|
{
|
|
return bt_hal_cbacks != NULL;
|
|
}
|
|
|
|
static int accept_connection(int sk)
|
|
{
|
|
int err;
|
|
struct pollfd pfd;
|
|
int new_sk;
|
|
|
|
memset(&pfd, 0 , sizeof(pfd));
|
|
pfd.fd = sk;
|
|
pfd.events = POLLIN;
|
|
|
|
err = poll(&pfd, 1, CONNECT_TIMEOUT);
|
|
if (err < 0) {
|
|
err = errno;
|
|
ALOGE("Failed to poll: %d (%s)", err, strerror(err));
|
|
return -1;
|
|
}
|
|
|
|
if (err == 0) {
|
|
ALOGE("bluetoothd connect timeout");
|
|
return -1;
|
|
}
|
|
|
|
new_sk = accept(sk, NULL, NULL);
|
|
if (new_sk < 0) {
|
|
err = errno;
|
|
ALOGE("Failed to accept socket: %d (%s)", err, strerror(err));
|
|
return -1;
|
|
}
|
|
|
|
return new_sk;
|
|
}
|
|
|
|
static bool start_daemon(void)
|
|
{
|
|
struct sockaddr_un addr;
|
|
int sk;
|
|
int err;
|
|
|
|
sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
|
|
if (sk < 0) {
|
|
err = errno;
|
|
ALOGE("Failed to create socket: %d (%s)", err,
|
|
strerror(err));
|
|
return false;
|
|
}
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
memcpy(addr.sun_path, BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH));
|
|
|
|
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
err = errno;
|
|
ALOGE("Failed to bind socket: %d (%s)", err, strerror(err));
|
|
close(sk);
|
|
return false;
|
|
}
|
|
|
|
if (listen(sk, 2) < 0) {
|
|
err = errno;
|
|
ALOGE("Failed to listen on socket: %d (%s)", err,
|
|
strerror(err));
|
|
close(sk);
|
|
return false;
|
|
}
|
|
|
|
/* Start Android Bluetooth daemon service */
|
|
property_set("ctl.start", SERVICE_NAME);
|
|
|
|
cmd_sk = accept_connection(sk);
|
|
if (cmd_sk < 0) {
|
|
close(sk);
|
|
return false;
|
|
}
|
|
|
|
notif_sk = accept_connection(sk);
|
|
if (notif_sk < 0) {
|
|
close(sk);
|
|
close(cmd_sk);
|
|
cmd_sk = -1;
|
|
return false;
|
|
}
|
|
|
|
ALOGI("bluetoothd connected");
|
|
|
|
close(sk);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void stop_daemon(void)
|
|
{
|
|
close(cmd_sk);
|
|
cmd_sk = -1;
|
|
|
|
close(notif_sk);
|
|
notif_sk = -1;
|
|
}
|
|
|
|
static int init(bt_callbacks_t *callbacks)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (interface_ready())
|
|
return BT_STATUS_SUCCESS;
|
|
|
|
if (!start_daemon())
|
|
return BT_STATUS_FAIL;
|
|
|
|
bt_hal_cbacks = callbacks;
|
|
|
|
return BT_STATUS_SUCCESS;
|
|
}
|
|
|
|
static int enable(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int disable(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static void cleanup(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return;
|
|
|
|
stop_daemon();
|
|
|
|
bt_hal_cbacks = NULL;
|
|
}
|
|
|
|
static int get_adapter_properties(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int get_adapter_property(bt_property_type_t type)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int set_adapter_property(const bt_property_t *property)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
if (property == NULL)
|
|
return BT_STATUS_PARM_INVALID;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int get_remote_device_properties(bt_bdaddr_t *remote_addr)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int get_remote_device_property(bt_bdaddr_t *remote_addr,
|
|
bt_property_type_t type)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int set_remote_device_property(bt_bdaddr_t *remote_addr,
|
|
const bt_property_t *property)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int get_remote_service_record(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int get_remote_services(bt_bdaddr_t *remote_addr)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int start_discovery(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int cancel_discovery(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int create_bond(const bt_bdaddr_t *bd_addr)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
if (!bd_addr)
|
|
return BT_STATUS_PARM_INVALID;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int cancel_bond(const bt_bdaddr_t *bd_addr)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int remove_bond(const bt_bdaddr_t *bd_addr)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int pin_reply(const bt_bdaddr_t *bd_addr, uint8_t accept,
|
|
uint8_t pin_len, bt_pin_code_t *pin_code)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int ssp_reply(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
|
|
uint8_t accept, uint32_t passkey)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
if (!bd_addr)
|
|
return BT_STATUS_PARM_INVALID;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static const void *get_profile_interface(const char *profile_id)
|
|
{
|
|
ALOGD("%s: %s", __func__, profile_id);
|
|
|
|
if (!interface_ready())
|
|
return NULL;
|
|
|
|
if (!strcmp(profile_id, BT_PROFILE_SOCKETS_ID))
|
|
return bt_get_sock_interface();
|
|
|
|
if (!strcmp(profile_id, BT_PROFILE_HIDHOST_ID))
|
|
return bt_get_hidhost_interface();
|
|
|
|
if (!strcmp(profile_id, BT_PROFILE_PAN_ID))
|
|
return bt_get_pan_interface();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int dut_mode_configure(uint8_t enable)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static int dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
if (!interface_ready())
|
|
return BT_STATUS_NOT_READY;
|
|
|
|
return BT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static const bt_interface_t bluetooth_if = {
|
|
.size = sizeof(bt_interface_t),
|
|
.init = init,
|
|
.enable = enable,
|
|
.disable = disable,
|
|
.cleanup = cleanup,
|
|
.get_adapter_properties = get_adapter_properties,
|
|
.get_adapter_property = get_adapter_property,
|
|
.set_adapter_property = set_adapter_property,
|
|
.get_remote_device_properties = get_remote_device_properties,
|
|
.get_remote_device_property = get_remote_device_property,
|
|
.set_remote_device_property = set_remote_device_property,
|
|
.get_remote_service_record = get_remote_service_record,
|
|
.get_remote_services = get_remote_services,
|
|
.start_discovery = start_discovery,
|
|
.cancel_discovery = cancel_discovery,
|
|
.create_bond = create_bond,
|
|
.remove_bond = remove_bond,
|
|
.cancel_bond = cancel_bond,
|
|
.pin_reply = pin_reply,
|
|
.ssp_reply = ssp_reply,
|
|
.get_profile_interface = get_profile_interface,
|
|
.dut_mode_configure = dut_mode_configure,
|
|
.dut_mode_send = dut_mode_send
|
|
};
|
|
|
|
static const bt_interface_t *get_bluetooth_interface(void)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
return &bluetooth_if;
|
|
}
|
|
|
|
static int close_bluetooth(struct hw_device_t *device)
|
|
{
|
|
ALOGD(__func__);
|
|
|
|
cleanup();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int open_bluetooth(const struct hw_module_t *module, char const *name,
|
|
struct hw_device_t **device)
|
|
{
|
|
bluetooth_device_t *dev = malloc(sizeof(bluetooth_device_t));
|
|
|
|
ALOGD(__func__);
|
|
|
|
memset(dev, 0, sizeof(bluetooth_device_t));
|
|
dev->common.tag = HARDWARE_DEVICE_TAG;
|
|
dev->common.version = 0;
|
|
dev->common.module = (struct hw_module_t *) module;
|
|
dev->common.close = close_bluetooth;
|
|
dev->get_bluetooth_interface = get_bluetooth_interface;
|
|
|
|
*device = (struct hw_device_t *) dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct hw_module_methods_t bluetooth_module_methods = {
|
|
.open = open_bluetooth,
|
|
};
|
|
|
|
struct hw_module_t HAL_MODULE_INFO_SYM = {
|
|
.tag = HARDWARE_MODULE_TAG,
|
|
.version_major = 1,
|
|
.version_minor = 0,
|
|
.id = BT_HARDWARE_MODULE_ID,
|
|
.name = "BlueZ Bluetooth stack",
|
|
.author = "Intel Corporation",
|
|
.methods = &bluetooth_module_methods
|
|
};
|