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
55typedef 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.
62static 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
73static sco_socket_t *sco_socket_establish_locked(bool is_listening, const bt_bdaddr_t *bd_addr, int *sock_fd);
74static sco_socket_t *sco_socket_new(void);
75static void sco_socket_free_locked(sco_socket_t *socket);
76static sco_socket_t *sco_socket_find_locked(uint16_t sco_handle);
77static void connection_request_cb(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *data);
78static void connect_completed_cb(uint16_t sco_handle);
79static void disconnect_completed_cb(uint16_t sco_handle);
80static 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.
84static pthread_mutex_t lock;
85static list_t *sco_sockets;              // Owns a collection of sco_socket_t objects.
86static sco_socket_t *listen_sco_socket;  // Not owned, do not free.
87static thread_t *thread;                 // Not owned, do not free.
88
89bt_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
104bt_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
111bt_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
127bt_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.
139static 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
173error:;
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
183static 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.
192static 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.
203static 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
212static 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
263error:;
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
271static 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
290out:;
291  pthread_mutex_unlock(&lock);
292}
293
294static 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
305out:;
306  pthread_mutex_unlock(&lock);
307}
308
309static 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