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