Home | History | Annotate | Download | only in l2cap
      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_l2cap_client"
     20 
     21 #include "stack/include/l2cap_client.h"
     22 
     23 #include <assert.h>
     24 #include <string.h>
     25 
     26 #include "btcore/include/bdaddr.h"
     27 #include "osi/include/allocator.h"
     28 #include "osi/include/buffer.h"
     29 #include "osi/include/list.h"
     30 #include "osi/include/log.h"
     31 #include "osi/include/osi.h"
     32 #include "stack/include/l2c_api.h"
     33 
     34 struct l2cap_client_t {
     35   l2cap_client_callbacks_t callbacks;
     36   void *context;
     37 
     38   uint16_t local_channel_id;
     39   uint16_t remote_mtu;
     40   bool configured_self;
     41   bool configured_peer;
     42   bool is_congested;
     43   list_t *outbound_fragments;
     44 };
     45 
     46 static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code);
     47 static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters);
     48 static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters);
     49 static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required);
     50 static void disconnect_completed_cb(uint16_t local_channel_id, uint16_t error_code);
     51 static void congestion_cb(uint16_t local_channel_id, bool is_congested);
     52 static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet);
     53 static void write_completed_cb(uint16_t local_channel_id, uint16_t packets_completed);
     54 
     55 static void fragment_packet(l2cap_client_t *client, buffer_t *packet);
     56 static void dispatch_fragments(l2cap_client_t *client);
     57 static l2cap_client_t *find(uint16_t local_channel_id);
     58 
     59 // From the Bluetooth Core specification.
     60 static const uint16_t L2CAP_MTU_DEFAULT = 672;
     61 static const uint16_t L2CAP_MTU_MINIMUM = 48;
     62 
     63 static const tL2CAP_APPL_INFO l2cap_callbacks = {
     64   .pL2CA_ConnectCfm_Cb       = connect_completed_cb,
     65   .pL2CA_ConfigInd_Cb        = config_request_cb,
     66   .pL2CA_ConfigCfm_Cb        = config_completed_cb,
     67   .pL2CA_DisconnectInd_Cb    = disconnect_request_cb,
     68   .pL2CA_DisconnectCfm_Cb    = disconnect_completed_cb,
     69   .pL2CA_CongestionStatus_Cb = congestion_cb,
     70   .pL2CA_DataInd_Cb          = read_ready_cb,
     71   .pL2CA_TxComplete_Cb       = write_completed_cb,
     72 };
     73 
     74 static list_t *l2cap_clients;  // A list of l2cap_client_t. Container does not own objects.
     75 
     76 buffer_t *l2cap_buffer_new(size_t size) {
     77   buffer_t *buf = buffer_new(size + L2CAP_MIN_OFFSET);
     78   buffer_t *slice = NULL;
     79   if (buf)
     80     slice = buffer_new_slice(buf, size);
     81   buffer_free(buf);
     82   return slice;
     83 }
     84 
     85 l2cap_client_t *l2cap_client_new(const l2cap_client_callbacks_t *callbacks, void *context) {
     86   assert(callbacks != NULL);
     87   assert(callbacks->connected != NULL);
     88   assert(callbacks->disconnected != NULL);
     89   assert(callbacks->read_ready != NULL);
     90   assert(callbacks->write_ready != NULL);
     91 
     92   if (!l2cap_clients) {
     93     l2cap_clients = list_new(NULL);
     94     if (!l2cap_clients) {
     95       LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.", __func__);
     96       return NULL;
     97     }
     98   }
     99 
    100   l2cap_client_t *ret = (l2cap_client_t *)osi_calloc(sizeof(l2cap_client_t));
    101 
    102   ret->callbacks = *callbacks;
    103   ret->context = context;
    104 
    105   ret->remote_mtu = L2CAP_MTU_DEFAULT;
    106   ret->outbound_fragments = list_new(NULL);
    107   if (!ret) {
    108     LOG_ERROR(LOG_TAG, "%s unable to allocate outbound L2CAP fragment list.", __func__);
    109     goto error;
    110   }
    111 
    112   list_append(l2cap_clients, ret);
    113 
    114   return ret;
    115 
    116 error:;
    117   osi_free(ret);
    118   return NULL;
    119 }
    120 
    121 void l2cap_client_free(l2cap_client_t *client) {
    122   if (!client)
    123     return;
    124 
    125   list_remove(l2cap_clients, client);
    126   l2cap_client_disconnect(client);
    127   list_free(client->outbound_fragments);
    128   osi_free(client);
    129 }
    130 
    131 bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm) {
    132   assert(client != NULL);
    133   assert(remote_bdaddr != NULL);
    134   assert(psm != 0);
    135   assert(!bdaddr_is_empty(remote_bdaddr));
    136   assert(client->local_channel_id == 0);
    137   assert(!client->configured_self);
    138   assert(!client->configured_peer);
    139   assert(!L2C_INVALID_PSM(psm));
    140 
    141   client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t *)remote_bdaddr);
    142   if (!client->local_channel_id) {
    143     LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
    144     return false;
    145   }
    146 
    147   L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks);
    148   return true;
    149 }
    150 
    151 void l2cap_client_disconnect(l2cap_client_t *client) {
    152   assert(client != NULL);
    153 
    154   if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
    155     LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id);
    156 
    157   client->local_channel_id = 0;
    158   client->remote_mtu = L2CAP_MTU_DEFAULT;
    159   client->configured_self = false;
    160   client->configured_peer = false;
    161   client->is_congested = false;
    162 
    163   for (const list_node_t *node = list_begin(client->outbound_fragments); node != list_end(client->outbound_fragments); node = list_next(node))
    164     osi_free(list_node(node));
    165 
    166   list_clear(client->outbound_fragments);
    167 }
    168 
    169 bool l2cap_client_is_connected(const l2cap_client_t *client) {
    170   assert(client != NULL);
    171 
    172   return client->local_channel_id != 0 && client->configured_self && client->configured_peer;
    173 }
    174 
    175 bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet) {
    176   assert(client != NULL);
    177   assert(packet != NULL);
    178   assert(l2cap_client_is_connected(client));
    179 
    180   if (client->is_congested)
    181     return false;
    182 
    183   fragment_packet(client, packet);
    184   dispatch_fragments(client);
    185   return true;
    186 }
    187 
    188 static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code) {
    189   assert(local_channel_id != 0);
    190 
    191   l2cap_client_t *client = find(local_channel_id);
    192   if (!client) {
    193     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id);
    194     return;
    195   }
    196 
    197   if (error_code != L2CAP_CONN_OK) {
    198     LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__, error_code);
    199     client->callbacks.disconnected(client, client->context);
    200     return;
    201   }
    202 
    203   // Use default L2CAP parameters.
    204   tL2CAP_CFG_INFO desired_parameters;
    205   memset(&desired_parameters, 0, sizeof(desired_parameters));
    206   if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
    207     LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
    208     client->callbacks.disconnected(client, client->context);
    209   }
    210 }
    211 
    212 static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters) {
    213   tL2CAP_CFG_INFO response;
    214   l2cap_client_t *client = find(local_channel_id);
    215 
    216   if (!client) {
    217     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
    218     return;
    219   }
    220 
    221   memset(&response, 0, sizeof(response));
    222   response.result = L2CAP_CFG_OK;
    223 
    224   if (requested_parameters->mtu_present) {
    225     // Make sure the peer chose an MTU at least as large as the minimum L2CAP MTU defined
    226     // by the Bluetooth Core spec.
    227     if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) {
    228       response.mtu = L2CAP_MTU_MINIMUM;
    229       response.mtu_present = true;
    230       response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    231     } else {
    232       client->remote_mtu = requested_parameters->mtu;
    233     }
    234   }
    235 
    236   if (requested_parameters->fcr_present) {
    237     if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) {
    238       response.fcr_present = true;
    239       response.fcr = requested_parameters->fcr;
    240       response.fcr.mode = L2CAP_FCR_BASIC_MODE;
    241       response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    242     }
    243   }
    244 
    245   if (!L2CA_ConfigRsp(local_channel_id, &response)) {
    246     LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id);
    247     l2cap_client_disconnect(client);
    248     return;
    249   }
    250 
    251   // If we've configured both endpoints, let the listener know we've connected.
    252   client->configured_peer = true;
    253   if (l2cap_client_is_connected(client))
    254     client->callbacks.connected(client, client->context);
    255 }
    256 
    257 static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters) {
    258   l2cap_client_t *client = find(local_channel_id);
    259 
    260   if (!client) {
    261     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
    262     return;
    263   }
    264 
    265   switch (negotiated_parameters->result) {
    266     // We'll get another configuration response later.
    267     case L2CAP_CFG_PENDING:
    268       break;
    269 
    270     case L2CAP_CFG_UNACCEPTABLE_PARAMS:
    271       // TODO: see if we can renegotiate parameters instead of dropping the connection.
    272       LOG_WARN(LOG_TAG, "%s dropping L2CAP connection due to unacceptable config parameters.", __func__);
    273       l2cap_client_disconnect(client);
    274       break;
    275 
    276     case L2CAP_CFG_OK:
    277       // If we've configured both endpoints, let the listener know we've connected.
    278       client->configured_self = true;
    279       if (l2cap_client_is_connected(client))
    280         client->callbacks.connected(client, client->context);
    281       break;
    282 
    283     // Failure, no further parameter negotiation possible.
    284     default:
    285       LOG_WARN(LOG_TAG, "%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result);
    286       l2cap_client_disconnect(client);
    287       break;
    288   }
    289 }
    290 
    291 static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required) {
    292   l2cap_client_t *client = find(local_channel_id);
    293   if (!client) {
    294     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
    295     return;
    296   }
    297 
    298   if (ack_required)
    299     L2CA_DisconnectRsp(local_channel_id);
    300 
    301   // We already sent a disconnect response so this LCID is now invalid.
    302   client->local_channel_id = 0;
    303   l2cap_client_disconnect(client);
    304 
    305   client->callbacks.disconnected(client, client->context);
    306 }
    307 
    308 static void disconnect_completed_cb(uint16_t local_channel_id, UNUSED_ATTR uint16_t error_code) {
    309   assert(local_channel_id != 0);
    310 
    311   l2cap_client_t *client = find(local_channel_id);
    312   if (!client) {
    313     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
    314     return;
    315   }
    316 
    317   client->local_channel_id = 0;
    318   l2cap_client_disconnect(client);
    319 
    320   client->callbacks.disconnected(client, client->context);
    321 }
    322 
    323 static void congestion_cb(uint16_t local_channel_id, bool is_congested) {
    324   assert(local_channel_id != 0);
    325 
    326   l2cap_client_t *client = find(local_channel_id);
    327   if (!client) {
    328     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
    329     return;
    330   }
    331 
    332   client->is_congested = is_congested;
    333 
    334   if (!is_congested) {
    335     // If we just decongested, dispatch whatever we have left over in our queue.
    336     // Once that's done, if we're still decongested, notify the listener so it
    337     // can start writing again.
    338     dispatch_fragments(client);
    339     if (!client->is_congested)
    340       client->callbacks.write_ready(client, client->context);
    341   }
    342 }
    343 
    344 static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet) {
    345   assert(local_channel_id != 0);
    346 
    347   l2cap_client_t *client = find(local_channel_id);
    348   if (!client) {
    349     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
    350     return;
    351   }
    352 
    353   // TODO(sharvil): eliminate copy from BT_HDR.
    354   buffer_t *buffer = buffer_new(packet->len);
    355   memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len);
    356   osi_free(packet);
    357 
    358   client->callbacks.read_ready(client, buffer, client->context);
    359   buffer_free(buffer);
    360 }
    361 
    362 static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id, UNUSED_ATTR uint16_t packets_completed) {
    363   // Do nothing. We update congestion state based on the congestion callback
    364   // and we've already removed items from outbound_fragments list so we don't
    365   // really care how many packets were successfully dispatched.
    366 }
    367 
    368 static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
    369   assert(client != NULL);
    370   assert(packet != NULL);
    371 
    372   // TODO(sharvil): eliminate copy into BT_HDR.
    373   BT_HDR *bt_packet = osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET);
    374   bt_packet->offset = L2CAP_MIN_OFFSET;
    375   bt_packet->len = buffer_length(packet);
    376   memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet));
    377 
    378   for (;;) {
    379     if (bt_packet->len <= client->remote_mtu) {
    380       if (bt_packet->len > 0)
    381         list_append(client->outbound_fragments, bt_packet);
    382       else
    383         osi_free(bt_packet);
    384       break;
    385     }
    386 
    387     BT_HDR *fragment = osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET);
    388     fragment->offset = L2CAP_MIN_OFFSET;
    389     fragment->len = client->remote_mtu;
    390     memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
    391 
    392     list_append(client->outbound_fragments, fragment);
    393 
    394     bt_packet->offset += client->remote_mtu;
    395     bt_packet->len -= client->remote_mtu;
    396   }
    397 }
    398 
    399 static void dispatch_fragments(l2cap_client_t *client) {
    400   assert(client != NULL);
    401   assert(!client->is_congested);
    402 
    403   while (!list_is_empty(client->outbound_fragments)) {
    404     BT_HDR *packet = (BT_HDR *)list_front(client->outbound_fragments);
    405     list_remove(client->outbound_fragments, packet);
    406 
    407     switch (L2CA_DataWrite(client->local_channel_id, packet)) {
    408       case L2CAP_DW_CONGESTED:
    409         client->is_congested = true;
    410         return;
    411 
    412       case L2CAP_DW_FAILED:
    413         LOG_ERROR(LOG_TAG, "%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id);
    414         l2cap_client_disconnect(client);
    415         return;
    416 
    417       case L2CAP_DW_SUCCESS:
    418         break;
    419     }
    420   }
    421 }
    422 
    423 static l2cap_client_t *find(uint16_t local_channel_id) {
    424   assert(local_channel_id != 0);
    425 
    426   for (const list_node_t *node = list_begin(l2cap_clients); node != list_end(l2cap_clients); node = list_next(node)) {
    427     l2cap_client_t *client = (l2cap_client_t *)list_node(node);
    428     if (client->local_channel_id == local_channel_id)
    429       return client;
    430   }
    431 
    432   return NULL;
    433 }
    434