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