hci_inject.cc revision 09f31c121df79afe045163e0142dec5c09caa072
1/******************************************************************************
2 *
3 *  Copyright (C) 2014 Google, Inc.
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19#define LOG_TAG "bt_hci_inject"
20
21#include <assert.h>
22#include <errno.h>
23#include <utils/Log.h>
24
25#include "bt_hci_bdroid.h"
26#include "bt_types.h"
27#include "hci_inject.h"
28#include "list.h"
29#include "osi.h"
30#include "socket.h"
31#include "thread.h"
32
33typedef enum {
34  HCI_PACKET_COMMAND  = 1,
35  HCI_PACKET_ACL_DATA = 2,
36  HCI_PACKET_SCO_DATA = 3,
37  HCI_PACKET_EVENT    = 4,
38} hci_packet_t;
39
40typedef struct {
41  socket_t *socket;
42  uint8_t buffer[65536 + 3];  // 2 bytes length prefix, 1 byte type prefix.
43  size_t buffer_size;
44} client_t;
45
46static const port_t LISTEN_PORT = 8873;
47
48static const bt_hc_interface_t *hci;
49static socket_t *listen_socket;
50static thread_t *thread;
51static list_t *clients;
52
53static int hci_packet_to_event(hci_packet_t packet);
54static void accept_ready(socket_t *socket, void *context);
55static void read_ready(socket_t *socket, void *context);
56static void client_free(void *ptr);
57
58bool hci_inject_open(void) {
59  assert(listen_socket == NULL);
60  assert(thread == NULL);
61  assert(clients == NULL);
62
63  hci = bt_hc_get_interface();
64
65  clients = list_new(client_free);
66  if (!clients)
67    goto error;
68
69  thread = thread_new("hci_inject");
70  if (!thread)
71    goto error;
72
73  listen_socket = socket_new();
74  if (!listen_socket)
75    goto error;
76
77  if (!socket_listen(listen_socket, LISTEN_PORT))
78    goto error;
79
80  socket_register(listen_socket, thread_get_reactor(thread), accept_ready, NULL, NULL);
81  return true;
82
83error:;
84  hci_inject_close();
85  return false;
86}
87
88void hci_inject_close(void) {
89  socket_free(listen_socket);
90  thread_free(thread);
91  list_free(clients);
92
93  listen_socket = NULL;
94  thread = NULL;
95  clients = NULL;
96}
97
98static int hci_packet_to_event(hci_packet_t packet) {
99  switch (packet) {
100    case HCI_PACKET_COMMAND:
101      return MSG_STACK_TO_HC_HCI_CMD;
102    case HCI_PACKET_ACL_DATA:
103      return MSG_STACK_TO_HC_HCI_ACL;
104    case HCI_PACKET_SCO_DATA:
105      return MSG_STACK_TO_HC_HCI_SCO;
106    default:
107      ALOGE("%s unsupported packet type: %d", __func__, packet);
108      return -1;
109  }
110}
111
112static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) {
113  assert(socket != NULL);
114  assert(socket == listen_socket);
115
116  socket = socket_accept(socket);
117  if (!socket)
118    return;
119
120  client_t *client = (client_t *)calloc(1, sizeof(client_t));
121  if (!client) {
122    ALOGE("%s unable to allocate memory for client.", __func__);
123    socket_free(socket);
124    return;
125  }
126
127  client->socket = socket;
128
129  if (!list_append(clients, client)) {
130    ALOGE("%s unable to add client to list.", __func__);
131    client_free(client);
132    return;
133  }
134
135  socket_register(socket, thread_get_reactor(thread), read_ready, NULL, client);
136}
137
138static void read_ready(UNUSED_ATTR socket_t *socket, void *context) {
139  assert(bt_hc_cbacks != NULL);
140  assert(socket != NULL);
141  assert(context != NULL);
142
143  client_t *client = (client_t *)context;
144
145  ssize_t ret = socket_read(client->socket, client->buffer + client->buffer_size, sizeof(client->buffer) - client->buffer_size);
146  if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
147    list_remove(clients, client);
148    return;
149  }
150  client->buffer_size += ret;
151
152  while (client->buffer_size > 3) {
153    uint8_t *buffer = client->buffer;
154    hci_packet_t packet_type = (hci_packet_t)buffer[0];
155    size_t packet_len = (buffer[2] << 8) | buffer[1];
156    size_t frame_len = 3 + packet_len;
157
158    if (client->buffer_size < frame_len)
159      break;
160
161    // TODO(sharvil): validate incoming HCI messages.
162    // TODO(sharvil): once we have an HCI parser, we can eliminate
163    //   the 2-byte size field since it will be contained in the packet.
164
165    BT_HDR *buf = (BT_HDR *)bt_hc_cbacks->alloc(packet_len);
166    if (buf) {
167      buf->event = hci_packet_to_event(packet_type);
168      buf->offset = 0;
169      buf->layer_specific = 0;
170      buf->len = packet_len;
171      memcpy(buf->data, buffer + 3, packet_len);
172      hci->transmit_buf(buf, NULL, 0);
173    } else {
174      ALOGE("%s dropping injected packet of length %zu", __func__, packet_len);
175    }
176
177    size_t remainder = client->buffer_size - frame_len;
178    memmove(buffer, buffer + frame_len, remainder);
179    client->buffer_size -= frame_len;
180  }
181}
182
183static void client_free(void *ptr) {
184  if (!ptr)
185    return;
186
187  client_t *client = (client_t *)ptr;
188  socket_free(client->socket);
189}
190