1 /******************************************************************************
2 *
3 * Copyright 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_btif_sock_sco"
20
21 #include <sys/socket.h>
22 #include <sys/types.h>
23
24 #include <cstdint>
25 #include <mutex>
26
27 #include "device/include/esco_parameters.h"
28 #include "include/hardware/bt_sock.h"
29 #include "osi/include/allocator.h"
30 #include "osi/include/list.h"
31 #include "osi/include/log.h"
32 #include "osi/include/osi.h" // UNUSED_ATTR
33 #include "osi/include/socket.h"
34 #include "osi/include/thread.h"
35 #include "stack/include/btm_api.h"
36 #include "types/raw_address.h"
37
38 // This module provides a socket abstraction for SCO connections to a higher
39 // layer. It returns file descriptors representing two types of sockets:
40 // listening (server) and connected (client) sockets. No SCO data is
41 // transferred across these sockets; instead, they are used to manage SCO
42 // connection lifecycles while the data routing takes place over the I2S bus.
43 //
44 // This code bridges the gap between the BTM layer, which implements SCO
45 // connections, and the Android HAL. It adapts the BTM representation of SCO
46 // connections (integer handles) to a file descriptor representation usable by
47 // Android's LocalSocket implementation.
48 //
49 // Sample flow for an incoming connection:
50 // btsock_sco_listen() - listen for incoming connections
51 // connection_request_cb() - incoming connection request from remote host
52 // connect_completed_cb() - connection successfully established
53 // socket_read_ready_cb() - local host closed SCO socket
54 // disconnect_completed_cb() - connection terminated
55
56 typedef struct {
57 uint16_t sco_handle;
58 socket_t* socket;
59 bool connect_completed;
60 } sco_socket_t;
61
62 static sco_socket_t* sco_socket_establish_locked(bool is_listening,
63 const RawAddress* bd_addr,
64 int* sock_fd);
65 static sco_socket_t* sco_socket_new(void);
66 static void sco_socket_free_locked(sco_socket_t* socket);
67 static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle);
68 static void connection_request_cb(tBTM_ESCO_EVT event,
69 tBTM_ESCO_EVT_DATA* data);
70 static void connect_completed_cb(uint16_t sco_handle);
71 static void disconnect_completed_cb(uint16_t sco_handle);
72 static void socket_read_ready_cb(socket_t* socket, void* context);
73
74 // |sco_lock| protects all of the static variables below and
75 // calls into the BTM layer.
76 static std::mutex sco_lock;
77 static list_t* sco_sockets; // Owns a collection of sco_socket_t objects.
78 static sco_socket_t* listen_sco_socket; // Not owned, do not free.
79 static thread_t* thread; // Not owned, do not free.
80
btsock_sco_init(thread_t * thread_)81 bt_status_t btsock_sco_init(thread_t* thread_) {
82 CHECK(thread_ != NULL);
83
84 sco_sockets = list_new((list_free_cb)sco_socket_free_locked);
85 if (!sco_sockets) return BT_STATUS_FAIL;
86
87 thread = thread_;
88 enh_esco_params_t params = esco_parameters_for_codec(SCO_CODEC_CVSD_D1);
89 BTM_SetEScoMode(¶ms);
90
91 return BT_STATUS_SUCCESS;
92 }
93
btsock_sco_cleanup(void)94 bt_status_t btsock_sco_cleanup(void) {
95 list_free(sco_sockets);
96 sco_sockets = NULL;
97 return BT_STATUS_SUCCESS;
98 }
99
btsock_sco_listen(int * sock_fd,UNUSED_ATTR int flags)100 bt_status_t btsock_sco_listen(int* sock_fd, UNUSED_ATTR int flags) {
101 CHECK(sock_fd != NULL);
102
103 std::unique_lock<std::mutex> lock(sco_lock);
104
105 sco_socket_t* sco_socket = sco_socket_establish_locked(true, NULL, sock_fd);
106 if (!sco_socket) return BT_STATUS_FAIL;
107
108 BTM_RegForEScoEvts(sco_socket->sco_handle, connection_request_cb);
109 listen_sco_socket = sco_socket;
110
111 return BT_STATUS_SUCCESS;
112 }
113
btsock_sco_connect(const RawAddress * bd_addr,int * sock_fd,UNUSED_ATTR int flags)114 bt_status_t btsock_sco_connect(const RawAddress* bd_addr, int* sock_fd,
115 UNUSED_ATTR int flags) {
116 CHECK(bd_addr != NULL);
117 CHECK(sock_fd != NULL);
118
119 std::unique_lock<std::mutex> lock(sco_lock);
120 sco_socket_t* sco_socket =
121 sco_socket_establish_locked(false, bd_addr, sock_fd);
122
123 return (sco_socket != NULL) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
124 }
125
126 // Must be called with |lock| held.
sco_socket_establish_locked(bool is_listening,const RawAddress * bd_addr,int * sock_fd)127 static sco_socket_t* sco_socket_establish_locked(bool is_listening,
128 const RawAddress* bd_addr,
129 int* sock_fd) {
130 int pair[2] = {INVALID_FD, INVALID_FD};
131 sco_socket_t* sco_socket = NULL;
132 socket_t* socket = NULL;
133 tBTM_STATUS status;
134 enh_esco_params_t params;
135 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) {
136 LOG_ERROR("%s unable to allocate socket pair: %s", __func__,
137 strerror(errno));
138 goto error;
139 }
140
141 sco_socket = sco_socket_new();
142 if (!sco_socket) {
143 LOG_ERROR("%s unable to allocate new SCO socket.", __func__);
144 goto error;
145 }
146
147 params = esco_parameters_for_codec(SCO_CODEC_CVSD_D1);
148 status = BTM_CreateSco(bd_addr, !is_listening, params.packet_types,
149 &sco_socket->sco_handle, connect_completed_cb,
150 disconnect_completed_cb);
151 if (status != BTM_CMD_STARTED) {
152 LOG_ERROR("%s unable to create SCO socket: %d", __func__, status);
153 goto error;
154 }
155
156 socket = socket_new_from_fd(pair[1]);
157 if (!socket) {
158 LOG_ERROR("%s unable to allocate socket from file descriptor %d.", __func__,
159 pair[1]);
160 goto error;
161 }
162
163 *sock_fd = pair[0]; // Transfer ownership of one end to caller.
164 sco_socket->socket = socket; // Hang on to the other end.
165 list_append(sco_sockets, sco_socket);
166
167 socket_register(socket, thread_get_reactor(thread), sco_socket,
168 socket_read_ready_cb, NULL);
169 return sco_socket;
170
171 error:;
172 if (pair[0] != INVALID_FD) close(pair[0]);
173 if (pair[1] != INVALID_FD) close(pair[1]);
174
175 sco_socket_free_locked(sco_socket);
176 return NULL;
177 }
178
sco_socket_new(void)179 static sco_socket_t* sco_socket_new(void) {
180 sco_socket_t* sco_socket = (sco_socket_t*)osi_calloc(sizeof(sco_socket_t));
181 sco_socket->sco_handle = BTM_INVALID_SCO_INDEX;
182 return sco_socket;
183 }
184
185 // Must be called with |lock| held except during teardown when we know the
186 // socket thread
187 // is no longer alive.
sco_socket_free_locked(sco_socket_t * sco_socket)188 static void sco_socket_free_locked(sco_socket_t* sco_socket) {
189 if (!sco_socket) return;
190
191 if (sco_socket->sco_handle != BTM_INVALID_SCO_INDEX)
192 BTM_RemoveSco(sco_socket->sco_handle);
193 socket_free(sco_socket->socket);
194 osi_free(sco_socket);
195 }
196
197 // Must be called with |lock| held.
sco_socket_find_locked(uint16_t sco_handle)198 static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle) {
199 for (const list_node_t* node = list_begin(sco_sockets);
200 node != list_end(sco_sockets); node = list_next(node)) {
201 sco_socket_t* sco_socket = (sco_socket_t*)list_node(node);
202 if (sco_socket->sco_handle == sco_handle) return sco_socket;
203 }
204 return NULL;
205 }
206
connection_request_cb(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * data)207 static void connection_request_cb(tBTM_ESCO_EVT event,
208 tBTM_ESCO_EVT_DATA* data) {
209 CHECK(data != NULL);
210
211 // Don't care about change of link parameters, only connection requests.
212 if (event != BTM_ESCO_CONN_REQ_EVT) return;
213
214 std::unique_lock<std::mutex> lock(sco_lock);
215
216 const tBTM_ESCO_CONN_REQ_EVT_DATA* conn_data = &data->conn_evt;
217 sco_socket_t* sco_socket = sco_socket_find_locked(conn_data->sco_inx);
218 int client_fd = INVALID_FD;
219
220 uint16_t temp;
221 sco_socket_t* new_sco_socket;
222
223 if (!sco_socket) {
224 LOG_ERROR("%s unable to find sco_socket for handle: %hu", __func__,
225 conn_data->sco_inx);
226 goto error;
227 }
228
229 if (sco_socket != listen_sco_socket) {
230 LOG_ERROR(
231
232 "%s received connection request on non-listening socket handle: %hu",
233 __func__, conn_data->sco_inx);
234 goto error;
235 }
236
237 new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd);
238 if (!new_sco_socket) {
239 LOG_ERROR("%s unable to allocate new sco_socket.", __func__);
240 goto error;
241 }
242
243 // Swap socket->sco_handle and new_socket->sco_handle
244 temp = sco_socket->sco_handle;
245 sco_socket->sco_handle = new_sco_socket->sco_handle;
246 new_sco_socket->sco_handle = temp;
247
248 sock_connect_signal_t connect_signal;
249 connect_signal.size = sizeof(connect_signal);
250 connect_signal.bd_addr = conn_data->bd_addr;
251 connect_signal.channel = 0;
252 connect_signal.status = 0;
253
254 if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal,
255 sizeof(connect_signal),
256 client_fd) != sizeof(connect_signal)) {
257 LOG_ERROR("%s unable to send new file descriptor to listening socket.",
258 __func__);
259 goto error;
260 }
261
262 BTM_RegForEScoEvts(listen_sco_socket->sco_handle, connection_request_cb);
263 BTM_EScoConnRsp(conn_data->sco_inx, HCI_SUCCESS, NULL);
264
265 return;
266
267 error:;
268 if (client_fd != INVALID_FD) close(client_fd);
269 BTM_EScoConnRsp(conn_data->sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
270 }
271
connect_completed_cb(uint16_t sco_handle)272 static void connect_completed_cb(uint16_t sco_handle) {
273 std::unique_lock<std::mutex> lock(sco_lock);
274
275 sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
276 if (!sco_socket) {
277 LOG_ERROR("%s SCO socket not found on connect for handle: %hu", __func__,
278 sco_handle);
279 return;
280 }
281
282 // If sco_socket->socket was closed, we should tear down because there is no
283 // app-level
284 // interest in the SCO socket.
285 if (!sco_socket->socket) {
286 BTM_RemoveSco(sco_socket->sco_handle);
287 list_remove(sco_sockets, sco_socket);
288 return;
289 }
290
291 sco_socket->connect_completed = true;
292 }
293
disconnect_completed_cb(uint16_t sco_handle)294 static void disconnect_completed_cb(uint16_t sco_handle) {
295 std::unique_lock<std::mutex> lock(sco_lock);
296
297 sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
298 if (!sco_socket) {
299 LOG_ERROR("%s SCO socket not found on disconnect for handle: %hu", __func__,
300 sco_handle);
301 return;
302 }
303
304 list_remove(sco_sockets, sco_socket);
305 }
306
socket_read_ready_cb(UNUSED_ATTR socket_t * socket,void * context)307 static void socket_read_ready_cb(UNUSED_ATTR socket_t* socket, void* context) {
308 std::unique_lock<std::mutex> lock(sco_lock);
309
310 sco_socket_t* sco_socket = (sco_socket_t*)context;
311 socket_free(sco_socket->socket);
312 sco_socket->socket = NULL;
313
314 // Defer the underlying disconnect until the connection completes
315 // since the BTM code doesn't behave correctly when a disconnect
316 // request is issued while a connect is in progress. The fact that
317 // sco_socket->socket == NULL indicates to the connect callback
318 // routine that the socket is no longer desired and should be torn
319 // down.
320 if (sco_socket->connect_completed || sco_socket == listen_sco_socket) {
321 if (BTM_RemoveSco(sco_socket->sco_handle) == BTM_SUCCESS)
322 list_remove(sco_sockets, sco_socket);
323 if (sco_socket == listen_sco_socket) listen_sco_socket = NULL;
324 }
325 }
326