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