OSDN Git Service

Switch to an epoll-based reactor implementation.
[android-x86/system-bt.git] / hci / src / hci_inject.c
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
33 typedef 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
40 typedef 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
46 static const port_t LISTEN_PORT = 8873;
47
48 static const bt_hc_interface_t *hci;
49 static socket_t *listen_socket;
50 static thread_t *thread;
51 static list_t *clients;
52
53 static int hci_packet_to_event(hci_packet_t packet);
54 static void accept_ready(socket_t *socket, void *context);
55 static void read_ready(socket_t *socket, void *context);
56 static void client_free(void *ptr);
57
58 bool 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   thread = thread_new("hci_inject");
66   if (!thread)
67     goto error;
68
69   clients = list_new(client_free);
70   if (!clients)
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), NULL, accept_ready, NULL);
81   return true;
82
83 error:;
84   hci_inject_close();
85   return false;
86 }
87
88 void hci_inject_close(void) {
89   socket_free(listen_socket);
90   list_free(clients);
91   thread_free(thread);
92
93   listen_socket = NULL;
94   thread = NULL;
95   clients = NULL;
96 }
97
98 static 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
112 static 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), client, read_ready, NULL);
136 }
137
138 static 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
183 static void client_free(void *ptr) {
184   if (!ptr)
185     return;
186
187   client_t *client = (client_t *)ptr;
188   socket_free(client->socket);
189 }