1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains the main SDP functions
23 ******************************************************************************/
29 #include "bt_target.h"
31 #include "bt_common.h"
46 extern fixed_queue_t *btu_general_alarm_queue;
48 /********************************************************************************/
49 /* G L O B A L S D P D A T A */
50 /********************************************************************************/
51 #if SDP_DYNAMIC_MEMORY == FALSE
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,
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);
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);
69 #define sdp_connect_cfm NULL
70 #define sdp_disconnect_cfm NULL
74 /*******************************************************************************
78 ** Description This function initializes the SDP unit.
82 *******************************************************************************/
85 /* Clears all structures and local SDP database (if Server is enabled) */
86 memset (&sdp_cb, 0, sizeof (tSDP_CB));
88 for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
89 sdp_cb.ccb[i].sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
92 /* Initialize the L2CAP configuration. We only care about MTU and flush */
93 sdp_cb.l2cap_my_cfg.mtu_present = TRUE;
94 sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
95 sdp_cb.l2cap_my_cfg.flush_to_present = TRUE;
96 sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO;
98 sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
99 sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
101 #if SDP_SERVER_ENABLED == TRUE
102 /* Register with Security Manager for the specific security level */
103 if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
104 SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
106 SDP_TRACE_ERROR ("Security Registration Server failed");
111 #if SDP_CLIENT_ENABLED == TRUE
112 /* Register with Security Manager for the specific security level */
113 if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
114 SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
116 SDP_TRACE_ERROR ("Security Registration for Client failed");
121 #if defined(SDP_INITIAL_TRACE_LEVEL)
122 sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
124 sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
127 sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
128 sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
129 sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
130 sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
131 sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
132 sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
133 sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
134 sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
135 sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
136 sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
137 sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
139 /* Now, register with L2CAP */
140 if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
142 SDP_TRACE_ERROR ("SDP Registration failed");
146 void sdp_free(void) {
147 for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) {
148 alarm_free(sdp_cb.ccb[i].sdp_conn_timer);
149 sdp_cb.ccb[i].sdp_conn_timer = NULL;
153 #if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE)
154 /*******************************************************************************
156 ** Function sdp_set_max_attr_list_size
158 ** Description This function sets the max attribute list size to use
162 *******************************************************************************/
163 UINT16 sdp_set_max_attr_list_size (UINT16 max_size)
165 if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
166 max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
168 sdp_cb.max_attr_list_size = max_size;
170 return sdp_cb.max_attr_list_size;
174 /*******************************************************************************
176 ** Function sdp_connect_ind
178 ** Description This function handles an inbound connection indication
179 ** from L2CAP. This is the case where we are acting as a
184 *******************************************************************************/
185 static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
188 #if SDP_SERVER_ENABLED == TRUE
191 /* Allocate a new CCB. Return if none available. */
192 if ((p_ccb = sdpu_allocate_ccb()) == NULL)
195 /* Transition to the next appropriate state, waiting for config setup. */
196 p_ccb->con_state = SDP_STATE_CFG_SETUP;
198 /* Save the BD Address and Channel ID. */
199 memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
200 p_ccb->connection_id = l2cap_cid;
202 /* Send response to the L2CAP layer. */
203 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
205 tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
209 SDP_TRACE_DEBUG("sdp_connect_ind: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
210 cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
211 cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
214 if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
215 && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
217 /* FCR not desired; try again in basic mode */
218 cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
219 cfg.fcr_present = FALSE;
220 L2CA_ConfigReq (l2cap_cid, &cfg);
224 SDP_TRACE_EVENT ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
225 #else /* No server */
226 /* Reject the connection */
227 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
231 #if SDP_CLIENT_ENABLED == TRUE
232 /*******************************************************************************
234 ** Function sdp_connect_cfm
236 ** Description This function handles the connect confirm events
237 ** from L2CAP. This is the case when we are acting as a
238 ** client and have sent a connect request.
242 *******************************************************************************/
243 static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result)
248 /* Find CCB based on CID */
249 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
251 SDP_TRACE_WARNING ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
255 /* If the connection response contains success status, then */
256 /* Transition to the next state and startup the timer. */
257 if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
259 p_ccb->con_state = SDP_STATE_CFG_SETUP;
261 cfg = sdp_cb.l2cap_my_cfg;
265 SDP_TRACE_DEBUG("sdp_connect_cfm: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
266 cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
267 cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
270 if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
271 && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
273 /* FCR not desired; try again in basic mode */
274 cfg.fcr_present = FALSE;
275 cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
276 L2CA_ConfigReq (l2cap_cid, &cfg);
279 SDP_TRACE_EVENT ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
283 SDP_TRACE_WARNING ("SDP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, p_ccb->connection_id);
285 /* Tell the user if he has a callback */
286 if (p_ccb->p_cb || p_ccb->p_cb2)
289 if ((result == HCI_ERR_HOST_REJECT_SECURITY)
290 || (result == HCI_ERR_AUTH_FAILURE)
291 || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
292 || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
293 || (result == HCI_ERR_KEY_MISSING))
294 err = SDP_SECURITY_ERR;
295 else if (result == HCI_ERR_HOST_REJECT_DEVICE)
296 err = SDP_CONN_REJECTED;
298 err = SDP_CONN_FAILED;
301 else if(p_ccb->p_cb2)
302 (*p_ccb->p_cb2)(err, p_ccb->user_data);
305 sdpu_release_ccb (p_ccb);
308 #endif /* SDP_CLIENT_ENABLED == TRUE */
311 /*******************************************************************************
313 ** Function sdp_config_ind
315 ** Description This function processes the L2CAP configuration indication
320 *******************************************************************************/
321 static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
325 /* Find CCB based on CID */
326 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
328 SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
332 /* Remember the remote MTU size */
333 if (!p_cfg->mtu_present)
335 /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
336 p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
340 if (p_cfg->mtu > SDP_MTU_SIZE)
341 p_ccb->rem_mtu_size = SDP_MTU_SIZE;
343 p_ccb->rem_mtu_size = p_cfg->mtu;
346 /* For now, always accept configuration from the other side */
347 p_cfg->flush_to_present = FALSE;
348 p_cfg->mtu_present = FALSE;
349 p_cfg->result = L2CAP_CFG_OK;
351 /* Check peer config request against our rfcomm configuration */
352 if (p_cfg->fcr_present)
354 /* Reject the window size if it is bigger than we want it to be */
355 if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
357 if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
358 && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
360 p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
361 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
362 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
365 /* Reject if locally we want basic and they don't */
366 if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
368 /* Ask for a new setup */
369 p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
370 p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
371 SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
373 /* Remain in configure state and give the peer our desired configuration */
374 if (p_cfg->result != L2CAP_CFG_OK)
376 SDP_TRACE_WARNING ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
377 L2CA_ConfigRsp (l2cap_cid, p_cfg);
381 else /* We agree with peer's request */
382 p_cfg->fcr_present = FALSE;
385 L2CA_ConfigRsp (l2cap_cid, p_cfg);
387 SDP_TRACE_EVENT ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
389 p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
391 if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
393 p_ccb->con_state = SDP_STATE_CONNECTED;
395 if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
396 sdp_disc_connected (p_ccb);
398 /* Start inactivity timer */
399 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
400 sdp_conn_timer_timeout, p_ccb,
401 btu_general_alarm_queue);
406 /*******************************************************************************
408 ** Function sdp_config_cfm
410 ** Description This function processes the L2CAP configuration confirmation
415 *******************************************************************************/
416 static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
420 SDP_TRACE_EVENT ("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
422 /* Find CCB based on CID */
423 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
425 SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
429 /* For now, always accept configuration from the other side */
430 if (p_cfg->result == L2CAP_CFG_OK)
432 p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
434 if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
436 p_ccb->con_state = SDP_STATE_CONNECTED;
438 if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
439 sdp_disc_connected (p_ccb);
441 /* Start inactivity timer */
442 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
443 sdp_conn_timer_timeout, p_ccb,
444 btu_general_alarm_queue);
450 /* If peer has rejected FCR and suggested basic then try basic */
451 if (p_cfg->fcr_present)
453 tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
454 cfg.fcr_present = FALSE;
455 L2CA_ConfigReq (l2cap_cid, &cfg);
457 /* Remain in configure state */
461 #if SDP_CLIENT_ENABLED == TRUE
462 sdp_disconnect(p_ccb, SDP_CFG_FAILED);
467 /*******************************************************************************
469 ** Function sdp_disconnect_ind
471 ** Description This function handles a disconnect event from L2CAP. If
472 ** requested to, we ack the disconnect before dropping the CCB
476 *******************************************************************************/
477 static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
481 /* Find CCB based on CID */
482 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
484 SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
489 L2CA_DisconnectRsp (l2cap_cid);
491 SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
492 #if SDP_CLIENT_ENABLED == TRUE
493 /* Tell the user if he has a callback */
495 (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
496 SDP_SUCCESS : SDP_CONN_FAILED));
497 else if (p_ccb->p_cb2)
498 (*p_ccb->p_cb2) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
499 SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data);
502 sdpu_release_ccb (p_ccb);
505 /*******************************************************************************
507 ** Function sdp_data_ind
509 ** Description This function is called when data is received from L2CAP.
510 ** if we are the originator of the connection, we are the SDP
511 ** client, and the received message is queued up for the client.
513 ** If we are the destination of the connection, we are the SDP
514 ** server, so the message is passed to the server processing
519 *******************************************************************************/
520 static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
524 /* Find CCB based on CID */
525 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
527 if (p_ccb->con_state == SDP_STATE_CONNECTED)
529 if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
530 sdp_disc_server_rsp (p_ccb, p_msg);
532 sdp_server_handle_client_req (p_ccb, p_msg);
536 SDP_TRACE_WARNING ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
537 p_ccb->con_state, l2cap_cid);
542 SDP_TRACE_WARNING ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
549 #if SDP_CLIENT_ENABLED == TRUE
550 /*******************************************************************************
552 ** Function sdp_conn_originate
554 ** Description This function is called from the API to originate a
559 *******************************************************************************/
560 tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr)
565 /* Allocate a new CCB. Return if none available. */
566 if ((p_ccb = sdpu_allocate_ccb()) == NULL)
568 SDP_TRACE_WARNING ("SDP - no spare CCB for orig");
572 SDP_TRACE_EVENT ("SDP - Originate started");
574 /* We are the originator of this connection */
575 p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
577 /* Save the BD Address and Channel ID. */
578 memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
580 /* Transition to the next appropriate state, waiting for connection confirm. */
581 p_ccb->con_state = SDP_STATE_CONN_SETUP;
583 cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr);
585 /* Check if L2CAP started the connection process */
588 p_ccb->connection_id = cid;
594 SDP_TRACE_WARNING ("SDP - Originate failed");
595 sdpu_release_ccb (p_ccb);
600 /*******************************************************************************
602 ** Function sdp_disconnect
604 ** Description This function disconnects a connection.
608 *******************************************************************************/
609 void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason)
611 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
613 /* If we are browsing for multiple UUIDs ... */
614 if ((p_ccb->con_state == SDP_STATE_CONNECTED)
615 && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
616 && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH)))
618 /* If the browse found something, do no more searching */
619 if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
620 p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
622 while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters)
624 /* Check we have not already found the UUID (maybe through browse) */
625 if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2)
626 && (SDP_FindServiceInDb (p_ccb->p_db,
627 p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16,
631 if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2)
632 && (SDP_FindServiceUUIDInDb (p_ccb->p_db,
633 &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL)))
636 p_ccb->cur_handle = 0;
638 SDP_TRACE_EVENT ("SDP - looking for for more, CID: 0x%x",
639 p_ccb->connection_id);
641 sdp_disc_connected (p_ccb);
646 if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
647 reason = SDP_SUCCESS;
651 SDP_TRACE_EVENT ("SDP - disconnect CID: 0x%x", p_ccb->connection_id);
653 /* Check if we have a connection ID */
654 if (p_ccb->connection_id != 0)
656 L2CA_DisconnectReq (p_ccb->connection_id);
657 p_ccb->disconnect_reason = reason;
660 /* If at setup state, we may not get callback ind from L2CAP */
661 /* Call user callback immediately */
662 if (p_ccb->con_state == SDP_STATE_CONN_SETUP)
664 /* Tell the user if he has a callback */
666 (*p_ccb->p_cb) (reason);
667 else if (p_ccb->p_cb2)
668 (*p_ccb->p_cb2) (reason, p_ccb->user_data);
670 sdpu_release_ccb (p_ccb);
675 /*******************************************************************************
677 ** Function sdp_disconnect_cfm
679 ** Description This function handles a disconnect confirm event from L2CAP.
683 *******************************************************************************/
684 static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
689 /* Find CCB based on CID */
690 if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
692 SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
696 SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
698 /* Tell the user if he has a callback */
700 (*p_ccb->p_cb) (p_ccb->disconnect_reason);
701 else if (p_ccb->p_cb2)
702 (*p_ccb->p_cb2) (p_ccb->disconnect_reason, p_ccb->user_data);
705 sdpu_release_ccb (p_ccb);
708 #endif /* SDP_CLIENT_ENABLED == TRUE */
710 /*******************************************************************************
712 ** Function sdp_conn_timer_timeout
714 ** Description This function processes a timeout. Currently, we simply send
715 ** a disconnect request to L2CAP.
719 *******************************************************************************/
720 void sdp_conn_timer_timeout(void *data)
722 tCONN_CB *p_ccb = (tCONN_CB *)data;
724 SDP_TRACE_EVENT ("SDP - CCB timeout in state: %d CID: 0x%x",
725 p_ccb->con_state, p_ccb->connection_id);
727 L2CA_DisconnectReq (p_ccb->connection_id);
728 #if SDP_CLIENT_ENABLED == TRUE
729 /* Tell the user if he has a callback */
731 (*p_ccb->p_cb) (SDP_CONN_FAILED);
732 else if (p_ccb->p_cb2)
733 (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data);
735 sdpu_release_ccb (p_ccb);