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