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 "bt_common.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 extern fixed_queue_t *btu_general_alarm_queue;
     47 
     48 /********************************************************************************/
     49 /*                       G L O B A L      S D P       D A T A                   */
     50 /********************************************************************************/
     51 #if SDP_DYNAMIC_MEMORY == FALSE
     52 tSDP_CB  sdp_cb;
     53 #endif
     54 
     55 /********************************************************************************/
     56 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     57 /********************************************************************************/
     58 static void sdp_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm,
     59                              UINT8 l2cap_id);
     60 static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     61 static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     62 static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
     63 static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
     64 
     65 #if SDP_CLIENT_ENABLED == TRUE
     66 static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result);
     67 static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
     68 #else
     69 #define sdp_connect_cfm     NULL
     70 #define sdp_disconnect_cfm  NULL
     71 #endif
     72 
     73 
     74 /*******************************************************************************
     75 **
     76 ** Function         sdp_init
     77 **
     78 ** Description      This function initializes the SDP unit.
     79 **
     80 ** Returns          void
     81 **
     82 *******************************************************************************/
     83 void sdp_init (void)
     84 {
     85     /* Clears all structures and local SDP database (if Server is enabled) */
     86     memset (&sdp_cb, 0, sizeof (tSDP_CB));
     87 
     88     /* Initialize the L2CAP configuration. We only care about MTU and flush */
     89     sdp_cb.l2cap_my_cfg.mtu_present       = TRUE;
     90     sdp_cb.l2cap_my_cfg.mtu               = SDP_MTU_SIZE;
     91     sdp_cb.l2cap_my_cfg.flush_to_present  = TRUE;
     92     sdp_cb.l2cap_my_cfg.flush_to          = SDP_FLUSH_TO;
     93 
     94     sdp_cb.max_attr_list_size             = SDP_MTU_SIZE - 16;
     95     sdp_cb.max_recs_per_search            = SDP_MAX_DISC_SERVER_RECS;
     96 
     97 #if SDP_SERVER_ENABLED == TRUE
     98     /* Register with Security Manager for the specific security level */
     99     if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
    100                                SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
    101     {
    102         SDP_TRACE_ERROR ("Security Registration Server failed");
    103         return;
    104     }
    105 #endif
    106 
    107 #if SDP_CLIENT_ENABLED == TRUE
    108     /* Register with Security Manager for the specific security level */
    109     if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
    110                                SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
    111     {
    112         SDP_TRACE_ERROR ("Security Registration for Client failed");
    113         return;
    114     }
    115 #endif
    116 
    117 #if defined(SDP_INITIAL_TRACE_LEVEL)
    118     sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
    119 #else
    120     sdp_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
    121 #endif
    122 
    123     sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
    124     sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
    125     sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
    126     sdp_cb.reg_info.pL2CA_ConfigInd_Cb  = sdp_config_ind;
    127     sdp_cb.reg_info.pL2CA_ConfigCfm_Cb  = sdp_config_cfm;
    128     sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
    129     sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
    130     sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
    131     sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
    132     sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
    133     sdp_cb.reg_info.pL2CA_TxComplete_Cb       = NULL;
    134 
    135     /* Now, register with L2CAP */
    136     if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
    137     {
    138         SDP_TRACE_ERROR ("SDP Registration failed");
    139     }
    140 }
    141 
    142 #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
    143 /*******************************************************************************
    144 **
    145 ** Function         sdp_set_max_attr_list_size
    146 **
    147 ** Description      This function sets the max attribute list size to use
    148 **
    149 ** Returns          void
    150 **
    151 *******************************************************************************/
    152 UINT16 sdp_set_max_attr_list_size (UINT16 max_size)
    153 {
    154     if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
    155         max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
    156 
    157     sdp_cb.max_attr_list_size  = max_size;
    158 
    159     return sdp_cb.max_attr_list_size;
    160 }
    161 #endif
    162 
    163 /*******************************************************************************
    164 **
    165 ** Function         sdp_connect_ind
    166 **
    167 ** Description      This function handles an inbound connection indication
    168 **                  from L2CAP. This is the case where we are acting as a
    169 **                  server.
    170 **
    171 ** Returns          void
    172 **
    173 *******************************************************************************/
    174 static void sdp_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
    175 {
    176     UNUSED(psm);
    177 #if SDP_SERVER_ENABLED == TRUE
    178     tCONN_CB    *p_ccb;
    179 
    180     /* Allocate a new CCB. Return if none available. */
    181     if ((p_ccb = sdpu_allocate_ccb()) == NULL)
    182         return;
    183 
    184     /* Transition to the next appropriate state, waiting for config setup. */
    185     p_ccb->con_state = SDP_STATE_CFG_SETUP;
    186 
    187     /* Save the BD Address and Channel ID. */
    188     memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
    189     p_ccb->connection_id = l2cap_cid;
    190 
    191     /* Send response to the L2CAP layer. */
    192     L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
    193     {
    194         tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
    195 
    196         if (cfg.fcr_present)
    197         {
    198             SDP_TRACE_DEBUG("sdp_connect_ind:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
    199                         cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
    200                         cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
    201         }
    202 
    203         if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
    204              && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
    205         {
    206             /* FCR not desired; try again in basic mode */
    207             cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
    208             cfg.fcr_present = FALSE;
    209             L2CA_ConfigReq (l2cap_cid, &cfg);
    210         }
    211     }
    212 
    213     SDP_TRACE_EVENT ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
    214 #else   /* No server */
    215     /* Reject the connection */
    216     L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
    217 #endif
    218 }
    219 
    220 #if SDP_CLIENT_ENABLED == TRUE
    221 /*******************************************************************************
    222 **
    223 ** Function         sdp_connect_cfm
    224 **
    225 ** Description      This function handles the connect confirm events
    226 **                  from L2CAP. This is the case when we are acting as a
    227 **                  client and have sent a connect request.
    228 **
    229 ** Returns          void
    230 **
    231 *******************************************************************************/
    232 static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result)
    233 {
    234     tCONN_CB    *p_ccb;
    235     tL2CAP_CFG_INFO cfg;
    236 
    237     /* Find CCB based on CID */
    238     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    239     {
    240         SDP_TRACE_WARNING ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
    241         return;
    242     }
    243 
    244     /* If the connection response contains success status, then */
    245     /* Transition to the next state and startup the timer.      */
    246     if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
    247     {
    248         p_ccb->con_state = SDP_STATE_CFG_SETUP;
    249 
    250         cfg = sdp_cb.l2cap_my_cfg;
    251 
    252         if (cfg.fcr_present)
    253         {
    254             SDP_TRACE_DEBUG("sdp_connect_cfm:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
    255                         cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
    256                         cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
    257         }
    258 
    259         if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
    260              && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
    261         {
    262             /* FCR not desired; try again in basic mode */
    263             cfg.fcr_present = FALSE;
    264             cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
    265             L2CA_ConfigReq (l2cap_cid, &cfg);
    266         }
    267 
    268         SDP_TRACE_EVENT ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
    269     }
    270     else
    271     {
    272         SDP_TRACE_WARNING ("SDP - Rcvd conn cnf with error: 0x%x  CID 0x%x", result, p_ccb->connection_id);
    273 
    274         /* Tell the user if he has a callback */
    275         if (p_ccb->p_cb || p_ccb->p_cb2)
    276         {
    277             UINT16 err = -1;
    278             if ((result == HCI_ERR_HOST_REJECT_SECURITY)
    279              || (result == HCI_ERR_AUTH_FAILURE)
    280              || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
    281              || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
    282              || (result == HCI_ERR_KEY_MISSING))
    283                 err = SDP_SECURITY_ERR;
    284             else if (result == HCI_ERR_HOST_REJECT_DEVICE)
    285                 err = SDP_CONN_REJECTED;
    286             else
    287                 err = SDP_CONN_FAILED;
    288             if(p_ccb->p_cb)
    289                 (*p_ccb->p_cb)(err);
    290             else if(p_ccb->p_cb2)
    291                 (*p_ccb->p_cb2)(err, p_ccb->user_data);
    292 
    293         }
    294         sdpu_release_ccb (p_ccb);
    295     }
    296 }
    297 #endif  /* SDP_CLIENT_ENABLED == TRUE */
    298 
    299 
    300 /*******************************************************************************
    301 **
    302 ** Function         sdp_config_ind
    303 **
    304 ** Description      This function processes the L2CAP configuration indication
    305 **                  event.
    306 **
    307 ** Returns          void
    308 **
    309 *******************************************************************************/
    310 static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    311 {
    312     tCONN_CB    *p_ccb;
    313 
    314     /* Find CCB based on CID */
    315     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    316     {
    317         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    318         return;
    319     }
    320 
    321     /* Remember the remote MTU size */
    322     if (!p_cfg->mtu_present)
    323     {
    324         /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
    325         p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
    326     }
    327     else
    328     {
    329         if (p_cfg->mtu > SDP_MTU_SIZE)
    330             p_ccb->rem_mtu_size = SDP_MTU_SIZE;
    331         else
    332             p_ccb->rem_mtu_size = p_cfg->mtu;
    333     }
    334 
    335     /* For now, always accept configuration from the other side */
    336     p_cfg->flush_to_present = FALSE;
    337     p_cfg->mtu_present      = FALSE;
    338     p_cfg->result           = L2CAP_CFG_OK;
    339 
    340     /* Check peer config request against our rfcomm configuration */
    341     if (p_cfg->fcr_present)
    342     {
    343         /* Reject the window size if it is bigger than we want it to be */
    344         if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
    345         {
    346             if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
    347                 && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
    348             {
    349                 p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
    350                 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    351                 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
    352             }
    353 
    354             /* Reject if locally we want basic and they don't */
    355             if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
    356             {
    357                 /* Ask for a new setup */
    358                 p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
    359                 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
    360                 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
    361             }
    362             /* Remain in configure state and give the peer our desired configuration */
    363             if (p_cfg->result != L2CAP_CFG_OK)
    364             {
    365                 SDP_TRACE_WARNING ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
    366                 L2CA_ConfigRsp (l2cap_cid, p_cfg);
    367                 return;
    368             }
    369         }
    370         else    /* We agree with peer's request */
    371             p_cfg->fcr_present = FALSE;
    372     }
    373 
    374     L2CA_ConfigRsp (l2cap_cid, p_cfg);
    375 
    376     SDP_TRACE_EVENT ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
    377 
    378     p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
    379 
    380     if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
    381     {
    382         p_ccb->con_state = SDP_STATE_CONNECTED;
    383 
    384         if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
    385             sdp_disc_connected (p_ccb);
    386         } else {
    387             /* Start inactivity timer */
    388             alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    389                                sdp_conn_timer_timeout, p_ccb,
    390                                btu_general_alarm_queue);
    391         }
    392     }
    393 }
    394 
    395 /*******************************************************************************
    396 **
    397 ** Function         sdp_config_cfm
    398 **
    399 ** Description      This function processes the L2CAP configuration confirmation
    400 **                  event.
    401 **
    402 ** Returns          void
    403 **
    404 *******************************************************************************/
    405 static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    406 {
    407     tCONN_CB    *p_ccb;
    408 
    409     SDP_TRACE_EVENT ("SDP - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
    410 
    411     /* Find CCB based on CID */
    412     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    413     {
    414         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    415         return;
    416     }
    417 
    418     /* For now, always accept configuration from the other side */
    419     if (p_cfg->result == L2CAP_CFG_OK)
    420     {
    421         p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
    422 
    423         if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
    424         {
    425             p_ccb->con_state = SDP_STATE_CONNECTED;
    426 
    427             if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
    428                 sdp_disc_connected (p_ccb);
    429             } else {
    430                 /* Start inactivity timer */
    431                 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    432                                    sdp_conn_timer_timeout, p_ccb,
    433                                    btu_general_alarm_queue);
    434             }
    435         }
    436     }
    437     else
    438     {
    439         /* If peer has rejected FCR and suggested basic then try basic */
    440         if (p_cfg->fcr_present)
    441         {
    442             tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
    443             cfg.fcr_present = FALSE;
    444             L2CA_ConfigReq (l2cap_cid, &cfg);
    445 
    446             /* Remain in configure state */
    447             return;
    448         }
    449 
    450 #if SDP_CLIENT_ENABLED == TRUE
    451         sdp_disconnect(p_ccb, SDP_CFG_FAILED);
    452 #endif
    453     }
    454 }
    455 
    456 /*******************************************************************************
    457 **
    458 ** Function         sdp_disconnect_ind
    459 **
    460 ** Description      This function handles a disconnect event from L2CAP. If
    461 **                  requested to, we ack the disconnect before dropping the CCB
    462 **
    463 ** Returns          void
    464 **
    465 *******************************************************************************/
    466 static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
    467 {
    468     tCONN_CB    *p_ccb;
    469 
    470     /* Find CCB based on CID */
    471     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
    472     {
    473         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
    474         return;
    475     }
    476 
    477     if (ack_needed)
    478         L2CA_DisconnectRsp (l2cap_cid);
    479 
    480     SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
    481 #if SDP_CLIENT_ENABLED == TRUE
    482     /* Tell the user if he has a callback */
    483     if (p_ccb->p_cb)
    484         (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
    485                         SDP_SUCCESS : SDP_CONN_FAILED));
    486     else if (p_ccb->p_cb2)
    487         (*p_ccb->p_cb2) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
    488                         SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data);
    489 
    490 #endif
    491     sdpu_release_ccb (p_ccb);
    492 }
    493 
    494 /*******************************************************************************
    495 **
    496 ** Function         sdp_data_ind
    497 **
    498 ** Description      This function is called when data is received from L2CAP.
    499 **                  if we are the originator of the connection, we are the SDP
    500 **                  client, and the received message is queued up for the client.
    501 **
    502 **                  If we are the destination of the connection, we are the SDP
    503 **                  server, so the message is passed to the server processing
    504 **                  function.
    505 **
    506 ** Returns          void
    507 **
    508 *******************************************************************************/
    509 static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
    510 {
    511     tCONN_CB    *p_ccb;
    512 
    513     /* Find CCB based on CID */
    514     if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
    515     {
    516         if (p_ccb->con_state == SDP_STATE_CONNECTED)
    517         {
    518             if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
    519                 sdp_disc_server_rsp (p_ccb, p_msg);
    520             else
    521                 sdp_server_handle_client_req (p_ccb, p_msg);
    522         }
    523         else
    524         {
    525             SDP_TRACE_WARNING ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
    526                                 p_ccb->con_state, l2cap_cid);
    527         }
    528     }
    529     else
    530     {
    531         SDP_TRACE_WARNING ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
    532     }
    533 
    534     osi_free(p_msg);
    535 }
    536 
    537 
    538 #if SDP_CLIENT_ENABLED == TRUE
    539 /*******************************************************************************
    540 **
    541 ** Function         sdp_conn_originate
    542 **
    543 ** Description      This function is called from the API to originate a
    544 **                  connection.
    545 **
    546 ** Returns          void
    547 **
    548 *******************************************************************************/
    549 tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr)
    550 {
    551     tCONN_CB              *p_ccb;
    552     UINT16                cid;
    553 
    554     /* Allocate a new CCB. Return if none available. */
    555     if ((p_ccb = sdpu_allocate_ccb()) == NULL)
    556     {
    557         SDP_TRACE_WARNING ("SDP - no spare CCB for orig");
    558         return (NULL);
    559     }
    560 
    561     SDP_TRACE_EVENT ("SDP - Originate started");
    562 
    563     /* We are the originator of this connection */
    564     p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
    565 
    566     /* Save the BD Address and Channel ID. */
    567     memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
    568 
    569     /* Transition to the next appropriate state, waiting for connection confirm. */
    570     p_ccb->con_state = SDP_STATE_CONN_SETUP;
    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_timer_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_timer_timeout(void *data)
    710 {
    711     tCONN_CB *p_ccb = (tCONN_CB *)data;
    712 
    713     SDP_TRACE_EVENT ("SDP - CCB timeout in state: %d  CID: 0x%x",
    714                       p_ccb->con_state, p_ccb->connection_id);
    715 
    716     L2CA_DisconnectReq (p_ccb->connection_id);
    717 #if SDP_CLIENT_ENABLED == TRUE
    718     /* Tell the user if he has a callback */
    719     if (p_ccb->p_cb)
    720         (*p_ccb->p_cb) (SDP_CONN_FAILED);
    721     else if (p_ccb->p_cb2)
    722         (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data);
    723 #endif
    724     sdpu_release_ccb (p_ccb);
    725 }
    726 
    727 
    728 
    729 
    730