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