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