/**********************************************************************
*
* Copyright (C) 2017 The Android Open Source Project
* Copyright (C) 2015 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "buffer_allocator.h"
#include "hci_internals.h"
#include "hci_layer.h"
#include "osi/include/compat.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
using base::Thread;
#define SOCKET_GET_IF "/tmp/if_get_hci_sock"
#define BTPROTO_HCI 1
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_CONTROL 3
#define HCI_DEV_NONE 0xffff
#define RFKILL_TYPE_BLUETOOTH 2
#define RFKILL_OP_CHANGE_ALL 3
#define MGMT_OP_INDEX_LIST 0x0003
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_COMMAND_COMP 0x0001
#define MGMT_EV_SIZE_MAX 1024
#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
#define BT_ACL_HDR_SIZE 4
#define BT_SCO_HDR_SIZE 3
#define BT_EVT_HDR_SIZE 2
#define BT_CMD_HDR_SIZE 3
struct sockaddr_hci {
sa_family_t hci_family;
unsigned short hci_dev;
unsigned short hci_channel;
};
struct rfkill_event {
uint32_t idx;
uint8_t type;
uint8_t op;
uint8_t soft, hard;
} __attribute__((packed));
struct mgmt_pkt {
uint16_t opcode;
uint16_t index;
uint16_t len;
uint8_t data[MGMT_EV_SIZE_MAX];
} __attribute__((packed));
struct mgmt_event_read_index {
uint16_t cc_opcode;
uint8_t status;
uint16_t num_intf;
uint16_t index[0];
} __attribute__((packed));
enum HciPacketType {
HCI_PACKET_TYPE_UNKNOWN = 0,
HCI_PACKET_TYPE_COMMAND = 1,
HCI_PACKET_TYPE_ACL_DATA = 2,
HCI_PACKET_TYPE_SCO_DATA = 3,
HCI_PACKET_TYPE_EVENT = 4
};
extern void initialization_complete();
extern void hci_event_received(const base::Location& from_here,
BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
static int bt_vendor_fd = -1;
static bool use_stream_sock = true;
static int hci_interface;
static int rfkill_en;
int reader_thread_ctrl_fd = -1;
Thread* reader_thread = NULL;
void monitor_socket_packet(int ctrl_fd, int fd) {
const allocator_t* buffer_allocator = buffer_allocator_get_interface();
const size_t buf_size = 2000;
uint8_t buf[buf_size];
ssize_t len = read(fd, buf, buf_size);
while (len > 0) {
if (len == buf_size)
LOG(FATAL) << "This packet filled buffer, if it have continuation we "
"don't know how to merge it, increase buffer size!";
uint8_t type = buf[0];
size_t packet_size = buf_size + BT_HDR_SIZE;
BT_HDR* packet =
reinterpret_cast(buffer_allocator->alloc(packet_size));
packet->offset = 0;
packet->layer_specific = 0;
packet->len = len - 1;
memcpy(packet->data, buf + 1, len - 1);
switch (type) {
case HCI_PACKET_TYPE_COMMAND:
packet->event = MSG_HC_TO_STACK_HCI_EVT;
hci_event_received(FROM_HERE, packet);
break;
case HCI_PACKET_TYPE_ACL_DATA:
packet->event = MSG_HC_TO_STACK_HCI_ACL;
acl_event_received(packet);
break;
case HCI_PACKET_TYPE_SCO_DATA:
packet->event = MSG_HC_TO_STACK_HCI_SCO;
sco_data_received(packet);
break;
case HCI_PACKET_TYPE_EVENT:
packet->event = MSG_HC_TO_STACK_HCI_EVT;
hci_event_received(FROM_HERE, packet);
break;
default:
LOG(FATAL) << "Unexpected event type: " << +type;
break;
}
fd_set fds;
FD_ZERO(&fds);
FD_SET(ctrl_fd, &fds);
FD_SET(fd, &fds);
int res = select(std::max(fd, ctrl_fd) + 1, &fds, NULL, NULL, NULL);
if (res <= 0) LOG(INFO) << "Nothing more to read";
if (FD_ISSET(ctrl_fd, &fds)) {
LOG(INFO) << "exitting";
return;
}
len = read(fd, buf, buf_size);
}
}
static int do_read(int fd, unsigned char* buf, size_t len)
{
int bytes_left = len, bytes_read = 0, read_offset = 0;
while(bytes_left > 0) {
bytes_read = read(fd, buf + read_offset, bytes_left);
if(bytes_read < 0) {
LOG(ERROR) << "read fail Error " << strerror(errno);
return -1;
} else if (bytes_read == 0) {
LOG(INFO) << " read returned 0, read bytes" << (len-bytes_left) << " expected len" << len;
return (len - bytes_left);
} else {
if(bytes_read < bytes_left) {
bytes_left -= bytes_read;
read_offset += bytes_read;
} else {
break;
}
}
}
return len;
}
void monitor_socket_stream(int ctrl_fd, int fd) {
const allocator_t* buffer_allocator = buffer_allocator_get_interface();
const size_t buf_size = 2000;
uint8_t buf[buf_size];
unsigned int packet_length;
ssize_t len = read(fd, buf, 1);
while (len > 0) {
if (len == buf_size)
LOG(FATAL) << "This packet filled buffer, if it have continuation we "
"don't know how to merge it, increase buffer size!";
uint8_t type = buf[0];
size_t packet_size = buf_size + BT_HDR_SIZE;
BT_HDR* packet =
reinterpret_cast(buffer_allocator->alloc(packet_size));
packet->offset = 0;
packet->layer_specific = 0;
LOG(INFO) << "packet type:" << +type;
switch (type) {
case HCI_PACKET_TYPE_COMMAND:
len = do_read(fd,buf+1,BT_CMD_HDR_SIZE);
packet->event = MSG_HC_TO_STACK_HCI_EVT;
packet_length = buf[3];
packet->len = packet_length + BT_CMD_HDR_SIZE;
len = do_read(fd,buf+1,packet->len);
memcpy(packet->data, buf+1, packet->len);
hci_event_received(FROM_HERE, packet);
break;
case HCI_PACKET_TYPE_ACL_DATA:
len = do_read(fd,buf+1,BT_ACL_HDR_SIZE);
packet->event = MSG_HC_TO_STACK_HCI_ACL;
packet_length = (buf[4] << 8) + buf[3];
packet->len = packet_length + BT_ACL_HDR_SIZE;
LOG(INFO) << "total packet length to be read:" << packet->len;
LOG(INFO) << "packet_length:" << packet_length;
len = do_read(fd, buf+BT_ACL_HDR_SIZE+1, packet_length);
LOG(INFO) << "length of bytes read:" << +len;
memcpy(packet->data, buf+1, packet->len);
acl_event_received(packet);
break;
case HCI_PACKET_TYPE_SCO_DATA:
len = do_read(fd,buf+1,BT_SCO_HDR_SIZE);
packet->event = MSG_HC_TO_STACK_HCI_SCO;
packet_length = buf[3];
packet->len = packet_length + BT_CMD_HDR_SIZE;
len = do_read(fd,buf+1,packet->len);
memcpy(packet->data, buf+1, packet->len);
sco_data_received(packet);
break;
case HCI_PACKET_TYPE_EVENT:
len = do_read(fd,buf+1,BT_EVT_HDR_SIZE);
packet->event = MSG_HC_TO_STACK_HCI_EVT;
packet_length = buf[2];
packet->len = packet_length + BT_EVT_HDR_SIZE;
len = do_read(fd, buf+BT_EVT_HDR_SIZE+1, packet_length);
memcpy(packet->data, buf+1, packet->len);
hci_event_received(FROM_HERE, packet);
break;
default:
LOG(FATAL) << "Unexpected event type: " << +type;
break;
}
fd_set fds;
FD_ZERO(&fds);
FD_SET(ctrl_fd, &fds);
FD_SET(fd, &fds);
int res = select(std::max(fd, ctrl_fd) + 1, &fds, NULL, NULL, NULL);
if (res <= 0) LOG(INFO) << "Nothing more to read";
if (FD_ISSET(ctrl_fd, &fds)) {
LOG(INFO) << "exitting";
return;
}
len = read(fd, buf, 1);
}
}
/* TODO: should thread the device waiting and return immedialty */
void hci_initialize() {
LOG(INFO) << __func__;
int fdGetSock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
CHECK(fdGetSock >= 0) << "socket create error" << strerror(errno);
struct sockaddr_un addr_get_sock;
memset(&addr_get_sock, 0, sizeof(struct sockaddr_un));
addr_get_sock.sun_family = AF_UNIX;
strncpy(addr_get_sock.sun_path, SOCKET_GET_IF, sizeof(addr_get_sock.sun_path) - 1);
LOG(ERROR) << "Connect to socket: " << SOCKET_GET_IF;
if (connect(fdGetSock, (struct sockaddr*)&addr_get_sock, sizeof(addr_get_sock)) < 0) {
LOG(FATAL) << "socket bind error " << strerror(errno);
}
char c_str_sock_name[255];
int len = read(fdGetSock, c_str_sock_name, 255);
std::string socket_name (c_str_sock_name, len);
LOG(ERROR) << __func__ << ": sock_name " << socket_name;
close(fdGetSock);
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_name.c_str(), sizeof(addr.sun_path) - 1);
/* Try to use STREAM type of socket */
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
CHECK(fd >= 0) << "socket create error" << strerror(errno);
LOG(ERROR) << "Connect to socket: " << socket_name;
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOG(ERROR) << "socket bind error: " << strerror(errno) << ". Retry";
close(fd);
/* Try to use SEQPACKET type of socket */
use_stream_sock = false;
fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
CHECK(fd >= 0) << "socket create error" << strerror(errno);
LOG(ERROR) << "Connect to socket: " << socket_name;
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOG(FATAL) << "socket bind error, abort" << strerror(errno);
close(fd);
return;
}
} else {
use_stream_sock = true;
}
bt_vendor_fd = fd;
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
LOG(FATAL) << "socketpair failed: " << strerror(errno);
}
reader_thread_ctrl_fd = sv[0];
reader_thread = new Thread("hci_sock_reader");
reader_thread->Start();
if (use_stream_sock) {
reader_thread->task_runner()->PostTask(
FROM_HERE, base::Bind(&monitor_socket_stream, sv[1], bt_vendor_fd));
} else {
reader_thread->task_runner()->PostTask(
FROM_HERE, base::Bind(&monitor_socket_packet, sv[1], bt_vendor_fd));
}
LOG(INFO) << "HCI device ready";
initialization_complete();
}
void hci_close() {
LOG(INFO) << __func__;
if (bt_vendor_fd != -1) {
close(bt_vendor_fd);
bt_vendor_fd = -1;
}
if (reader_thread_ctrl_fd != -1) {
uint8_t msg[] = {1};
send(reader_thread_ctrl_fd, msg, sizeof(msg), 0);
reader_thread_ctrl_fd = -1;
}
if (reader_thread != NULL) {
reader_thread->Stop();
delete reader_thread;
reader_thread = NULL;
}
}
hci_transmit_status_t hci_transmit(BT_HDR* packet) {
uint8_t type;
hci_transmit_status_t status = HCI_TRANSMIT_SUCCESS;
CHECK(bt_vendor_fd != -1);
uint16_t event = packet->event & MSG_EVT_MASK;
switch (event & MSG_EVT_MASK) {
case MSG_STACK_TO_HC_HCI_CMD:
type = 1;
break;
case MSG_STACK_TO_HC_HCI_ACL:
type = 2;
break;
case MSG_STACK_TO_HC_HCI_SCO:
type = 3;
break;
default:
status = HCI_TRANSMIT_INVALID_PKT;
LOG(FATAL) << "Unknown packet type " << event;
break;
}
uint8_t* addr = packet->data + packet->offset - 1;
uint8_t store = *addr;
*addr = type;
size_t ret = write(bt_vendor_fd, addr, packet->len + 1);
*(addr) = store;
if (ret != packet->len + 1) {
status = HCI_TRANSMIT_DAEMON_DIED;
LOG(ERROR) << "Should have send whole packet";
}
if (ret == -1) {
status = HCI_TRANSMIT_DAEMON_DIED;
LOG(FATAL) << strerror(errno);
}
return status;
}
#if (OFF_TARGET_TEST_ENABLED == FALSE)
static int wait_hcidev(void) {
struct sockaddr_hci addr;
struct pollfd fds[1];
struct mgmt_pkt ev;
int fd;
int ret = 0;
LOG(INFO) << __func__;
fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (fd < 0) {
LOG(ERROR) << "Bluetooth socket error: %s" << strerror(errno);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = HCI_CHANNEL_CONTROL;
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOG(ERROR) << "HCI Channel Control: " << strerror(errno);
close(fd);
return -1;
}
fds[0].fd = fd;
fds[0].events = POLLIN;
/* Read Controller Index List Command */
ev.opcode = MGMT_OP_INDEX_LIST;
ev.index = HCI_DEV_NONE;
ev.len = 0;
ssize_t wrote;
OSI_NO_INTR(wrote = write(fd, &ev, 6));
if (wrote != 6) {
LOG(ERROR) << "Unable to write mgmt command: " << strerror(errno);
ret = -1;
goto end;
}
while (1) {
int n;
OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
if (n == -1) {
LOG(ERROR) << "Poll error: " << strerror(errno);
ret = -1;
break;
} else if (n == 0) {
LOG(ERROR) << "Timeout, no HCI device detected";
ret = -1;
break;
}
if (fds[0].revents & POLLIN) {
OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
if (n < 0) {
LOG(ERROR) << "Error reading control channel: " << strerror(errno);
ret = -1;
break;
}
if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
goto end;
} else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
struct mgmt_event_read_index* cc;
int i;
cc = (struct mgmt_event_read_index*)ev.data;
if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
for (i = 0; i < cc->num_intf; i++) {
if (cc->index[i] == hci_interface) goto end;
}
}
}
}
end:
close(fd);
return ret;
}
static int rfkill(int block) {
struct rfkill_event event;
int fd;
LOG(INFO) << __func__;
fd = open("/dev/rfkill", O_WRONLY);
if (fd < 0) {
LOG(ERROR) << "Unable to open /dev/rfkill";
return -1;
}
memset(&event, 0, sizeof(struct rfkill_event));
event.op = RFKILL_OP_CHANGE_ALL;
event.type = RFKILL_TYPE_BLUETOOTH;
event.hard = block;
event.soft = block;
ssize_t len;
OSI_NO_INTR(len = write(fd, &event, sizeof(event)));
if (len < 0) {
LOG(ERROR) << "Failed to change rfkill state";
close(fd);
return 1;
}
close(fd);
return 0;
}
#endif
int hci_open_firmware_log_file() { return INVALID_FD; }
void hci_close_firmware_log_file(int fd) {}
void hci_log_firmware_debug_packet(int fd, BT_HDR* packet) {}