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