1 /******************************************************************************
2  *
3  *  Copyright (C) 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 <assert.h>
22 #include <errno.h>
23 #include <hardware/bluetooth.h>
24 #include <hardware/bt_sock.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 
29 #include "btif_common.h"
30 #include "osi/include/allocator.h"
31 #include "osi/include/list.h"
32 #include "osi/include/osi.h"
33 #include "osi/include/log.h"
34 #include "osi/include/socket.h"
35 #include "osi/include/thread.h"
36 
37 // This module provides a socket abstraction for SCO connections to a higher
38 // layer. It returns file descriptors representing two types of sockets:
39 // listening (server) and connected (client) sockets. No SCO data is
40 // transferred across these sockets; instead, they are used to manage SCO
41 // connection lifecycles while the data routing takes place over the I2S bus.
42 //
43 // This code bridges the gap between the BTM layer, which implements SCO
44 // connections, and the Android HAL. It adapts the BTM representation of SCO
45 // connections (integer handles) to a file descriptor representation usable by
46 // Android's LocalSocket implementation.
47 //
48 // Sample flow for an incoming connection:
49 //   btsock_sco_listen()       - listen for incoming connections
50 //   connection_request_cb()   - incoming connection request from remote host
51 //   connect_completed_cb()    - connection successfully established
52 //   socket_read_ready_cb()    - local host closed SCO socket
53 //   disconnect_completed_cb() - connection terminated
54 
55 typedef struct {
56   uint16_t sco_handle;
57   socket_t *socket;
58   bool connect_completed;
59 } sco_socket_t;
60 
61 // TODO: verify packet types that are being sent OTA.
62 static tBTM_ESCO_PARAMS sco_parameters = {
63     BTM_64KBITS_RATE,                   /* TX Bandwidth (64 kbits/sec)              */
64     BTM_64KBITS_RATE,                   /* RX Bandwidth (64 kbits/sec)              */
65     0x000a,                             /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
66     0x0060,                             /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
67     (BTM_SCO_LINK_ALL_PKT_MASK       |
68      BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
69      BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
70      BTM_ESCO_RETRANS_POWER       /* Retransmission effort                      */
71 };
72 
73 static sco_socket_t *sco_socket_establish_locked(bool is_listening, const bt_bdaddr_t *bd_addr, int *sock_fd);
74 static sco_socket_t *sco_socket_new(void);
75 static void sco_socket_free_locked(sco_socket_t *socket);
76 static sco_socket_t *sco_socket_find_locked(uint16_t sco_handle);
77 static void connection_request_cb(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *data);
78 static void connect_completed_cb(uint16_t sco_handle);
79 static void disconnect_completed_cb(uint16_t sco_handle);
80 static void socket_read_ready_cb(socket_t *socket, void *context);
81 
82 // |lock| protects all of the static variables below and
83 // calls into the BTM layer.
84 static pthread_mutex_t lock;
85 static list_t *sco_sockets;              // Owns a collection of sco_socket_t objects.
86 static sco_socket_t *listen_sco_socket;  // Not owned, do not free.
87 static thread_t *thread;                 // Not owned, do not free.
88 
btsock_sco_init(thread_t * thread_)89 bt_status_t btsock_sco_init(thread_t *thread_) {
90   assert(thread_ != NULL);
91 
92   sco_sockets = list_new((list_free_cb)sco_socket_free_locked);
93   if (!sco_sockets)
94     return BT_STATUS_FAIL;
95 
96   pthread_mutex_init(&lock, NULL);
97 
98   thread = thread_;
99   BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &sco_parameters);
100 
101   return BT_STATUS_SUCCESS;
102 }
103 
btsock_sco_cleanup(void)104 bt_status_t btsock_sco_cleanup(void) {
105   list_free(sco_sockets);
106   sco_sockets = NULL;
107   pthread_mutex_destroy(&lock);
108   return BT_STATUS_SUCCESS;
109 }
110 
btsock_sco_listen(int * sock_fd,UNUSED_ATTR int flags)111 bt_status_t btsock_sco_listen(int *sock_fd, UNUSED_ATTR int flags) {
112   assert(sock_fd != NULL);
113 
114   pthread_mutex_lock(&lock);
115 
116   sco_socket_t *sco_socket = sco_socket_establish_locked(true, NULL, sock_fd);
117   if (sco_socket) {
118     BTM_RegForEScoEvts(sco_socket->sco_handle, connection_request_cb);
119     listen_sco_socket = sco_socket;
120   }
121 
122   pthread_mutex_unlock(&lock);
123 
124   return sco_socket ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
125 }
126 
btsock_sco_connect(const bt_bdaddr_t * bd_addr,int * sock_fd,UNUSED_ATTR int flags)127 bt_status_t btsock_sco_connect(const bt_bdaddr_t *bd_addr, int *sock_fd, UNUSED_ATTR int flags) {
128   assert(bd_addr != NULL);
129   assert(sock_fd != NULL);
130 
131   pthread_mutex_lock(&lock);
132   sco_socket_t *sco_socket = sco_socket_establish_locked(false, bd_addr, sock_fd);
133   pthread_mutex_unlock(&lock);
134 
135   return (sco_socket != NULL) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
136 }
137 
138 // Must be called with |lock| held.
sco_socket_establish_locked(bool is_listening,const bt_bdaddr_t * bd_addr,int * sock_fd)139 static sco_socket_t *sco_socket_establish_locked(bool is_listening, const bt_bdaddr_t *bd_addr, int *sock_fd) {
140   int pair[2] = { INVALID_FD, INVALID_FD };
141   sco_socket_t *sco_socket = NULL;
142 
143   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) {
144     LOG_ERROR("%s unable to allocate socket pair: %s", __func__, strerror(errno));
145     goto error;
146   }
147 
148   sco_socket = sco_socket_new();
149   if (!sco_socket) {
150     LOG_ERROR("%s unable to allocate new SCO socket.", __func__);
151     goto error;
152   }
153 
154   tBTM_STATUS status = BTM_CreateSco((uint8_t *)bd_addr, !is_listening, sco_parameters.packet_types, &sco_socket->sco_handle, connect_completed_cb, disconnect_completed_cb);
155   if (status != BTM_CMD_STARTED) {
156     LOG_ERROR("%s unable to create SCO socket: %d", __func__, status);
157     goto error;
158   }
159 
160   socket_t *socket = socket_new_from_fd(pair[1]);
161   if (!socket) {
162     LOG_ERROR("%s unable to allocate socket from file descriptor %d.", __func__, pair[1]);
163     goto error;
164   }
165 
166   *sock_fd = pair[0];           // Transfer ownership of one end to caller.
167   sco_socket->socket = socket;  // Hang on to the other end.
168   list_append(sco_sockets, sco_socket);
169 
170   socket_register(socket, thread_get_reactor(thread), sco_socket, socket_read_ready_cb, NULL);
171   return sco_socket;
172 
173 error:;
174   if (pair[0] != INVALID_FD)
175     close(pair[0]);
176   if (pair[1] != INVALID_FD)
177     close(pair[1]);
178 
179   sco_socket_free_locked(sco_socket);
180   return NULL;
181 }
182 
sco_socket_new(void)183 static sco_socket_t *sco_socket_new(void) {
184   sco_socket_t *sco_socket = (sco_socket_t *)osi_calloc(sizeof(sco_socket_t));
185   if (sco_socket)
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 socket thread
191 // is no longer alive.
sco_socket_free_locked(sco_socket_t * sco_socket)192 static void sco_socket_free_locked(sco_socket_t *sco_socket) {
193   if (!sco_socket)
194     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); node != list_end(sco_sockets); node = list_next(node)) {
205     sco_socket_t *sco_socket = (sco_socket_t *)list_node(node);
206     if (sco_socket->sco_handle == sco_handle)
207       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, tBTM_ESCO_EVT_DATA *data) {
213   assert(data != NULL);
214 
215   // Don't care about change of link parameters, only connection requests.
216   if (event != BTM_ESCO_CONN_REQ_EVT)
217     return;
218 
219   pthread_mutex_lock(&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   if (!sco_socket) {
226     LOG_ERROR("%s unable to find sco_socket for handle: %hu", __func__, conn_data->sco_inx);
227     goto error;
228   }
229 
230   if (sco_socket != listen_sco_socket) {
231     LOG_ERROR("%s received connection request on non-listening socket handle: %hu", __func__, conn_data->sco_inx);
232     goto error;
233   }
234 
235   sco_socket_t *new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd);
236   if (!new_sco_socket) {
237     LOG_ERROR("%s unable to allocate new sco_socket.", __func__);
238     goto error;
239   }
240 
241   // Swap socket->sco_handle and new_socket->sco_handle
242   uint16_t temp = sco_socket->sco_handle;
243   sco_socket->sco_handle = new_sco_socket->sco_handle;
244   new_sco_socket->sco_handle = temp;
245 
246   sock_connect_signal_t connect_signal;
247   connect_signal.size = sizeof(connect_signal);
248   memcpy(&connect_signal.bd_addr, conn_data->bd_addr, sizeof(bt_bdaddr_t));
249   connect_signal.channel = 0;
250   connect_signal.status = 0;
251 
252   if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal, sizeof(connect_signal), client_fd) != sizeof(connect_signal)) {
253     LOG_ERROR("%s unable to send new file descriptor to listening socket.", __func__);
254     goto error;
255   }
256 
257   BTM_RegForEScoEvts(listen_sco_socket->sco_handle, connection_request_cb);
258   BTM_EScoConnRsp(conn_data->sco_inx, HCI_SUCCESS, NULL);
259 
260   pthread_mutex_unlock(&lock);
261   return;
262 
263 error:;
264   pthread_mutex_unlock(&lock);
265 
266   if (client_fd != INVALID_FD)
267     close(client_fd);
268   BTM_EScoConnRsp(conn_data->sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
269 }
270 
connect_completed_cb(uint16_t sco_handle)271 static void connect_completed_cb(uint16_t sco_handle) {
272   pthread_mutex_lock(&lock);
273 
274   sco_socket_t *sco_socket = sco_socket_find_locked(sco_handle);
275   if (!sco_socket) {
276     LOG_ERROR("%s SCO socket not found on connect for handle: %hu", __func__, sco_handle);
277     goto out;
278   }
279 
280   // If sco_socket->socket was closed, we should tear down because there is no app-level
281   // interest in the SCO socket.
282   if (!sco_socket->socket) {
283     BTM_RemoveSco(sco_socket->sco_handle);
284     list_remove(sco_sockets, sco_socket);
285     goto out;
286   }
287 
288   sco_socket->connect_completed = true;
289 
290 out:;
291   pthread_mutex_unlock(&lock);
292 }
293 
disconnect_completed_cb(uint16_t sco_handle)294 static void disconnect_completed_cb(uint16_t sco_handle) {
295   pthread_mutex_lock(&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__, sco_handle);
300     goto out;
301   }
302 
303   list_remove(sco_sockets, sco_socket);
304 
305 out:;
306   pthread_mutex_unlock(&lock);
307 }
308 
socket_read_ready_cb(UNUSED_ATTR socket_t * socket,void * context)309 static void socket_read_ready_cb(UNUSED_ATTR socket_t *socket, void *context) {
310   pthread_mutex_lock(&lock);
311 
312   sco_socket_t *sco_socket = (sco_socket_t *)context;
313   socket_free(sco_socket->socket);
314   sco_socket->socket = NULL;
315 
316   // Defer the underlying disconnect until the connection completes
317   // since the BTM code doesn't behave correctly when a disconnect
318   // request is issued while a connect is in progress. The fact that
319   // sco_socket->socket == NULL indicates to the connect callback
320   // routine that the socket is no longer desired and should be torn
321   // down.
322   if (sco_socket->connect_completed || sco_socket == listen_sco_socket) {
323     if (BTM_RemoveSco(sco_socket->sco_handle) == BTM_SUCCESS)
324       list_remove(sco_sockets, sco_socket);
325     if (sco_socket == listen_sco_socket)
326       listen_sco_socket = NULL;
327   }
328 
329   pthread_mutex_unlock(&lock);
330 }
331