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