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