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