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