Home | History | Annotate | Download | only in gap
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2013 Broadcom Corporation
      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 #include <string.h>
     20 #include "bt_target.h"
     21 #include "bt_utils.h"
     22 #include "btu.h"
     23 #include "gap_int.h"
     24 #include "l2c_int.h"
     25 #include "l2cdefs.h"
     26 #include "osi/include/mutex.h"
     27 #include "osi/include/osi.h"
     28 #if (GAP_CONN_INCLUDED == TRUE)
     29 #include "btm_int.h"
     30 
     31 /******************************************************************************/
     32 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     33 /******************************************************************************/
     34 static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
     35                             uint8_t l2cap_id);
     36 static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result);
     37 static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
     38 static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
     39 static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
     40 static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
     41 static void gap_congestion_ind(uint16_t lcid, bool is_congested);
     42 static void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent);
     43 
     44 static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid);
     45 static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle);
     46 static tGAP_CCB* gap_allocate_ccb(void);
     47 static void gap_release_ccb(tGAP_CCB* p_ccb);
     48 static void gap_checks_con_flags(tGAP_CCB* p_ccb);
     49 
     50 /*******************************************************************************
     51  *
     52  * Function         gap_conn_init
     53  *
     54  * Description      This function is called to initialize GAP connection
     55  *                  management
     56  *
     57  * Returns          void
     58  *
     59  ******************************************************************************/
     60 void gap_conn_init(void) {
     61 #if (AMP_INCLUDED == TRUE)
     62   gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
     63   gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm;
     64   gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL;
     65   gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind;
     66   gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm;
     67   gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind;
     68   gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL;
     69   gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL;
     70   gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind;
     71   gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind;
     72   gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL;
     73   gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL;
     74   gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL;
     75   gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL;     // gap_move_cfm
     76   gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL;  // gap_move_cfm_rsp
     77 
     78 #else
     79   gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
     80   gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
     81   gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
     82   gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
     83   gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
     84   gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
     85   gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
     86   gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
     87   gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
     88   gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
     89   gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;
     90 #endif
     91 }
     92 
     93 /*******************************************************************************
     94  *
     95  * Function         GAP_ConnOpen
     96  *
     97  * Description      This function is called to open an L2CAP connection.
     98  *
     99  * Parameters:      is_server   - If true, the connection is not created
    100  *                                but put into a "listen" mode waiting for
    101  *                                the remote side to connect.
    102  *
    103  *                  service_id  - Unique service ID from
    104  *                                BTM_SEC_SERVICE_FIRST_EMPTY (6)
    105  *                                to BTM_SEC_MAX_SERVICE_RECORDS (32)
    106  *
    107  *                  p_rem_bda   - Pointer to remote BD Address.
    108  *                                If a server, and we don't care about the
    109  *                                remote BD Address, then NULL should be passed.
    110  *
    111  *                  psm         - the PSM used for the connection
    112  *
    113  *                  p_config    - Optional pointer to configuration structure.
    114  *                                If NULL, the default GAP configuration will
    115  *                                be used.
    116  *
    117  *                  security    - security flags
    118  *                  chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC,
    119  *                                    GAP_FCR_CHAN_OPT_ERTM,
    120  *                                    GAP_FCR_CHAN_OPT_STREAM)
    121  *
    122  *                  p_cb        - Pointer to callback function for events.
    123  *
    124  * Returns          handle of the connection if successful, else
    125  *                            GAP_INVALID_HANDLE
    126  *
    127  ******************************************************************************/
    128 uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
    129                       bool is_server, BD_ADDR p_rem_bda, uint16_t psm,
    130                       tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info,
    131                       uint16_t security, uint8_t chan_mode_mask,
    132                       tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) {
    133   tGAP_CCB* p_ccb;
    134   uint16_t cid;
    135 
    136   GAP_TRACE_EVENT("GAP_CONN - Open Request");
    137 
    138   /* Allocate a new CCB. Return if none available. */
    139   p_ccb = gap_allocate_ccb();
    140   if (p_ccb == NULL) return (GAP_INVALID_HANDLE);
    141 
    142   /* update the transport */
    143   p_ccb->transport = transport;
    144 
    145   /* If caller specified a BD address, save it */
    146   if (p_rem_bda) {
    147     /* the bd addr is not BT_BD_ANY, then a bd address was specified */
    148     if (memcmp(p_rem_bda, BT_BD_ANY, BD_ADDR_LEN))
    149       p_ccb->rem_addr_specified = true;
    150 
    151     memcpy(&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
    152   } else if (!is_server) {
    153     /* remore addr is not specified and is not a server -> bad */
    154     return (GAP_INVALID_HANDLE);
    155   }
    156 
    157   /* A client MUST have specified a bd addr to connect with */
    158   if (!p_ccb->rem_addr_specified && !is_server) {
    159     gap_release_ccb(p_ccb);
    160     GAP_TRACE_ERROR(
    161         "GAP ERROR: Client must specify a remote BD ADDR to connect to!");
    162     return (GAP_INVALID_HANDLE);
    163   }
    164 
    165   /* Check if configuration was specified */
    166   if (p_cfg) p_ccb->cfg = *p_cfg;
    167 
    168   /* Configure L2CAP COC, if transport is LE */
    169   if (transport == BT_TRANSPORT_LE) {
    170     p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
    171     p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
    172     p_ccb->local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
    173   }
    174 
    175   p_ccb->p_callback = p_cb;
    176 
    177 /* If originator, use a dynamic PSM */
    178 #if (AMP_INCLUDED == TRUE)
    179   if (!is_server)
    180     gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
    181   else
    182     gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
    183 #else
    184   if (!is_server)
    185     gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
    186   else
    187     gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
    188 #endif
    189 
    190   /* Register the PSM with L2CAP */
    191   if (transport == BT_TRANSPORT_BR_EDR) {
    192     p_ccb->psm =
    193         L2CA_REGISTER(psm, &gap_cb.conn.reg_info,
    194                       AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
    195     if (p_ccb->psm == 0) {
    196       GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
    197       gap_release_ccb(p_ccb);
    198       return (GAP_INVALID_HANDLE);
    199     }
    200   }
    201 
    202   if (transport == BT_TRANSPORT_LE) {
    203     p_ccb->psm =
    204         L2CA_REGISTER_COC(psm, &gap_cb.conn.reg_info,
    205                           AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
    206     if (p_ccb->psm == 0) {
    207       GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
    208       gap_release_ccb(p_ccb);
    209       return (GAP_INVALID_HANDLE);
    210     }
    211   }
    212 
    213   /* Register with Security Manager for the specific security level */
    214   p_ccb->service_id = service_id;
    215   if (!BTM_SetSecurityLevel((uint8_t)!is_server, p_serv_name, p_ccb->service_id,
    216                             security, p_ccb->psm, 0, 0)) {
    217     GAP_TRACE_ERROR("GAP_CONN - Security Error");
    218     gap_release_ccb(p_ccb);
    219     return (GAP_INVALID_HANDLE);
    220   }
    221 
    222   /* Fill in eL2CAP parameter data */
    223   if (p_ccb->cfg.fcr_present) {
    224     if (ertm_info == NULL) {
    225       p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
    226       p_ccb->ertm_info.user_rx_buf_size = GAP_DATA_BUF_SIZE;
    227       p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
    228       p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
    229       p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
    230     } else {
    231       p_ccb->ertm_info = *ertm_info;
    232     }
    233   }
    234 
    235   /* optional FCR channel modes */
    236   if (ertm_info != NULL) {
    237     p_ccb->ertm_info.allowed_modes =
    238         (chan_mode_mask) ? chan_mode_mask : (uint8_t)L2CAP_FCR_CHAN_OPT_BASIC;
    239   }
    240 
    241   if (is_server) {
    242     p_ccb->con_flags |=
    243         GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
    244     p_ccb->con_state = GAP_CCB_STATE_LISTENING;
    245     return (p_ccb->gap_handle);
    246   } else {
    247     /* We are the originator of this connection */
    248     p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
    249 
    250     /* Transition to the next appropriate state, waiting for connection confirm.
    251      */
    252     p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
    253 
    254     /* mark security done flag, when security is not required */
    255     if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE |
    256                      BTM_SEC_OUT_ENCRYPT)) == 0)
    257       p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
    258 
    259     /* Check if L2CAP started the connection process */
    260     if (p_rem_bda && (transport == BT_TRANSPORT_BR_EDR)) {
    261       cid = L2CA_CONNECT_REQ(p_ccb->psm, p_rem_bda, &p_ccb->ertm_info);
    262       if (cid != 0) {
    263         p_ccb->connection_id = cid;
    264         return (p_ccb->gap_handle);
    265       }
    266     }
    267 
    268     if (p_rem_bda && (transport == BT_TRANSPORT_LE)) {
    269       cid = L2CA_CONNECT_COC_REQ(p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
    270       if (cid != 0) {
    271         p_ccb->connection_id = cid;
    272         return (p_ccb->gap_handle);
    273       }
    274     }
    275 
    276     gap_release_ccb(p_ccb);
    277     return (GAP_INVALID_HANDLE);
    278   }
    279 }
    280 
    281 /*******************************************************************************
    282  *
    283  * Function         GAP_ConnClose
    284  *
    285  * Description      This function is called to close a connection.
    286  *
    287  * Parameters:      handle - Handle of the connection returned by GAP_ConnOpen
    288  *
    289  * Returns          BT_PASS             - closed OK
    290  *                  GAP_ERR_BAD_HANDLE  - invalid handle
    291  *
    292  ******************************************************************************/
    293 uint16_t GAP_ConnClose(uint16_t gap_handle) {
    294   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    295 
    296   GAP_TRACE_EVENT("GAP_CONN - close  handle: 0x%x", gap_handle);
    297 
    298   if (p_ccb) {
    299     /* Check if we have a connection ID */
    300     if (p_ccb->con_state != GAP_CCB_STATE_LISTENING)
    301       L2CA_DISCONNECT_REQ(p_ccb->connection_id);
    302 
    303     gap_release_ccb(p_ccb);
    304 
    305     return (BT_PASS);
    306   }
    307 
    308   return (GAP_ERR_BAD_HANDLE);
    309 }
    310 
    311 /*******************************************************************************
    312  *
    313  * Function         GAP_ConnReadData
    314  *
    315  * Description      Normally not GKI aware application will call this function
    316  *                  after receiving GAP_EVT_RXDATA event.
    317  *
    318  * Parameters:      handle      - Handle of the connection returned in the Open
    319  *                  p_data      - Data area
    320  *                  max_len     - Byte count requested
    321  *                  p_len       - Byte count received
    322  *
    323  * Returns          BT_PASS             - data read
    324  *                  GAP_ERR_BAD_HANDLE  - invalid handle
    325  *                  GAP_NO_DATA_AVAIL   - no data available
    326  *
    327  ******************************************************************************/
    328 uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data,
    329                           uint16_t max_len, uint16_t* p_len) {
    330   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    331   uint16_t copy_len;
    332 
    333   if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
    334 
    335   *p_len = 0;
    336 
    337   if (fixed_queue_is_empty(p_ccb->rx_queue)) return (GAP_NO_DATA_AVAIL);
    338 
    339   mutex_global_lock();
    340 
    341   while (max_len) {
    342     BT_HDR* p_buf =
    343         static_cast<BT_HDR*>(fixed_queue_try_peek_first(p_ccb->rx_queue));
    344     if (p_buf == NULL) break;
    345 
    346     copy_len = (p_buf->len > max_len) ? max_len : p_buf->len;
    347     max_len -= copy_len;
    348     *p_len += copy_len;
    349     if (p_data) {
    350       memcpy(p_data, (uint8_t*)(p_buf + 1) + p_buf->offset, copy_len);
    351       p_data += copy_len;
    352     }
    353 
    354     if (p_buf->len > copy_len) {
    355       p_buf->offset += copy_len;
    356       p_buf->len -= copy_len;
    357       break;
    358     }
    359     osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
    360   }
    361 
    362   p_ccb->rx_queue_size -= *p_len;
    363 
    364   mutex_global_unlock();
    365 
    366   GAP_TRACE_EVENT("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
    367                   p_ccb->rx_queue_size, *p_len);
    368 
    369   return (BT_PASS);
    370 }
    371 
    372 /*******************************************************************************
    373  *
    374  * Function         GAP_GetRxQueueCnt
    375  *
    376  * Description      This function return number of bytes on the rx queue.
    377  *
    378  * Parameters:      handle     - Handle returned in the GAP_ConnOpen
    379  *                  p_rx_queue_count - Pointer to return queue count in.
    380  *
    381  *
    382  ******************************************************************************/
    383 int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) {
    384   tGAP_CCB* p_ccb;
    385   int rc = BT_PASS;
    386 
    387   /* Check that handle is valid */
    388   if (handle < GAP_MAX_CONNECTIONS) {
    389     p_ccb = &gap_cb.conn.ccb_pool[handle];
    390 
    391     if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
    392       *p_rx_queue_count = p_ccb->rx_queue_size;
    393     } else
    394       rc = GAP_INVALID_HANDLE;
    395   } else
    396     rc = GAP_INVALID_HANDLE;
    397 
    398   GAP_TRACE_EVENT("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
    399                   *p_rx_queue_count);
    400 
    401   return (rc);
    402 }
    403 
    404 /*******************************************************************************
    405  *
    406  * Function         GAP_ConnBTRead
    407  *
    408  * Description      Bluetooth-aware applications will call this function after
    409  *                  receiving GAP_EVT_RXDATA event.
    410  *
    411  * Parameters:      handle      - Handle of the connection returned in the Open
    412  *                  pp_buf      - pointer to address of buffer with data,
    413  *
    414  * Returns          BT_PASS             - data read
    415  *                  GAP_ERR_BAD_HANDLE  - invalid handle
    416  *                  GAP_NO_DATA_AVAIL   - no data available
    417  *
    418  ******************************************************************************/
    419 uint16_t GAP_ConnBTRead(uint16_t gap_handle, BT_HDR** pp_buf) {
    420   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    421   BT_HDR* p_buf;
    422 
    423   if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
    424 
    425   p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rx_queue);
    426 
    427   if (p_buf) {
    428     *pp_buf = p_buf;
    429 
    430     p_ccb->rx_queue_size -= p_buf->len;
    431     return (BT_PASS);
    432   } else {
    433     *pp_buf = NULL;
    434     return (GAP_NO_DATA_AVAIL);
    435   }
    436 }
    437 
    438 /*******************************************************************************
    439  *
    440  * Function         GAP_ConnWriteData
    441  *
    442  * Description      Normally not GKI aware application will call this function
    443  *                  to send data to the connection.
    444  *
    445  * Parameters:      handle      - Handle of the connection returned in the Open
    446  *                  p_data      - Data area
    447  *                  max_len     - Byte count requested
    448  *                  p_len       - Byte count received
    449  *
    450  * Returns          BT_PASS                 - data read
    451  *                  GAP_ERR_BAD_HANDLE      - invalid handle
    452  *                  GAP_ERR_BAD_STATE       - connection not established
    453  *                  GAP_CONGESTION          - system is congested
    454  *
    455  ******************************************************************************/
    456 uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
    457                            uint16_t max_len, uint16_t* p_len) {
    458   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    459   BT_HDR* p_buf;
    460 
    461   *p_len = 0;
    462 
    463   if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
    464 
    465   if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) return (GAP_ERR_BAD_STATE);
    466 
    467   while (max_len) {
    468     if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
    469       p_buf = (BT_HDR*)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE);
    470     else
    471       p_buf = (BT_HDR*)osi_malloc(GAP_DATA_BUF_SIZE);
    472 
    473     p_buf->offset = L2CAP_MIN_OFFSET;
    474     p_buf->len =
    475         (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
    476     p_buf->event = BT_EVT_TO_BTU_SP_DATA;
    477 
    478     memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
    479 
    480     *p_len += p_buf->len;
    481     max_len -= p_buf->len;
    482     p_data += p_buf->len;
    483 
    484     GAP_TRACE_EVENT("GAP_WriteData %d bytes", p_buf->len);
    485 
    486     fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
    487   }
    488 
    489   if (p_ccb->is_congested) {
    490     return (BT_PASS);
    491   }
    492 
    493   /* Send the buffer through L2CAP */
    494   while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
    495     uint8_t status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
    496 
    497     if (status == L2CAP_DW_CONGESTED) {
    498       p_ccb->is_congested = true;
    499       break;
    500     } else if (status != L2CAP_DW_SUCCESS)
    501       return (GAP_ERR_BAD_STATE);
    502   }
    503 
    504   return (BT_PASS);
    505 }
    506 
    507 /*******************************************************************************
    508  *
    509  * Function         GAP_ConnReconfig
    510  *
    511  * Description      Applications can call this function to reconfigure the
    512  *                  connection.
    513  *
    514  * Parameters:      handle      - Handle of the connection
    515  *                  p_cfg       - Pointer to new configuration
    516  *
    517  * Returns          BT_PASS                 - config process started
    518  *                  GAP_ERR_BAD_HANDLE      - invalid handle
    519  *
    520  ******************************************************************************/
    521 uint16_t GAP_ConnReconfig(uint16_t gap_handle, tL2CAP_CFG_INFO* p_cfg) {
    522   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    523 
    524   if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
    525 
    526   p_ccb->cfg = *p_cfg;
    527 
    528   if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
    529     L2CA_CONFIG_REQ(p_ccb->connection_id, p_cfg);
    530 
    531   return (BT_PASS);
    532 }
    533 
    534 /*******************************************************************************
    535  *
    536  * Function         GAP_ConnSetIdleTimeout
    537  *
    538  * Description      Higher layers call this function to set the idle timeout for
    539  *                  a connection, or for all future connections. The "idle
    540  *                  timeout" is the amount of time that a connection can remain
    541  *                  up with no L2CAP channels on it. A timeout of zero means
    542  *                  that the connection will be torn down immediately when the
    543  *                  last channel is removed. A timeout of 0xFFFF means no
    544  *                  timeout. Values are in seconds.
    545  *
    546  * Parameters:      handle      - Handle of the connection
    547  *                  timeout     - in secs
    548  *                                0 = immediate disconnect when last channel is
    549  *                                    removed
    550  *                                0xFFFF = no idle timeout
    551  *
    552  * Returns          BT_PASS                 - config process started
    553  *                  GAP_ERR_BAD_HANDLE      - invalid handle
    554  *
    555  ******************************************************************************/
    556 uint16_t GAP_ConnSetIdleTimeout(uint16_t gap_handle, uint16_t timeout) {
    557   tGAP_CCB* p_ccb;
    558 
    559   p_ccb = gap_find_ccb_by_handle(gap_handle);
    560   if (p_ccb == NULL) return (GAP_ERR_BAD_HANDLE);
    561 
    562   if (L2CA_SetIdleTimeout(p_ccb->connection_id, timeout, false))
    563     return (BT_PASS);
    564   else
    565     return (GAP_ERR_BAD_HANDLE);
    566 }
    567 
    568 /*******************************************************************************
    569  *
    570  * Function         GAP_ConnGetRemoteAddr
    571  *
    572  * Description      This function is called to get the remote BD address
    573  *                  of a connection.
    574  *
    575  * Parameters:      handle - Handle of the connection returned by GAP_ConnOpen
    576  *
    577  * Returns          BT_PASS             - closed OK
    578  *                  GAP_ERR_BAD_HANDLE  - invalid handle
    579  *
    580  ******************************************************************************/
    581 uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle) {
    582   tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
    583 
    584   GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
    585 
    586   if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) {
    587     GAP_TRACE_EVENT(
    588         "GAP_ConnGetRemoteAddr bda "
    589         ":0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
    590         p_ccb->rem_dev_address[0], p_ccb->rem_dev_address[1],
    591         p_ccb->rem_dev_address[2], p_ccb->rem_dev_address[3],
    592         p_ccb->rem_dev_address[4], p_ccb->rem_dev_address[5]);
    593     return (p_ccb->rem_dev_address);
    594   } else {
    595     GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr return Error ");
    596     return (NULL);
    597   }
    598 }
    599 
    600 /*******************************************************************************
    601  *
    602  * Function         GAP_ConnGetRemMtuSize
    603  *
    604  * Description      Returns the remote device's MTU size
    605  *
    606  * Parameters:      handle      - Handle of the connection
    607  *
    608  * Returns          uint16_t    - maximum size buffer that can be transmitted to
    609  *                                the peer
    610  *
    611  ******************************************************************************/
    612 uint16_t GAP_ConnGetRemMtuSize(uint16_t gap_handle) {
    613   tGAP_CCB* p_ccb;
    614 
    615   p_ccb = gap_find_ccb_by_handle(gap_handle);
    616   if (p_ccb == NULL) return (0);
    617 
    618   return (p_ccb->rem_mtu_size);
    619 }
    620 
    621 /*******************************************************************************
    622  *
    623  * Function         GAP_ConnGetL2CAPCid
    624  *
    625  * Description      Returns the L2CAP channel id
    626  *
    627  * Parameters:      handle      - Handle of the connection
    628  *
    629  * Returns          uint16_t    - The L2CAP channel id
    630  *                  0, if error
    631  *
    632  ******************************************************************************/
    633 uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) {
    634   tGAP_CCB* p_ccb;
    635 
    636   p_ccb = gap_find_ccb_by_handle(gap_handle);
    637   if (p_ccb == NULL) return (0);
    638 
    639   return (p_ccb->connection_id);
    640 }
    641 
    642 /*******************************************************************************
    643  *
    644  * Function         gap_tx_connect_ind
    645  *
    646  * Description      Sends out GAP_EVT_TX_EMPTY when transmission has been
    647  *                  completed.
    648  *
    649  * Returns          void
    650  *
    651  ******************************************************************************/
    652 void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) {
    653   tGAP_CCB* p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    654   if (p_ccb == NULL) return;
    655 
    656   if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) {
    657     GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
    658     p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
    659   }
    660 }
    661 
    662 /*******************************************************************************
    663  *
    664  * Function         gap_connect_ind
    665  *
    666  * Description      This function handles an inbound connection indication
    667  *                  from L2CAP. This is the case where we are acting as a
    668  *                  server.
    669  *
    670  * Returns          void
    671  *
    672  ******************************************************************************/
    673 static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
    674                             uint8_t l2cap_id) {
    675   uint16_t xx;
    676   tGAP_CCB* p_ccb;
    677 
    678   /* See if we have a CCB listening for the connection */
    679   for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
    680        xx++, p_ccb++) {
    681     if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) && (p_ccb->psm == psm) &&
    682         ((p_ccb->rem_addr_specified == false) ||
    683          (!memcmp(bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN))))
    684       break;
    685   }
    686 
    687   if (xx == GAP_MAX_CONNECTIONS) {
    688     GAP_TRACE_WARNING("*******");
    689     GAP_TRACE_WARNING(
    690         "WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
    691     GAP_TRACE_WARNING("*******");
    692 
    693     /* Disconnect because it is an unexpected connection */
    694     L2CA_DISCONNECT_REQ(l2cap_cid);
    695     return;
    696   }
    697 
    698   /* Transition to the next appropriate state, waiting for config setup. */
    699   if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
    700     p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
    701 
    702   /* Save the BD Address and Channel ID. */
    703   memcpy(&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
    704   p_ccb->connection_id = l2cap_cid;
    705 
    706   /* Send response to the L2CAP layer. */
    707   if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
    708     L2CA_CONNECT_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK,
    709                      &p_ccb->ertm_info);
    710 
    711   if (p_ccb->transport == BT_TRANSPORT_LE) {
    712     L2CA_CONNECT_COC_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK,
    713                          L2CAP_CONN_OK, &p_ccb->local_coc_cfg);
    714 
    715     /* get the remote coc configuration */
    716     L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
    717     p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
    718 
    719     /* configuration is not required for LE COC */
    720     p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
    721     p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
    722     gap_checks_con_flags(p_ccb);
    723   }
    724 
    725   GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
    726                   p_ccb->connection_id);
    727 
    728   /* Send a Configuration Request. */
    729   if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
    730     L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
    731 }
    732 
    733 /*******************************************************************************
    734  *
    735  * Function         gap_checks_con_flags
    736  *
    737  * Description      This function processes the L2CAP configuration indication
    738  *                  event.
    739  *
    740  * Returns          void
    741  *
    742  ******************************************************************************/
    743 static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
    744   GAP_TRACE_EVENT("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
    745   /* if all the required con_flags are set, report the OPEN event now */
    746   if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
    747     p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
    748 
    749     p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
    750   }
    751 }
    752 
    753 /*******************************************************************************
    754  *
    755  * Function         gap_sec_check_complete
    756  *
    757  * Description      The function called when Security Manager finishes
    758  *                  verification of the service side connection
    759  *
    760  * Returns          void
    761  *
    762  ******************************************************************************/
    763 static void gap_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
    764                                    UNUSED_ATTR tBT_TRANSPORT transport,
    765                                    void* p_ref_data, uint8_t res) {
    766   tGAP_CCB* p_ccb = (tGAP_CCB*)p_ref_data;
    767 
    768   GAP_TRACE_EVENT(
    769       "gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
    770       p_ccb->con_state, p_ccb->con_flags, res);
    771   if (p_ccb->con_state == GAP_CCB_STATE_IDLE) return;
    772 
    773   if (res == BTM_SUCCESS) {
    774     p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
    775     gap_checks_con_flags(p_ccb);
    776   } else {
    777     /* security failed - disconnect the channel */
    778     L2CA_DISCONNECT_REQ(p_ccb->connection_id);
    779   }
    780 }
    781 
    782 /*******************************************************************************
    783  *
    784  * Function         gap_connect_cfm
    785  *
    786  * Description      This function handles the connect confirm events
    787  *                  from L2CAP. This is the case when we are acting as a
    788  *                  client and have sent a connect request.
    789  *
    790  * Returns          void
    791  *
    792  ******************************************************************************/
    793 static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
    794   tGAP_CCB* p_ccb;
    795 
    796   /* Find CCB based on CID */
    797   p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    798   if (p_ccb == NULL) return;
    799 
    800   /* initiate security process, if needed */
    801   if ((p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0 &&
    802       p_ccb->transport != BT_TRANSPORT_LE) {
    803     btm_sec_mx_access_request(p_ccb->rem_dev_address, p_ccb->psm, true, 0, 0,
    804                               &gap_sec_check_complete, p_ccb);
    805   }
    806 
    807   /* If the connection response contains success status, then */
    808   /* Transition to the next state and startup the timer.      */
    809   if ((result == L2CAP_CONN_OK) &&
    810       (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) {
    811     if (p_ccb->transport == BT_TRANSPORT_BR_EDR) {
    812       p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
    813 
    814       /* Send a Configuration Request. */
    815       L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
    816     }
    817 
    818     if (p_ccb->transport == BT_TRANSPORT_LE) {
    819       /* get the remote coc configuration */
    820       L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
    821       p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
    822 
    823       /* configuration is not required for LE COC */
    824       p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
    825       p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
    826       p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
    827       gap_checks_con_flags(p_ccb);
    828     }
    829   } else {
    830     /* Tell the user if he has a callback */
    831     if (p_ccb->p_callback)
    832       (*p_ccb->p_callback)(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
    833 
    834     gap_release_ccb(p_ccb);
    835   }
    836 }
    837 
    838 /*******************************************************************************
    839  *
    840  * Function         gap_config_ind
    841  *
    842  * Description      This function processes the L2CAP configuration indication
    843  *                  event.
    844  *
    845  * Returns          void
    846  *
    847  ******************************************************************************/
    848 static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
    849   tGAP_CCB* p_ccb;
    850   uint16_t local_mtu_size;
    851 
    852   /* Find CCB based on CID */
    853   p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    854   if (p_ccb == NULL) return;
    855 
    856   /* Remember the remote MTU size */
    857 
    858   if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
    859     local_mtu_size =
    860         p_ccb->ertm_info.user_tx_buf_size - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
    861   } else
    862     local_mtu_size = L2CAP_MTU_SIZE;
    863 
    864   if ((!p_cfg->mtu_present) || (p_cfg->mtu > local_mtu_size)) {
    865     p_ccb->rem_mtu_size = local_mtu_size;
    866   } else
    867     p_ccb->rem_mtu_size = p_cfg->mtu;
    868 
    869   /* For now, always accept configuration from the other side */
    870   p_cfg->flush_to_present = false;
    871   p_cfg->mtu_present = false;
    872   p_cfg->result = L2CAP_CFG_OK;
    873   p_cfg->fcs_present = false;
    874 
    875   L2CA_CONFIG_RSP(l2cap_cid, p_cfg);
    876 
    877   p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
    878 
    879   gap_checks_con_flags(p_ccb);
    880 }
    881 
    882 /*******************************************************************************
    883  *
    884  * Function         gap_config_cfm
    885  *
    886  * Description      This function processes the L2CAP configuration confirmation
    887  *                  event.
    888  *
    889  * Returns          void
    890  *
    891  ******************************************************************************/
    892 static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
    893   tGAP_CCB* p_ccb;
    894 
    895   /* Find CCB based on CID */
    896   p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    897   if (p_ccb == NULL) return;
    898 
    899   if (p_cfg->result == L2CAP_CFG_OK) {
    900     p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
    901 
    902     if (p_ccb->cfg.fcr_present)
    903       p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
    904     else
    905       p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
    906 
    907     gap_checks_con_flags(p_ccb);
    908   } else {
    909     p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
    910     gap_release_ccb(p_ccb);
    911   }
    912 }
    913 
    914 /*******************************************************************************
    915  *
    916  * Function         gap_disconnect_ind
    917  *
    918  * Description      This function handles a disconnect event from L2CAP. If
    919  *                  requested to, we ack the disconnect before dropping the CCB
    920  *
    921  * Returns          void
    922  *
    923  ******************************************************************************/
    924 static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
    925   tGAP_CCB* p_ccb;
    926 
    927   GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
    928 
    929   /* Find CCB based on CID */
    930   p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    931   if (p_ccb == NULL) return;
    932 
    933   if (ack_needed) L2CA_DISCONNECT_RSP(l2cap_cid);
    934 
    935   p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
    936   gap_release_ccb(p_ccb);
    937 }
    938 
    939 /*******************************************************************************
    940  *
    941  * Function         gap_data_ind
    942  *
    943  * Description      This function is called when data is received from L2CAP.
    944  *
    945  * Returns          void
    946  *
    947  ******************************************************************************/
    948 static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
    949   tGAP_CCB* p_ccb;
    950 
    951   /* Find CCB based on CID */
    952   p_ccb = gap_find_ccb_by_cid(l2cap_cid);
    953   if (p_ccb == NULL) {
    954     osi_free(p_msg);
    955     return;
    956   }
    957 
    958   if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
    959     fixed_queue_enqueue(p_ccb->rx_queue, p_msg);
    960 
    961     p_ccb->rx_queue_size += p_msg->len;
    962     /*
    963     GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
    964                                    p_ccb->rx_queue_size, p_msg->len);
    965      */
    966 
    967     p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
    968   } else {
    969     osi_free(p_msg);
    970   }
    971 }
    972 
    973 /*******************************************************************************
    974  *
    975  * Function         gap_congestion_ind
    976  *
    977  * Description      This is a callback function called by L2CAP when
    978  *                  data L2CAP congestion status changes
    979  *
    980  ******************************************************************************/
    981 static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
    982   tGAP_CCB* p_ccb;
    983   uint16_t event;
    984   BT_HDR* p_buf;
    985   uint8_t status;
    986 
    987   GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
    988                   is_congested, lcid);
    989 
    990   /* Find CCB based on CID */
    991   p_ccb = gap_find_ccb_by_cid(lcid);
    992   if (p_ccb == NULL) return;
    993 
    994   p_ccb->is_congested = is_congested;
    995 
    996   event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
    997   p_ccb->p_callback(p_ccb->gap_handle, event);
    998 
    999   if (!is_congested) {
   1000     while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) !=
   1001            NULL) {
   1002       status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
   1003 
   1004       if (status == L2CAP_DW_CONGESTED) {
   1005         p_ccb->is_congested = true;
   1006         break;
   1007       } else if (status != L2CAP_DW_SUCCESS)
   1008         break;
   1009     }
   1010   }
   1011 }
   1012 
   1013 /*******************************************************************************
   1014  *
   1015  * Function         gap_find_ccb_by_cid
   1016  *
   1017  * Description      This function searches the CCB table for an entry with the
   1018  *                  passed CID.
   1019  *
   1020  * Returns          the CCB address, or NULL if not found.
   1021  *
   1022  ******************************************************************************/
   1023 static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
   1024   uint16_t xx;
   1025   tGAP_CCB* p_ccb;
   1026 
   1027   /* Look through each connection control block */
   1028   for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
   1029        xx++, p_ccb++) {
   1030     if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) &&
   1031         (p_ccb->connection_id == cid))
   1032       return (p_ccb);
   1033   }
   1034 
   1035   /* If here, not found */
   1036   return (NULL);
   1037 }
   1038 
   1039 /*******************************************************************************
   1040  *
   1041  * Function         gap_find_ccb_by_handle
   1042  *
   1043  * Description      This function searches the CCB table for an entry with the
   1044  *                  passed handle.
   1045  *
   1046  * Returns          the CCB address, or NULL if not found.
   1047  *
   1048  ******************************************************************************/
   1049 static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle) {
   1050   tGAP_CCB* p_ccb;
   1051 
   1052   /* Check that handle is valid */
   1053   if (handle < GAP_MAX_CONNECTIONS) {
   1054     p_ccb = &gap_cb.conn.ccb_pool[handle];
   1055 
   1056     if (p_ccb->con_state != GAP_CCB_STATE_IDLE) return (p_ccb);
   1057   }
   1058 
   1059   /* If here, handle points to invalid connection */
   1060   return (NULL);
   1061 }
   1062 
   1063 /*******************************************************************************
   1064  *
   1065  * Function         gap_allocate_ccb
   1066  *
   1067  * Description      This function allocates a new CCB.
   1068  *
   1069  * Returns          CCB address, or NULL if none available.
   1070  *
   1071  ******************************************************************************/
   1072 static tGAP_CCB* gap_allocate_ccb(void) {
   1073   uint16_t xx;
   1074   tGAP_CCB* p_ccb;
   1075 
   1076   /* Look through each connection control block for a free one */
   1077   for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
   1078        xx++, p_ccb++) {
   1079     if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
   1080       memset(p_ccb, 0, sizeof(tGAP_CCB));
   1081       p_ccb->tx_queue = fixed_queue_new(SIZE_MAX);
   1082       p_ccb->rx_queue = fixed_queue_new(SIZE_MAX);
   1083 
   1084       p_ccb->gap_handle = xx;
   1085       p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
   1086 
   1087       return (p_ccb);
   1088     }
   1089   }
   1090 
   1091   /* If here, no free CCB found */
   1092   return (NULL);
   1093 }
   1094 
   1095 /*******************************************************************************
   1096  *
   1097  * Function         gap_release_ccb
   1098  *
   1099  * Description      This function releases a CCB.
   1100  *
   1101  * Returns          void
   1102  *
   1103  ******************************************************************************/
   1104 static void gap_release_ccb(tGAP_CCB* p_ccb) {
   1105   /* Drop any buffers we may be holding */
   1106   p_ccb->rx_queue_size = 0;
   1107 
   1108   while (!fixed_queue_is_empty(p_ccb->rx_queue))
   1109     osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
   1110   fixed_queue_free(p_ccb->rx_queue, NULL);
   1111   p_ccb->rx_queue = NULL;
   1112 
   1113   while (!fixed_queue_is_empty(p_ccb->tx_queue))
   1114     osi_free(fixed_queue_try_dequeue(p_ccb->tx_queue));
   1115   fixed_queue_free(p_ccb->tx_queue, NULL);
   1116   p_ccb->tx_queue = NULL;
   1117 
   1118   p_ccb->con_state = GAP_CCB_STATE_IDLE;
   1119 
   1120   /* If no-one else is using the PSM, deregister from L2CAP */
   1121   tGAP_CCB* p_ccb_local = gap_cb.conn.ccb_pool;
   1122   for (uint16_t i = 0; i < GAP_MAX_CONNECTIONS; i++, p_ccb_local++) {
   1123     if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) &&
   1124         (p_ccb_local->psm == p_ccb->psm)) {
   1125       GAP_TRACE_EVENT("%s :%d PSM is still in use, do not deregister",
   1126                       __func__, p_ccb_local->psm);
   1127       return;
   1128     }
   1129   }
   1130 
   1131   /* Free the security record for this PSM */
   1132   BTM_SecClrService(p_ccb->service_id);
   1133   if (p_ccb->transport == BT_TRANSPORT_BR_EDR) L2CA_DEREGISTER(p_ccb->psm);
   1134   if (p_ccb->transport == BT_TRANSPORT_LE) L2CA_DEREGISTER_COC(p_ccb->psm);
   1135 }
   1136 
   1137 #endif /* GAP_CONN_INCLUDED */
   1138