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(&params);
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