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