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