Home | History | Annotate | Download | only in sdp
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 1999-2012 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 /******************************************************************************
     20  *
     21  *  This file contains the main SDP functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <stdio.h>
     28 
     29 #include "bt_target.h"
     30 #include "bt_utils.h"
     31 #include "gki.h"
     32 #include "l2cdefs.h"
     33 #include "hcidefs.h"
     34 #include "hcimsgs.h"
     35 
     36 #include "l2c_api.h"
     37 #include "l2cdefs.h"
     38 
     39 #include "btu.h"
     40 #include "btm_api.h"
     41 
     42 #include "sdp_api.h"
     43 #include "sdpint.h"
     44 
     45 
     46 /********************************************************************************/
     47 /*                       G L O B A L      S D P       D A T A                   */
     48 /********************************************************************************/
     49 #if SDP_DYNAMIC_MEMORY == FALSE
     50 tSDP_CB  sdp_cb;
     51 #endif
     52 
     53 /********************************************************************************/
     54 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     55 /********************************************************************************/
     56 static void sdp_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm,
     57                              UINT8 l2cap_id);
     58 static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     59 static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     60 static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
     61 static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
     62 
     63 #if SDP_CLIENT_ENABLED == TRUE
     64 static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result);
     65 static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
     66 #else
     67 #define sdp_connect_cfm     NULL
     68 #define sdp_disconnect_cfm  NULL
     69 #endif
     70 
     71 
     72 /*******************************************************************************
     73 **
     74 ** Function         sdp_init
     75 **
     76 ** Description      This function initializes the SDP unit.
     77 **
     78 ** Returns          void
     79 **
     80 *******************************************************************************/
     81 void sdp_init (void)
     82 {
     83     /* Clears all structures and local SDP database (if Server is enabled) */
     84     memset (&sdp_cb, 0, sizeof (tSDP_CB));
     85 
     86     /* Initialize the L2CAP configuration. We only care about MTU and flush */
     87     sdp_cb.l2cap_my_cfg.mtu_present       = TRUE;
     88     sdp_cb.l2cap_my_cfg.mtu               = SDP_MTU_SIZE;
     89     sdp_cb.l2cap_my_cfg.flush_to_present  = TRUE;
     90     sdp_cb.l2cap_my_cfg.flush_to          = SDP_FLUSH_TO;
     91 
     92     sdp_cb.max_attr_list_size             = SDP_MTU_SIZE - 16;
     93     sdp_cb.max_recs_per_search            = SDP_MAX_DISC_SERVER_RECS;
     94 
     95 #if SDP_SERVER_ENABLED == TRUE
     96     /* Register with Security Manager for the specific security level */
     97     if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
     98                                SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
     99     {
    100         SDP_TRACE_ERROR ("Security Registration Server failed");
    101         return;
    102     }
    103 #endif
    104 
    105 #if SDP_CLIENT_ENABLED == TRUE
    106     /* Register with Security Manager for the specific security level */
    107     if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
    108                                SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
    109     {
    110         SDP_TRACE_ERROR ("Security Registration for Client failed");
    111         return;
    112     }
    113 #endif
    114 
    115 #if defined(SDP_INITIAL_TRACE_LEVEL)
    116     sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
    117 #else
    118     sdp_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
    119 #endif
    120 
    121     sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
    122     sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
    123     sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
    124     sdp_cb.reg_info.pL2CA_ConfigInd_Cb  = sdp_config_ind;
    125     sdp_cb.reg_info.pL2CA_ConfigCfm_Cb  = sdp_config_cfm;
    126     sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
    127     sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
    128     sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
    129     sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
    130     sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
    131     sdp_cb.reg_info.pL2CA_TxComplete_Cb       = NULL;
    132 
    133     /* Now, register with L2CAP */
    134     if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
    135     {
    136         SDP_TRACE_ERROR ("SDP Registration failed");
    137     }
    138 }
    139 
    140 #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    141 /*******************************************************************************
    142 **
    143 ** Function         sdp_set_max_attr_list_size
    144 **
    145 ** Description      This function sets the max attribute list size to use
    146 **
    147 ** Returns          void
    148 **
    149 *******************************************************************************/
    150 UINT16 sdp_set_max_attr_list_size (UINT16 max_size)
    151 {
    152     if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
    153         max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
    154 
    155     sdp_cb.max_attr_list_size  = max_size;
    156 
    157     return sdp_cb.max_attr_list_size;
    158 }
    159 #endif
    160 
    161 /*******************************************************************************
    162 **
    163 ** Function         sdp_connect_ind
    164 **
    165 ** Description      This function handles an inbound connection indication
    166 **                  from L2CAP. This is the case where we are acting as a
    167 **                  server.
    168 **
    169 ** Returns          void
    170 **
    171 *******************************************************************************/
    172 static void sdp_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
    173 {
    174     UNUSED(psm);
    175 #if SDP_SERVER_ENABLED == TRUE
    176     tCONN_CB    *p_ccb;
    177 
    178     /* Allocate a new CCB. Return if none available. */
    179     if ((p_ccb = sdpu_allocate_ccb()) == NULL)
    180         return;
    181 
    182     /* Transition to the next appropriate state, waiting for config setup. */
    183     p_ccb->con_state = SDP_STATE_CFG_SETUP;
    184 
    185     /* Save the BD Address and Channel ID. */
    186     memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
    187     p_ccb->connection_id = l2cap_cid;
    188 
    189     /* Send response to the L2CAP layer. */
    190     L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
    191     {
    192         tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
    193 
    194         if (cfg.fcr_present)
    195         {
    196             SDP_TRACE_DEBUG("sdp_connect_ind:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
    197                         cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
    198                         cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
    199         }
    200 
    201         if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
    202              && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
    203         {
    204             /* FCR not desired; try again in basic mode */
    205             cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
    206             cfg.fcr_present = FALSE;
    207             L2CA_ConfigReq (l2cap_cid, &cfg);
    208         }
    209     }
    210 
    211     SDP_TRACE_EVENT ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
    212 #else   /* No server */
    213     /* Reject the connection */
    214     L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
    215 #endif
    216 }
    217 
    218 #if SDP_CLIENT_ENABLED == TRUE
    219 /*******************************************************************************
    220 **
    221 ** Function         sdp_connect_cfm
    222 **
    223 ** Description      This function handles the connect confirm events
    224 **                  from L2CAP. This is the case when we are acting as a
    225 **                  client and have sent a connect request.
    226 **
    227 ** Returns          void
    228 **
    229 *******************************************************************************/
    230 static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result)
    231 {
    232     tCONN_CB    *p_ccb;
    233     tL2CAP_CFG_INFO cfg;
    234 
    235     /* Find CCB based on CID */
    236     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    237     {
    238         SDP_TRACE_WARNING ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
    239         return;
    240     }
    241 
    242     /* If the connection response contains success status, then */
    243     /* Transition to the next state and startup the timer.      */
    244     if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
    245     {
    246         p_ccb->con_state = SDP_STATE_CFG_SETUP;
    247 
    248         cfg = sdp_cb.l2cap_my_cfg;
    249 
    250         if (cfg.fcr_present)
    251         {
    252             SDP_TRACE_DEBUG("sdp_connect_cfm:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
    253                         cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
    254                         cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
    255         }
    256 
    257         if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
    258              && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
    259         {
    260             /* FCR not desired; try again in basic mode */
    261             cfg.fcr_present = FALSE;
    262             cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
    263             L2CA_ConfigReq (l2cap_cid, &cfg);
    264         }
    265 
    266         SDP_TRACE_EVENT ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
    267     }
    268     else
    269     {
    270         SDP_TRACE_WARNING ("SDP - Rcvd conn cnf with error: 0x%x  CID 0x%x", result, p_ccb->connection_id);
    271 
    272         /* Tell the user if he has a callback */
    273         if (p_ccb->p_cb || p_ccb->p_cb2)
    274         {
    275             UINT16 err = -1;
    276             if ((result == HCI_ERR_HOST_REJECT_SECURITY)
    277              || (result == HCI_ERR_AUTH_FAILURE)
    278              || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
    279              || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
    280              || (result == HCI_ERR_KEY_MISSING))
    281                 err = SDP_SECURITY_ERR;
    282             else if (result == HCI_ERR_HOST_REJECT_DEVICE)
    283                 err = SDP_CONN_REJECTED;
    284             else
    285                 err = SDP_CONN_FAILED;
    286             if(p_ccb->p_cb)
    287                 (*p_ccb->p_cb)(err);
    288             else if(p_ccb->p_cb2)
    289                 (*p_ccb->p_cb2)(err, p_ccb->user_data);
    290 
    291         }
    292         sdpu_release_ccb (p_ccb);
    293     }
    294 }
    295 #endif  /* SDP_CLIENT_ENABLED == TRUE */
    296 
    297 
    298 /*******************************************************************************
    299 **
    300 ** Function         sdp_config_ind
    301 **
    302 ** Description      This function processes the L2CAP configuration indication
    303 **                  event.
    304 **
    305 ** Returns          void
    306 **
    307 *******************************************************************************/
    308 static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    309 {
    310     tCONN_CB    *p_ccb;
    311 
    312     /* Find CCB based on CID */
    313     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    314     {
    315         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    316         return;
    317     }
    318 
    319     /* Remember the remote MTU size */
    320     if (!p_cfg->mtu_present)
    321     {
    322         /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
    323         p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
    324     }
    325     else
    326     {
    327         if (p_cfg->mtu > SDP_MTU_SIZE)
    328             p_ccb->rem_mtu_size = SDP_MTU_SIZE;
    329         else
    330             p_ccb->rem_mtu_size = p_cfg->mtu;
    331     }
    332 
    333     /* For now, always accept configuration from the other side */
    334     p_cfg->flush_to_present = FALSE;
    335     p_cfg->mtu_present      = FALSE;
    336     p_cfg->result           = L2CAP_CFG_OK;
    337 
    338     /* Check peer config request against our rfcomm configuration */
    339     if (p_cfg->fcr_present)
    340     {
    341         /* Reject the window size if it is bigger than we want it to be */
    342         if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
    343         {
    344             if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
    345                 && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
    346             {
    347                 p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
    348                 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    349                 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
    350             }
    351 
    352             /* Reject if locally we want basic and they don't */
    353             if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
    354             {
    355                 /* Ask for a new setup */
    356                 p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
    357                 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    358                 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
    359             }
    360             /* Remain in configure state and give the peer our desired configuration */
    361             if (p_cfg->result != L2CAP_CFG_OK)
    362             {
    363                 SDP_TRACE_WARNING ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
    364                 L2CA_ConfigRsp (l2cap_cid, p_cfg);
    365                 return;
    366             }
    367         }
    368         else    /* We agree with peer's request */
    369             p_cfg->fcr_present = FALSE;
    370     }
    371 
    372     L2CA_ConfigRsp (l2cap_cid, p_cfg);
    373 
    374     SDP_TRACE_EVENT ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
    375 
    376     p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
    377 
    378     if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
    379     {
    380         p_ccb->con_state = SDP_STATE_CONNECTED;
    381 
    382         if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
    383             sdp_disc_connected (p_ccb);
    384         else
    385             /* Start inactivity timer */
    386             btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
    387     }
    388 
    389 }
    390 
    391 
    392 /*******************************************************************************
    393 **
    394 ** Function         sdp_config_cfm
    395 **
    396 ** Description      This function processes the L2CAP configuration confirmation
    397 **                  event.
    398 **
    399 ** Returns          void
    400 **
    401 *******************************************************************************/
    402 static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    403 {
    404     tCONN_CB    *p_ccb;
    405 
    406     SDP_TRACE_EVENT ("SDP - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
    407 
    408     /* Find CCB based on CID */
    409     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    410     {
    411         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    412         return;
    413     }
    414 
    415     /* For now, always accept configuration from the other side */
    416     if (p_cfg->result == L2CAP_CFG_OK)
    417     {
    418         p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
    419 
    420         if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
    421         {
    422             p_ccb->con_state = SDP_STATE_CONNECTED;
    423 
    424             if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
    425                 sdp_disc_connected (p_ccb);
    426             else
    427                 /* Start inactivity timer */
    428                 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
    429         }
    430     }
    431     else
    432     {
    433         /* If peer has rejected FCR and suggested basic then try basic */
    434         if (p_cfg->fcr_present)
    435         {
    436             tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
    437             cfg.fcr_present = FALSE;
    438             L2CA_ConfigReq (l2cap_cid, &cfg);
    439 
    440             /* Remain in configure state */
    441             return;
    442         }
    443 
    444 #if SDP_CLIENT_ENABLED == TRUE
    445         sdp_disconnect(p_ccb, SDP_CFG_FAILED);
    446 #endif
    447     }
    448 }
    449 
    450 /*******************************************************************************
    451 **
    452 ** Function         sdp_disconnect_ind
    453 **
    454 ** Description      This function handles a disconnect event from L2CAP. If
    455 **                  requested to, we ack the disconnect before dropping the CCB
    456 **
    457 ** Returns          void
    458 **
    459 *******************************************************************************/
    460 static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
    461 {
    462     tCONN_CB    *p_ccb;
    463 
    464     /* Find CCB based on CID */
    465     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    466     {
    467         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
    468         return;
    469     }
    470 
    471     if (ack_needed)
    472         L2CA_DisconnectRsp (l2cap_cid);
    473 
    474     SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
    475 #if SDP_CLIENT_ENABLED == TRUE
    476     /* Tell the user if he has a callback */
    477     if (p_ccb->p_cb)
    478         (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
    479                         SDP_SUCCESS : SDP_CONN_FAILED));
    480     else if (p_ccb->p_cb2)
    481         (*p_ccb->p_cb2) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
    482                         SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data);
    483 
    484 #endif
    485     sdpu_release_ccb (p_ccb);
    486 }
    487 
    488 /*******************************************************************************
    489 **
    490 ** Function         sdp_data_ind
    491 **
    492 ** Description      This function is called when data is received from L2CAP.
    493 **                  if we are the originator of the connection, we are the SDP
    494 **                  client, and the received message is queued up for the client.
    495 **
    496 **                  If we are the destination of the connection, we are the SDP
    497 **                  server, so the message is passed to the server processing
    498 **                  function.
    499 **
    500 ** Returns          void
    501 **
    502 *******************************************************************************/
    503 static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
    504 {
    505     tCONN_CB    *p_ccb;
    506 
    507     /* Find CCB based on CID */
    508     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
    509     {
    510         if (p_ccb->con_state == SDP_STATE_CONNECTED)
    511         {
    512             if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
    513                 sdp_disc_server_rsp (p_ccb, p_msg);
    514             else
    515                 sdp_server_handle_client_req (p_ccb, p_msg);
    516         }
    517         else
    518         {
    519             SDP_TRACE_WARNING ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
    520                                 p_ccb->con_state, l2cap_cid);
    521         }
    522     }
    523     else
    524     {
    525         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
    526     }
    527 
    528     GKI_freebuf (p_msg);
    529 }
    530 
    531 
    532 #if SDP_CLIENT_ENABLED == TRUE
    533 /*******************************************************************************
    534 **
    535 ** Function         sdp_conn_originate
    536 **
    537 ** Description      This function is called from the API to originate a
    538 **                  connection.
    539 **
    540 ** Returns          void
    541 **
    542 *******************************************************************************/
    543 tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr)
    544 {
    545     tCONN_CB              *p_ccb;
    546     UINT16                cid;
    547 
    548     /* Allocate a new CCB. Return if none available. */
    549     if ((p_ccb = sdpu_allocate_ccb()) == NULL)
    550     {
    551         SDP_TRACE_WARNING ("SDP - no spare CCB for orig");
    552         return (NULL);
    553     }
    554 
    555     SDP_TRACE_EVENT ("SDP - Originate started");
    556 
    557     /* We are the originator of this connection */
    558     p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
    559 
    560     /* Save the BD Address and Channel ID. */
    561     memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
    562 
    563     /* Transition to the next appropriate state, waiting for connection confirm. */
    564     p_ccb->con_state = SDP_STATE_CONN_SETUP;
    565 
    566 // btla-specific ++
    567 #ifndef ANDROID_APP_INCLUDED  /* Skip for Android: Do not need to set out_service for sdp, since sdp does not use sec. Prevents over-writing service_rec of a connection already in progress */
    568     BTM_SetOutService(p_bd_addr, BTM_SEC_SERVICE_SDP_SERVER, 0);
    569 #endif
    570 // btla-specific --
    571 
    572     cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr);
    573 
    574     /* Check if L2CAP started the connection process */
    575     if (cid != 0)
    576     {
    577         p_ccb->connection_id = cid;
    578 
    579         return (p_ccb);
    580     }
    581     else
    582     {
    583         SDP_TRACE_WARNING ("SDP - Originate failed");
    584         sdpu_release_ccb (p_ccb);
    585         return (NULL);
    586     }
    587 }
    588 
    589 /*******************************************************************************
    590 **
    591 ** Function         sdp_disconnect
    592 **
    593 ** Description      This function disconnects a connection.
    594 **
    595 ** Returns          void
    596 **
    597 *******************************************************************************/
    598 void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason)
    599 {
    600 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
    601 
    602     /* If we are browsing for multiple UUIDs ... */
    603     if ((p_ccb->con_state == SDP_STATE_CONNECTED)
    604      && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
    605      && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH)))
    606     {
    607         /* If the browse found something, do no more searching */
    608         if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
    609             p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
    610 
    611         while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters)
    612         {
    613             /* Check we have not already found the UUID (maybe through browse) */
    614             if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2)
    615                 && (SDP_FindServiceInDb (p_ccb->p_db,
    616                         p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16,
    617                         NULL)))
    618                 continue;
    619 
    620             if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2)
    621                 && (SDP_FindServiceUUIDInDb (p_ccb->p_db,
    622                         &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL)))
    623                 continue;
    624 
    625             p_ccb->cur_handle = 0;
    626 
    627             SDP_TRACE_EVENT ("SDP - looking for for more,  CID: 0x%x",
    628                               p_ccb->connection_id);
    629 
    630             sdp_disc_connected (p_ccb);
    631             return;
    632         }
    633     }
    634 
    635     if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
    636         reason = SDP_SUCCESS;
    637 
    638 #endif
    639 
    640     SDP_TRACE_EVENT ("SDP - disconnect  CID: 0x%x", p_ccb->connection_id);
    641 
    642     /* Check if we have a connection ID */
    643     if (p_ccb->connection_id != 0)
    644     {
    645         L2CA_DisconnectReq (p_ccb->connection_id);
    646         p_ccb->disconnect_reason = reason;
    647     }
    648 
    649     /* If at setup state, we may not get callback ind from L2CAP */
    650     /* Call user callback immediately */
    651     if (p_ccb->con_state == SDP_STATE_CONN_SETUP)
    652     {
    653         /* Tell the user if he has a callback */
    654         if (p_ccb->p_cb)
    655             (*p_ccb->p_cb) (reason);
    656         else if (p_ccb->p_cb2)
    657             (*p_ccb->p_cb2) (reason, p_ccb->user_data);
    658 
    659         sdpu_release_ccb (p_ccb);
    660     }
    661 
    662 }
    663 
    664 /*******************************************************************************
    665 **
    666 ** Function         sdp_disconnect_cfm
    667 **
    668 ** Description      This function handles a disconnect confirm event from L2CAP.
    669 **
    670 ** Returns          void
    671 **
    672 *******************************************************************************/
    673 static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
    674 {
    675     tCONN_CB    *p_ccb;
    676     UNUSED(result);
    677 
    678     /* Find CCB based on CID */
    679     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    680     {
    681         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
    682         return;
    683     }
    684 
    685     SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
    686 
    687     /* Tell the user if he has a callback */
    688     if (p_ccb->p_cb)
    689         (*p_ccb->p_cb) (p_ccb->disconnect_reason);
    690     else if (p_ccb->p_cb2)
    691         (*p_ccb->p_cb2) (p_ccb->disconnect_reason, p_ccb->user_data);
    692 
    693 
    694     sdpu_release_ccb (p_ccb);
    695 }
    696 
    697 #endif  /* SDP_CLIENT_ENABLED == TRUE */
    698 
    699 /*******************************************************************************
    700 **
    701 ** Function         sdp_conn_timeout
    702 **
    703 ** Description      This function processes a timeout. Currently, we simply send
    704 **                  a disconnect request to L2CAP.
    705 **
    706 ** Returns          void
    707 **
    708 *******************************************************************************/
    709 void sdp_conn_timeout (tCONN_CB*p_ccb)
    710 {
    711     SDP_TRACE_EVENT ("SDP - CCB timeout in state: %d  CID: 0x%x",
    712                       p_ccb->con_state, p_ccb->connection_id);
    713 
    714     L2CA_DisconnectReq (p_ccb->connection_id);
    715 #if SDP_CLIENT_ENABLED == TRUE
    716     /* Tell the user if he has a callback */
    717     if (p_ccb->p_cb)
    718         (*p_ccb->p_cb) (SDP_CONN_FAILED);
    719     else if (p_ccb->p_cb2)
    720         (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data);
    721 #endif
    722     sdpu_release_ccb (p_ccb);
    723 }
    724 
    725 
    726 
    727 
    728