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 <string.h>
24
25#include "osi/include/allocator.h"
26#include "bt_types.h"
27#include "buffer_allocator.h"
28#include "hci_inject.h"
29#include "hci_layer.h"
30#include "osi/include/list.h"
31#include "osi/include/osi.h"
32#include "osi/include/log.h"
33#include "osi/include/socket.h"
34#include "osi/include/thread.h"
35
36typedef enum {
37  HCI_PACKET_COMMAND  = 1,
38  HCI_PACKET_ACL_DATA = 2,
39  HCI_PACKET_SCO_DATA = 3,
40  HCI_PACKET_EVENT    = 4,
41} hci_packet_t;
42
43typedef struct {
44  socket_t *socket;
45  uint8_t buffer[65536 + 3];  // 2 bytes length prefix, 1 byte type prefix.
46  size_t buffer_size;
47} client_t;
48
49static const port_t LISTEN_PORT = 8873;
50
51static const hci_inject_t interface;
52static const hci_t *hci;
53static const allocator_t *buffer_allocator;
54static socket_t *listen_socket;
55static thread_t *thread;
56static list_t *clients;
57
58static int hci_packet_to_event(hci_packet_t packet);
59static void accept_ready(socket_t *socket, void *context);
60static void read_ready(socket_t *socket, void *context);
61static void client_free(void *ptr);
62
63bool hci_inject_open(const hci_t *hci_interface) {
64#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
65  return true;          // Disable using network sockets for security reasons
66#endif
67
68  assert(listen_socket == NULL);
69  assert(thread == NULL);
70  assert(clients == NULL);
71  assert(hci_interface != NULL);
72
73  hci = hci_interface;
74
75  thread = thread_new("hci_inject");
76  if (!thread)
77    goto error;
78
79  clients = list_new(client_free);
80  if (!clients)
81    goto error;
82
83  listen_socket = socket_new();
84  if (!listen_socket)
85    goto error;
86
87  if (!socket_listen(listen_socket, LISTEN_PORT))
88    goto error;
89
90  socket_register(listen_socket, thread_get_reactor(thread), NULL, accept_ready, NULL);
91  return true;
92
93error:;
94  interface.close();
95  return false;
96}
97
98void hci_inject_close(void) {
99#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
100  return;               // Disable using network sockets for security reasons
101#endif
102
103  socket_free(listen_socket);
104  list_free(clients);
105  thread_free(thread);
106
107  listen_socket = NULL;
108  thread = NULL;
109  clients = NULL;
110}
111
112static int hci_packet_to_event(hci_packet_t packet) {
113  switch (packet) {
114    case HCI_PACKET_COMMAND:
115      return MSG_STACK_TO_HC_HCI_CMD;
116    case HCI_PACKET_ACL_DATA:
117      return MSG_STACK_TO_HC_HCI_ACL;
118    case HCI_PACKET_SCO_DATA:
119      return MSG_STACK_TO_HC_HCI_SCO;
120    default:
121      LOG_ERROR("%s unsupported packet type: %d", __func__, packet);
122      return -1;
123  }
124}
125
126static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) {
127  assert(socket != NULL);
128  assert(socket == listen_socket);
129
130  socket = socket_accept(socket);
131  if (!socket)
132    return;
133
134  client_t *client = (client_t *)osi_calloc(sizeof(client_t));
135  if (!client) {
136    LOG_ERROR("%s unable to allocate memory for client.", __func__);
137    socket_free(socket);
138    return;
139  }
140
141  client->socket = socket;
142
143  if (!list_append(clients, client)) {
144    LOG_ERROR("%s unable to add client to list.", __func__);
145    client_free(client);
146    return;
147  }
148
149  socket_register(socket, thread_get_reactor(thread), client, read_ready, NULL);
150}
151
152static void read_ready(UNUSED_ATTR socket_t *socket, void *context) {
153  assert(socket != NULL);
154  assert(context != NULL);
155
156  client_t *client = (client_t *)context;
157
158  ssize_t ret = socket_read(client->socket, client->buffer + client->buffer_size, sizeof(client->buffer) - client->buffer_size);
159  if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
160    list_remove(clients, client);
161    return;
162  }
163  client->buffer_size += ret;
164
165  while (client->buffer_size > 3) {
166    uint8_t *buffer = client->buffer;
167    hci_packet_t packet_type = (hci_packet_t)buffer[0];
168    size_t packet_len = (buffer[2] << 8) | buffer[1];
169    size_t frame_len = 3 + packet_len;
170
171    if (client->buffer_size < frame_len)
172      break;
173
174    // TODO(sharvil): validate incoming HCI messages.
175    // TODO(sharvil): once we have an HCI parser, we can eliminate
176    //   the 2-byte size field since it will be contained in the packet.
177
178    BT_HDR *buf = (BT_HDR *)buffer_allocator->alloc(BT_HDR_SIZE + packet_len);
179    if (buf) {
180      buf->event = hci_packet_to_event(packet_type);
181      buf->offset = 0;
182      buf->layer_specific = 0;
183      buf->len = packet_len;
184      memcpy(buf->data, buffer + 3, packet_len);
185      hci->transmit_downward(buf->event, buf);
186    } else {
187      LOG_ERROR("%s dropping injected packet of length %zu", __func__, packet_len);
188    }
189
190    size_t remainder = client->buffer_size - frame_len;
191    memmove(buffer, buffer + frame_len, remainder);
192    client->buffer_size -= frame_len;
193  }
194}
195
196static void client_free(void *ptr) {
197  if (!ptr)
198    return;
199
200  client_t *client = (client_t *)ptr;
201  socket_free(client->socket);
202  osi_free(client);
203}
204
205static const hci_inject_t interface = {
206  hci_inject_open,
207  hci_inject_close
208};
209
210const hci_inject_t *hci_inject_get_interface() {
211  buffer_allocator = buffer_allocator_get_interface();
212  return &interface;
213}
214