summaryrefslogtreecommitdiffstats
path: root/stack/sdp/sdp_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/sdp/sdp_main.c')
-rw-r--r--stack/sdp/sdp_main.c724
1 files changed, 724 insertions, 0 deletions
diff --git a/stack/sdp/sdp_main.c b/stack/sdp/sdp_main.c
new file mode 100644
index 0000000..14cd39b
--- /dev/null
+++ b/stack/sdp/sdp_main.c
@@ -0,0 +1,724 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the main SDP functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btu.h"
+#include "btm_api.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+
+/********************************************************************************/
+/* G L O B A L S D P D A T A */
+/********************************************************************************/
+#if SDP_DYNAMIC_MEMORY == FALSE
+tSDP_CB sdp_cb;
+#endif
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm,
+ UINT8 l2cap_id);
+static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+
+#if SDP_CLIENT_ENABLED == TRUE
+static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+#else
+#define sdp_connect_cfm NULL
+#define sdp_disconnect_cfm NULL
+#endif
+
+
+/*******************************************************************************
+**
+** Function sdp_init
+**
+** Description This function initializes the SDP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_init (void)
+{
+ /* Clears all structures and local SDP database (if Server is enabled) */
+ memset (&sdp_cb, 0, sizeof (tSDP_CB));
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ sdp_cb.l2cap_my_cfg.mtu_present = TRUE;
+ sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
+ sdp_cb.l2cap_my_cfg.flush_to_present = TRUE;
+ sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO;
+
+ sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
+ sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
+
+#if SDP_SERVER_ENABLED == TRUE
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+ {
+ SDP_TRACE_ERROR0 ("Security Registration Server failed");
+ return;
+ }
+#endif
+
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+ {
+ SDP_TRACE_ERROR0 ("Security Registration for Client failed");
+ return;
+ }
+#endif
+
+#if defined(SDP_INITIAL_TRACE_LEVEL)
+ sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
+#else
+ sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
+ sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
+ sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
+ sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
+ sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
+ sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
+ sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
+ sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
+ {
+ SDP_TRACE_ERROR0 ("SDP Registration failed");
+ }
+}
+
+#if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
+/*******************************************************************************
+**
+** Function sdp_set_max_attr_list_size
+**
+** Description This function sets the max attribute list size to use
+**
+** Returns void
+**
+*******************************************************************************/
+UINT16 sdp_set_max_attr_list_size (UINT16 max_size)
+{
+ if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
+ max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
+
+ sdp_cb.max_attr_list_size = max_size;
+
+ return sdp_cb.max_attr_list_size;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function sdp_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+#if SDP_SERVER_ENABLED == TRUE
+ tCONN_CB *p_ccb;
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+ return;
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present)
+ {
+ SDP_TRACE_DEBUG6("sdp_connect_ind: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcr_present = FALSE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+ }
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
+#else /* No server */
+ /* Reject the connection */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+#endif
+}
+
+#if SDP_CLIENT_ENABLED == TRUE
+/*******************************************************************************
+**
+** Function sdp_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tCONN_CB *p_ccb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
+ {
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present)
+ {
+ SDP_TRACE_DEBUG6("sdp_connect_cfm: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+ && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr_present = FALSE;
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
+ }
+ else
+ {
+ SDP_TRACE_WARNING2 ("SDP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, p_ccb->connection_id);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb || p_ccb->p_cb2)
+ {
+ UINT16 err = -1;
+ if ((result == HCI_ERR_HOST_REJECT_SECURITY)
+ || (result == HCI_ERR_AUTH_FAILURE)
+ || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
+ || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
+ || (result == HCI_ERR_KEY_MISSING))
+ err = SDP_SECURITY_ERR;
+ else if (result == HCI_ERR_HOST_REJECT_DEVICE)
+ err = SDP_CONN_REJECTED;
+ else
+ err = SDP_CONN_FAILED;
+ if(p_ccb->p_cb)
+ (*p_ccb->p_cb)(err);
+ else if(p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(err, p_ccb->user_data);
+
+ }
+ sdpu_release_ccb (p_ccb);
+ }
+}
+#endif /* SDP_CLIENT_ENABLED == TRUE */
+
+
+/*******************************************************************************
+**
+** Function sdp_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* Remember the remote MTU size */
+ if (!p_cfg->mtu_present)
+ {
+ /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
+ p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
+ }
+ else
+ {
+ if (p_cfg->mtu > SDP_MTU_SIZE)
+ p_ccb->rem_mtu_size = SDP_MTU_SIZE;
+ else
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+ }
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ /* Check peer config request against our rfcomm configuration */
+ if (p_cfg->fcr_present)
+ {
+ /* Reject the window size if it is bigger than we want it to be */
+ if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
+ {
+ if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
+ && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
+ {
+ p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
+ }
+
+ /* Reject if locally we want basic and they don't */
+ if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ {
+ /* Ask for a new setup */
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG0("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
+ }
+ /* Remain in configure state and give the peer our desired configuration */
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+ return;
+ }
+ }
+ else /* We agree with peer's request */
+ p_cfg->fcr_present = FALSE;
+ }
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
+ {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_connected (p_ccb);
+ else
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function sdp_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tCONN_CB *p_ccb;
+
+ SDP_TRACE_EVENT2 ("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK)
+ {
+ p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
+ {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_connected (p_ccb);
+ else
+ /* Start inactivity timer */
+ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
+ }
+ }
+ else
+ {
+ /* If peer has rejected FCR and suggested basic then try basic */
+ if (p_cfg->fcr_present)
+ {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+ cfg.fcr_present = FALSE;
+ L2CA_ConfigReq (l2cap_cid, &cfg);
+
+ /* Remain in configure state */
+ return;
+ }
+
+#if SDP_CLIENT_ENABLED == TRUE
+ sdp_disconnect(p_ccb, SDP_CFG_FAILED);
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
+ SDP_SUCCESS : SDP_CONN_FAILED));
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
+ SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data);
+
+#endif
+ sdpu_release_ccb (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function sdp_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
+ {
+ if (p_ccb->con_state == SDP_STATE_CONNECTED)
+ {
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_server_rsp (p_ccb, p_msg);
+ else
+ sdp_server_handle_client_req (p_ccb, p_msg);
+ }
+ else
+ {
+ SDP_TRACE_WARNING2 ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+ p_ccb->con_state, l2cap_cid);
+ }
+ }
+ else
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ }
+
+ GKI_freebuf (p_msg);
+}
+
+
+#if SDP_CLIENT_ENABLED == TRUE
+/*******************************************************************************
+**
+** Function sdp_conn_originate
+**
+** Description This function is called from the API to originate a
+** connection.
+**
+** Returns void
+**
+*******************************************************************************/
+tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr)
+{
+ tCONN_CB *p_ccb;
+ UINT16 cid;
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+ {
+ SDP_TRACE_WARNING0 ("SDP - no spare CCB for orig");
+ return (NULL);
+ }
+
+ SDP_TRACE_EVENT0 ("SDP - Originate started");
+
+ /* We are the originator of this connection */
+ p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
+
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_ccb->con_state = SDP_STATE_CONN_SETUP;
+
+// btla-specific ++
+#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 */
+ BTM_SetOutService(p_bd_addr, BTM_SEC_SERVICE_SDP_SERVER, 0);
+#endif
+// btla-specific --
+
+ cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr);
+
+ /* Check if L2CAP started the connection process */
+ if (cid != 0)
+ {
+ p_ccb->connection_id = cid;
+
+ return (p_ccb);
+ }
+ else
+ {
+ SDP_TRACE_WARNING0 ("SDP - Originate failed");
+ sdpu_release_ccb (p_ccb);
+ return (NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason)
+{
+#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
+
+ /* If we are browsing for multiple UUIDs ... */
+ if ((p_ccb->con_state == SDP_STATE_CONNECTED)
+ && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH)))
+ {
+ /* If the browse found something, do no more searching */
+ if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
+ p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
+
+ while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters)
+ {
+ /* Check we have not already found the UUID (maybe through browse) */
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2)
+ && (SDP_FindServiceInDb (p_ccb->p_db,
+ p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16,
+ NULL)))
+ continue;
+
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2)
+ && (SDP_FindServiceUUIDInDb (p_ccb->p_db,
+ &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL)))
+ continue;
+
+ p_ccb->cur_handle = 0;
+
+ SDP_TRACE_EVENT1 ("SDP - looking for for more, CID: 0x%x",
+ p_ccb->connection_id);
+
+ sdp_disc_connected (p_ccb);
+ return;
+ }
+ }
+
+ if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
+ reason = SDP_SUCCESS;
+
+#endif
+
+ SDP_TRACE_EVENT1 ("SDP - disconnect CID: 0x%x", p_ccb->connection_id);
+
+ /* Check if we have a connection ID */
+ if (p_ccb->connection_id != 0)
+ {
+ L2CA_DisconnectReq (p_ccb->connection_id);
+ p_ccb->disconnect_reason = reason;
+ }
+
+ /* If at setup state, we may not get callback ind from L2CAP */
+ /* Call user callback immediately */
+ if (p_ccb->con_state == SDP_STATE_CONN_SETUP)
+ {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (reason);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2) (reason, p_ccb->user_data);
+
+ sdpu_release_ccb (p_ccb);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function sdp_disconnect_cfm
+**
+** Description This function handles a disconnect confirm event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tCONN_CB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+ {
+ SDP_TRACE_WARNING1 ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ SDP_TRACE_EVENT1 ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (p_ccb->disconnect_reason);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2) (p_ccb->disconnect_reason, p_ccb->user_data);
+
+
+ sdpu_release_ccb (p_ccb);
+}
+
+#endif /* SDP_CLIENT_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function sdp_conn_timeout
+**
+** Description This function processes a timeout. Currently, we simply send
+** a disconnect request to L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_conn_timeout (tCONN_CB*p_ccb)
+{
+ SDP_TRACE_EVENT2 ("SDP - CCB timeout in state: %d CID: 0x%x",
+ p_ccb->con_state, p_ccb->connection_id);
+
+ L2CA_DisconnectReq (p_ccb->connection_id);
+#if SDP_CLIENT_ENABLED == TRUE
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb) (SDP_CONN_FAILED);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data);
+#endif
+ sdpu_release_ccb (p_ccb);
+}
+
+
+
+